Skip to content

Commit 9a16d74

Browse files
abhishekagrawal080nvrakesh06
authored andcommitted
Merge pull request #6108 from BitGo/WIN-5440
fix(sdk-coin-trx): handling string type for scanning factor TICKET: WIN-5425
2 parents 398815d + e465870 commit 9a16d74

File tree

8 files changed

+376
-5
lines changed

8 files changed

+376
-5
lines changed

modules/abstract-substrate/src/lib/transaction.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ import { DEFAULT_SUBSTRATE_PREFIX } from './constants';
2121

2222
export class Transaction extends BaseTransaction {
2323
protected _substrateTransaction: UnsignedTransaction;
24-
private _signedTransaction?: string;
25-
private _registry: TypeRegistry;
26-
private _chainName: string;
27-
private _sender: string;
24+
protected _signedTransaction?: string;
25+
protected _registry: TypeRegistry;
26+
protected _chainName: string;
27+
protected _sender: string;
2828

2929
private static FAKE_SIGNATURE = `0x${Buffer.from(new Uint8Array(256).fill(1)).toString('hex')}`;
3030

@@ -128,6 +128,7 @@ export class Transaction extends BaseTransaction {
128128

129129
/** @inheritdoc */
130130
toJson(): TxData {
131+
console.log('Transaction toJson called in substrate Transaction class');
131132
if (!this._substrateTransaction) {
132133
throw new InvalidTransactionError('Empty transaction');
133134
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
import { Args } from '@substrate/txwrapper-core';
2+
import { Interface } from '@bitgo/abstract-substrate';
3+
import { DecodedUnsignedTx } from '@substrate/txwrapper-core/lib/types';
24

35
export interface RegisterDidWithCDDArgs extends Args {
46
targetAccount: string;
57
secondaryKeys: [];
68
expiry: null;
79
}
10+
11+
export interface TxMethod extends Omit<Interface.TxMethod, 'args'> {
12+
args:
13+
| Interface.TransferArgs
14+
| Interface.TransferAllArgs
15+
| Interface.AddStakeArgs
16+
| Interface.RemoveStakeArgs
17+
| RegisterDidWithCDDArgs;
18+
}
19+
20+
export interface DecodedTx extends Omit<DecodedUnsignedTx, 'method'> {
21+
method: TxMethod;
22+
}

modules/sdk-coin-polyx/src/lib/registerDidWithCDDBuilder.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import { BaseCoin as CoinConfig } from '@bitgo/statics';
44
import { TransactionType, BaseAddress, InvalidTransactionError } from '@bitgo/sdk-core';
55
import { RegisterDidWithCDDArgs } from './iface';
66
import { RegisterDidWithCDDTransactionSchema } from './txnSchema';
7+
import { Transaction } from './transaction';
78

89
export class RegisterDidWithCDDBuilder extends TransactionBuilder {
910
protected _to: string;
1011

1112
constructor(_coinConfig: Readonly<CoinConfig>) {
1213
super(_coinConfig);
14+
this._transaction = new Transaction(_coinConfig);
1315
}
1416

1517
protected get transactionType(): TransactionType {
@@ -41,6 +43,17 @@ export class RegisterDidWithCDDBuilder extends TransactionBuilder {
4143
return this;
4244
}
4345

46+
/** @inheritdoc */
47+
// protected fromImplementation(rawTransaction: string): Transaction {
48+
// if (this._method?.name === Interface.MethodNames.RegisterDidWithCDD) {
49+
// const txMethod = this._method.args as RegisterDidWithCDDArgs;
50+
// this.to({ address: utils.decodeSubstrateAddress(txMethod.targetAccount, this.getAddressFormat()) });
51+
// } else {
52+
// throw new InvalidTransactionError(`Invalid Transaction Type: ${this._method?.name}. Expected transferWithMemo`);
53+
// }
54+
// return this._transaction;
55+
// }
56+
4457
/** @inheritdoc */
4558
validateDecodedTransaction(decodedTxn: DecodedSigningPayload | DecodedSignedTx, rawTransaction?: string): void {
4659
if (decodedTxn.method?.name === Interface.MethodNames.RegisterDidWithCDD) {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Transaction as SubstrateTransaction, Interface, utils, KeyPair } from '@bitgo/abstract-substrate';
2+
import { InvalidTransactionError, TransactionType } from '@bitgo/sdk-core';
3+
import { construct, decode } from '@substrate/txwrapper-polkadot';
4+
import { decodeAddress } from '@polkadot/keyring';
5+
import { DecodedTx, RegisterDidWithCDDArgs } from './iface';
6+
7+
export class Transaction extends SubstrateTransaction {
8+
/** @inheritdoc */
9+
toJson(): Interface.TxData {
10+
console.log('Transaction toJson called in polyx Transaction class');
11+
if (!this._substrateTransaction) {
12+
throw new InvalidTransactionError('Empty transaction');
13+
}
14+
15+
const decodedTx = decode(this._substrateTransaction, {
16+
metadataRpc: this._substrateTransaction.metadataRpc,
17+
registry: this._registry,
18+
isImmortalEra: utils.isZeroHex(this._substrateTransaction.era),
19+
}) as unknown as DecodedTx;
20+
21+
const result: Interface.TxData = {
22+
id: construct.txHash(this.toBroadcastFormat()),
23+
sender: decodedTx.address,
24+
referenceBlock: decodedTx.blockHash,
25+
blockNumber: decodedTx.blockNumber,
26+
genesisHash: decodedTx.genesisHash,
27+
nonce: decodedTx.nonce,
28+
specVersion: decodedTx.specVersion,
29+
transactionVersion: decodedTx.transactionVersion,
30+
eraPeriod: decodedTx.eraPeriod,
31+
chainName: this._chainName,
32+
tip: decodedTx.tip ? Number(decodedTx.tip) : 0,
33+
};
34+
35+
const txMethod = decodedTx.method.args;
36+
if (this.type === TransactionType.WalletInitialization) {
37+
const { targetAccount } = txMethod as RegisterDidWithCDDArgs;
38+
const keypairDest = new KeyPair({
39+
pub: Buffer.from(decodeAddress(targetAccount)).toString('hex'),
40+
});
41+
result.to = keypairDest.getAddress(this.getAddressFormat());
42+
} else {
43+
super.toJson();
44+
}
45+
46+
return result;
47+
}
48+
49+
/**
50+
* Load the input and output data on this transaction.
51+
*/
52+
loadInputsAndOutputs(): void {
53+
super.loadInputsAndOutputs();
54+
55+
const decodedTx = decode(this._substrateTransaction, {
56+
metadataRpc: this._substrateTransaction.metadataRpc,
57+
registry: this._registry,
58+
isImmortalEra: utils.isZeroHex(this._substrateTransaction.era),
59+
}) as unknown as DecodedTx;
60+
61+
if (this.type === TransactionType.WalletInitialization) {
62+
this.decodeInputsAndOutputsForRegisterDidWithCDD(decodedTx);
63+
}
64+
}
65+
66+
private decodeInputsAndOutputsForRegisterDidWithCDD(decodedTx: DecodedTx) {
67+
const txMethod = decodedTx.method.args as RegisterDidWithCDDArgs;
68+
const keypairDest = new KeyPair({
69+
pub: Buffer.from(decodeAddress(txMethod.targetAccount)).toString('hex'),
70+
});
71+
const to = keypairDest.getAddress(this.getAddressFormat());
72+
const value = '0';
73+
const from = decodedTx.address;
74+
75+
this._inputs.push({
76+
address: from,
77+
value,
78+
coin: this._coinConfig.name,
79+
});
80+
81+
this._outputs.push({
82+
address: to,
83+
value,
84+
coin: this._coinConfig.name,
85+
});
86+
}
87+
}

modules/sdk-coin-polyx/test/resources/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ export const mockTssSignature =
55
'aadae7fa1f53e7a5c900b330ff71bee6782cf3c29a2c6f9599162381cd021ad581c74ded89f49ec79adefed64af8ff16649553523dda9cb4f017cbf15681e50e';
66

77
export const accounts = {
8+
cddProvider: {
9+
secretKey:
10+
'360dcfad8fbe6d514e27866ce134fcc458bc450dd2f03600b0a646ec8f5b40245a9f5ba5f51de3a38b1ee7f7e91dc9e844696d7da545d78a14b1635244e34d2a',
11+
publicKey: '5a9f5ba5f51de3a38b1ee7f7e91dc9e844696d7da545d78a14b1635244e34d2a',
12+
address: '5E7XWJRysj27EzibT4duRxrBQT9Qfa7Z5nAAvJmvd32nhkjH',
13+
},
814
account1: {
915
secretKey:
1016
'acfa9a91ed11ecc72dc015562fcb28a4b4bbca4b74f7915119578ed4579844c8cd1293d5b2ea6d7c70689079cde9ccc3dd3f4366dff4fa2f3e46ba9ee380df57',
@@ -38,6 +44,12 @@ export const rawTx = {
3844
unsigned:
3945
'0x250105010087c8be067be02a321ad8e946a4a50d71c25b9a640d064ec577d4ef9424b90b460300943577013030303030303030303030303030303030303030303030303030303132333435a503900090d76a00070000002ace05e703aa50b48c0ccccfc8b424f7aab9a1e2c424ed12e45d20b1e8ffd0d6e5c5396f3291d2575d138b98d34eac2fc156e5280276f57a30a8e3b8fbc49bfc',
4046
},
47+
cddTransaction: {
48+
signed:
49+
'0x2d0284005a9f5ba5f51de3a38b1ee7f7e91dc9e844696d7da545d78a14b1635244e34d2a00bb9ce1ddfda6d60e8169d2cab37e57ca1b1d8592f3caacc25b80d23f4c29c1efd096c9afbd86148c12e68570bab4ed3965b3180570293ea4be6f849ba362d80345030400071460b685d82b315b70d7c7604f990a05395eab09d5e75bae5d2c519ca1b01e25e50000',
50+
unsigned:
51+
'0x90071460b685d82b315b70d7c7604f990a05395eab09d5e75bae5d2c519ca1b01e25e500004503040090d76a00070000002ace05e703aa50b48c0ccccfc8b424f7aab9a1e2c424ed12e45d20b1e8ffd0d6cbd4f0bb74e13c8c4da973b1a15c3df61ae3b82677b024ffa60faf7799d5ed4b',
52+
},
4153
};
4254

4355
export const { txVersion, specVersion, genesisHash, chainName, specName } = Networks.test.polyx;
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import assert from 'assert';
2+
import should from 'should';
3+
import sinon from 'sinon';
4+
import { RegisterDidWithCDDBuilder } from '../../../src/lib';
5+
import { utils } from '../../../src';
6+
7+
import { accounts, rawTx, chainName, genesisHash, mockTssSignature } from '../../resources';
8+
import { buildTestConfig } from './base';
9+
import { testnetMaterial } from '../../../src/resources';
10+
11+
describe('Polyx Register DID with CDD builder Builder', () => {
12+
let builder: RegisterDidWithCDDBuilder;
13+
14+
const sender = accounts.cddProvider;
15+
const receiver = accounts.account2;
16+
17+
beforeEach(() => {
18+
const config = buildTestConfig();
19+
builder = new RegisterDidWithCDDBuilder(config).material(utils.getMaterial(config.network.type));
20+
});
21+
22+
describe('setter validation', () => {
23+
it('should validate to address', () => {
24+
const spy = sinon.spy(builder, 'validateAddress');
25+
assert.throws(
26+
() => builder.to({ address: 'asd' }),
27+
(e: Error) => e.message === `The address 'asd' is not a well-formed dot address`
28+
);
29+
should.doesNotThrow(() => builder.to({ address: sender.address }));
30+
sinon.assert.calledTwice(spy);
31+
});
32+
});
33+
34+
describe('build transfer transaction', () => {
35+
it('should build a register did with cdd transaction', async () => {
36+
builder
37+
.to({ address: receiver.address })
38+
.sender({ address: sender.address })
39+
.validity({ firstValid: 3933, maxDuration: 64 })
40+
.referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d')
41+
.sequenceId({ name: 'Nonce', keyword: 'nonce', value: 200 })
42+
.fee({ amount: 0, type: 'tip' });
43+
builder.addSignature({ pub: sender.publicKey }, Buffer.from(mockTssSignature, 'hex'));
44+
const tx = await builder.build();
45+
const txJson = tx.toJson();
46+
should.deepEqual(txJson.to, receiver.address);
47+
should.deepEqual(txJson.sender, sender.address);
48+
should.deepEqual(txJson.blockNumber, 3933);
49+
should.deepEqual(txJson.referenceBlock, '0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');
50+
should.deepEqual(txJson.genesisHash, genesisHash);
51+
should.deepEqual(txJson.specVersion, Number(testnetMaterial.specVersion));
52+
should.deepEqual(txJson.nonce, 200);
53+
should.deepEqual(txJson.tip, 0);
54+
should.deepEqual(txJson.transactionVersion, Number(testnetMaterial.txVersion));
55+
should.deepEqual(txJson.chainName, testnetMaterial.chainName);
56+
should.deepEqual(txJson.eraPeriod, 64);
57+
58+
const inputs = tx.inputs[0];
59+
should.deepEqual(inputs.address, sender.address);
60+
should.deepEqual(inputs.value, '0');
61+
62+
const outputs = tx.outputs[0];
63+
should.deepEqual(outputs.address, receiver.address);
64+
should.deepEqual(outputs.value, '0');
65+
});
66+
67+
it('should build a transaction with zero maxDuration (immortal)', async () => {
68+
builder
69+
.to({ address: receiver.address })
70+
.sender({ address: sender.address })
71+
.validity({ firstValid: 3933, maxDuration: 0 })
72+
.referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d')
73+
.sequenceId({ name: 'Nonce', keyword: 'nonce', value: 200 })
74+
.fee({ amount: 0, type: 'tip' });
75+
builder.addSignature({ pub: sender.publicKey }, Buffer.from(mockTssSignature, 'hex'));
76+
const tx = await builder.build();
77+
const txJson = tx.toJson();
78+
should.deepEqual(txJson.to, receiver.address);
79+
should.deepEqual(txJson.sender, sender.address);
80+
should.deepEqual(txJson.blockNumber, 3933);
81+
should.deepEqual(txJson.referenceBlock, '0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');
82+
should.deepEqual(txJson.genesisHash, genesisHash);
83+
should.deepEqual(txJson.specVersion, Number(testnetMaterial.specVersion));
84+
should.deepEqual(txJson.nonce, 200);
85+
should.deepEqual(txJson.tip, 0);
86+
should.deepEqual(txJson.transactionVersion, Number(testnetMaterial.txVersion));
87+
should.deepEqual(txJson.chainName, chainName);
88+
should.deepEqual(txJson.eraPeriod, 0);
89+
90+
const inputs = tx.inputs[0];
91+
should.deepEqual(inputs.address, sender.address);
92+
should.deepEqual(inputs.value, '0');
93+
94+
const outputs = tx.outputs[0];
95+
should.deepEqual(outputs.address, receiver.address);
96+
should.deepEqual(outputs.value, '0');
97+
});
98+
99+
it('should build an unsigned transfer transaction', async () => {
100+
builder
101+
.to({ address: receiver.address })
102+
.sender({ address: sender.address })
103+
.validity({ firstValid: 3933, maxDuration: 64 })
104+
.referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d')
105+
.sequenceId({ name: 'Nonce', keyword: 'nonce', value: 200 })
106+
.fee({ amount: 0, type: 'tip' });
107+
const tx = await builder.build();
108+
const txJson = tx.toJson();
109+
should.deepEqual(txJson.to, receiver.address);
110+
should.deepEqual(txJson.sender, sender.address);
111+
should.deepEqual(txJson.blockNumber, 3933);
112+
should.deepEqual(txJson.referenceBlock, '0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');
113+
should.deepEqual(txJson.genesisHash, genesisHash);
114+
should.deepEqual(txJson.specVersion, Number(testnetMaterial.specVersion));
115+
should.deepEqual(txJson.nonce, 200);
116+
should.deepEqual(txJson.tip, 0);
117+
should.deepEqual(txJson.transactionVersion, Number(testnetMaterial.txVersion));
118+
should.deepEqual(txJson.chainName, chainName);
119+
should.deepEqual(txJson.eraPeriod, 64);
120+
});
121+
122+
it('should build from raw signed tx', async () => {
123+
builder.from(rawTx.cddTransaction.signed);
124+
builder
125+
.validity({ firstValid: 3933, maxDuration: 64 })
126+
.referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');
127+
const tx = await builder.build();
128+
const txJson = tx.toJson();
129+
should.deepEqual(txJson.to, '5F8jxKE81GhFrphyfMFr5UjeAz5wS4AaZFmeFPnf8wTetD72');
130+
should.deepEqual(txJson.sender, '5CLYvxwx4PUS678MNuhNJ9EfpUU9utrYCz9WVxovac4u9AYD');
131+
should.deepEqual(txJson.blockNumber, 3933);
132+
should.deepEqual(txJson.referenceBlock, '0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');
133+
should.deepEqual(txJson.genesisHash, genesisHash);
134+
should.deepEqual(txJson.specVersion, Number(testnetMaterial.specVersion));
135+
should.deepEqual(txJson.nonce, 34);
136+
should.deepEqual(txJson.tip, 0);
137+
should.deepEqual(txJson.transactionVersion, Number(testnetMaterial.txVersion));
138+
should.deepEqual(txJson.chainName, chainName);
139+
should.deepEqual(txJson.eraPeriod, 64);
140+
});
141+
142+
it('should build from raw unsigned tx', async () => {
143+
builder.from(rawTx.transfer.unsigned);
144+
builder
145+
.validity({ firstValid: 3933, maxDuration: 64 })
146+
.referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d')
147+
.sender({ address: sender.address })
148+
.addSignature({ pub: sender.publicKey }, Buffer.from(mockTssSignature, 'hex'));
149+
150+
const tx = await builder.build();
151+
const txJson = tx.toJson();
152+
should.deepEqual(txJson.amount, '2000000000');
153+
should.deepEqual(txJson.to, '5F8jxKE81GhFrphyfMFr5UjeAz5wS4AaZFmeFPnf8wTetD72');
154+
should.deepEqual(txJson.sender, sender.address);
155+
should.deepEqual(txJson.blockNumber, 3933);
156+
should.deepEqual(txJson.referenceBlock, '0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');
157+
should.deepEqual(txJson.genesisHash, genesisHash);
158+
should.deepEqual(txJson.specVersion, Number(testnetMaterial.specVersion));
159+
should.deepEqual(txJson.nonce, 36);
160+
should.deepEqual(txJson.eraPeriod, 64);
161+
should.deepEqual(txJson.tip, 0);
162+
should.deepEqual(txJson.transactionVersion, Number(testnetMaterial.txVersion));
163+
should.deepEqual(txJson.chainName, chainName);
164+
});
165+
});
166+
});

modules/sdk-coin-trx/src/trx.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,10 +586,15 @@ export class Trx extends BaseCoin {
586586
} else if (!isInteger(startIdx) || startIdx < 0) {
587587
throw new Error('Invalid starting index to scan for addresses');
588588
}
589+
589590
let numIteration = params.scan;
590591
if (isUndefined(numIteration)) {
591592
numIteration = 20;
592-
} else if (!isInteger(numIteration) || numIteration <= 0) {
593+
} else if (typeof numIteration === 'string') {
594+
numIteration = parseInt(numIteration, 10);
595+
}
596+
597+
if (!isInteger(numIteration) || numIteration <= 0) {
593598
throw new Error('Invalid scanning factor');
594599
}
595600

0 commit comments

Comments
 (0)