Skip to content

Commit 8f8775b

Browse files
twtaylorbitgoperrybitgo
authored andcommitted
TRON-36 - trx recovery tests
1 parent efb765e commit 8f8775b

2 files changed

Lines changed: 60 additions & 13 deletions

File tree

modules/core/src/v2/coins/trx.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,15 @@ export class Trx extends BaseCoin {
341341
* @param callback
342342
* @returns {BigNumber} address balance
343343
*/
344-
getAccountBalanceFromNode(address: string, callback?: NodeCallback<any>): Bluebird<any> {
344+
getAccountFromNode(address: string, callback?: NodeCallback<any>): Bluebird<any> {
345345
const self = this;
346346
return co(function*() {
347347
const result = yield self.recoveryPost({
348348
path: '/walletsolidity/getaccount',
349349
jsonObj: { address },
350350
node: NodeTypes.Solidity,
351351
});
352-
return result.balance;
352+
return result;
353353
})
354354
.call(this)
355355
.asCallback(callback);
@@ -381,6 +381,26 @@ export class Trx extends BaseCoin {
381381
.asCallback(callback);
382382
}
383383

384+
/**
385+
* Throws an error if any keys in the ownerKeys collection don't match the keys array we pass
386+
* @param ownerKeys
387+
* @param keysToFind
388+
*/
389+
checkPermissions(ownerKeys: { address: string; weight: number }[], keys: string[]) {
390+
keys = keys.map(k => k.toUpperCase());
391+
392+
ownerKeys.map(key => {
393+
const hexKey = key.address.toUpperCase();
394+
if (!keys.includes(hexKey)) {
395+
throw new Error(`pub address ${hexKey} not found in account`);
396+
}
397+
398+
if (key.weight !== 1) {
399+
throw new Error('owner permission is invalid for this structure');
400+
}
401+
});
402+
}
403+
384404
/**
385405
* Builds a funds recovery transaction without BitGo.
386406
* We need to do three queries during this:
@@ -400,30 +420,34 @@ export class Trx extends BaseCoin {
400420
const keys = yield self.initiateRecovery(params);
401421

402422
// we need to decode our bitgoKey to a base58 address
403-
const bitgoAddress = self.compressedPubToHexAddress(self.xpubToCompressedPub(params.bitgoKey));
423+
const bitgoHexAddr = self.compressedPubToHexAddress(self.xpubToCompressedPub(params.bitgoKey));
404424
const recoveryAddressHex = bitgoAccountLib.Trx.Utils.getHexAddressFromBase58Address(params.recoveryDestination);
405425

406426
// call the node to get our account balance
407-
const recoveryAmount = yield self.getAccountBalanceFromNode(bitgoAddress);
427+
const account = yield self.getAccountFromNode(bitgoHexAddr);
428+
const recoveryAmount = account.balance;
408429

409430
const userXPub = keys[0].neutered().toBase58();
410431
const userXPrv = keys[0].toBase58();
411432
const backupXPub = keys[1].neutered().toBase58();
412433

413-
const userPrv = self.xprvToCompressedPrv(userXPrv);
414-
const userHexAddr = self.compressedPubToHexAddress(self.xpubToCompressedPub(userXPub));
415-
const backupHexAddr = self.compressedPubToHexAddress(self.xpubToCompressedPub(backupXPub));
416-
417434
// construct the tx -
418435
// there's an assumption here being made about fees: for a wallet that hasn't been used in awhile, the implication is
419436
// it has maximum bandwidth. thus, a recovery should cost the minimum amount (1e6 sun or 1 Tron)
420437
if (1e6 > recoveryAmount) {
421438
throw new Error('Amount of funds to recover wouldnt be able to fund a send');
422439
}
423440
const recoveryAmountMinusFees = recoveryAmount - 1e6;
424-
const buildTx = yield self.getBuildTransaction(recoveryAddressHex, bitgoAddress, recoveryAmountMinusFees);
441+
const buildTx = yield self.getBuildTransaction(recoveryAddressHex, bitgoHexAddr, recoveryAmountMinusFees);
425442

426-
// TODO: some checks here about pubs being valid, for this wallet, etc. from build transaction
443+
// run a check to ensure this is a valid tx
444+
const keyHexAddresses = [
445+
self.compressedPubToHexAddress(self.xpubToCompressedPub(userXPub)),
446+
self.compressedPubToHexAddress(self.xpubToCompressedPub(backupXPub)),
447+
bitgoHexAddr,
448+
];
449+
self.checkPermissions(account.owner_permission.keys, keyHexAddresses);
450+
self.checkPermissions(account.active_permission[0].keys, keyHexAddresses);
427451

428452
// construct our tx
429453
const txBuilder = new bitgoAccountLib.TransactionBuilder({ coinName: this.getChain() });
@@ -434,6 +458,8 @@ export class Trx extends BaseCoin {
434458
return txBuilder.build().toJson();
435459
}
436460

461+
const userPrv = self.xprvToCompressedPrv(userXPrv);
462+
437463
txBuilder.sign({ key: userPrv });
438464

439465
// krs recoveries don't get signed

modules/core/test/v2/unit/recovery.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ describe('Recovery:', function() {
566566
recoveryNocks.nockTronRecovery();
567567
});
568568

569-
it('should generate TRON recovery tx from user and backup keys', co(function *() {
569+
it('should generate recovery tx from encrypted user and backup keys', co(function *() {
570570
const recoveryTx = yield baseCoin.recover({
571571
userKey: '{"iv":"QPX3xtGROshqHW8kGPAYCw==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"LJ4YYCyClRE=","ct":"hlJH8lWk/FaciymG8UsscxVFCnOduLRjoWxaK8xU7TjsqUDXsQjj0BpH7aNm64p6ldueaGoU2/VfrrzX9lWrcVmXspFp2oON5EyK45JbI13hirqG2dkOqoT8G8mrMydMp6zG5iOA+EtXRy69kYDCI1Re6mR7k1c="}',
572572
backupKey: '{"iv":"xbOCFaZVnrQLAYKcgMvdNw==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"86cZ+hT+S0Y=","ct":"RH7Uks/JjNARX9wuIw6r4Map2C9FtLlWYk4zjLcrjzkBuNTCUNQgxF7kU5/SWzD+tomVBj6P9CLkXYzPlR1NhVi+aT9mTW6LK9nJ+ErpLKXzbIAxBLezDjJ5xqUS5cGkjoHCtANL7qTZcDBvOfejLDrUjQdw2WQ="}',
@@ -583,12 +583,33 @@ describe('Recovery:', function() {
583583
recoveryTx.raw_data_hex.should.equal('0a023ffb2208c1647593403d263b40b8b2e6fce72d5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15414d0941161d0f7e1da0c8989b1566c9d9b43e1226121541f3a3d6d514e7d43fbbf632a687acd65aafb8a50c18c0cdd6ac03709deae2fce72d');
584584
}));
585585

586-
it('should generate TRON recovery tx with unencrypted keys', co(function *() {
586+
it('should generate recovery tx with unencrypted keys', co(function *() {
587+
const recoveryTx = yield baseCoin.recover({
588+
userKey: 'xpub661MyMwAqRbcEvKZzdcvuU1nesKjFz8Gh8P1gTsowTCkGCByHRu1JsZwZYPJV6mUT3s3pQYxUtDU3JjkNruSGDK3kZUpgXqTfDAY6664a2H',
589+
backupKey: 'xpub661MyMwAqRbcF2zqeVjGdDJgEoZMFi5Vksfk3DtD9v4sBraTdgTzV3rTifJGWWudUxswBza3RotmQGxDCVKLNcRh7nW8ECB3BNSU6Xx91fL',
590+
bitgoKey: 'xpub661MyMwAqRbcFcaxCPsEyhj79VUuVVThWinZnjhvAPnFLB1SBp7Yk4gvqWsGE3MHdw1tPRLnHRRQLNcrKqaCyBnFK5XTrZUrLyY94LXn4v9',
591+
recoveryDestination: 'TYBTURKpanKxnx91uyfvvtztNeHE3EQf6G',
592+
});
587593

594+
should.exist(recoveryTx);
595+
596+
recoveryTx.txID.should.equal('55d76a068b97933a98e5d02e6fecd4c2971f1d37f0bb850a919b17def906a239');
597+
recoveryTx.raw_data_hex.should.equal('0a023ffb2208c1647593403d263b40b8b2e6fce72d5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15414d0941161d0f7e1da0c8989b1566c9d9b43e1226121541f3a3d6d514e7d43fbbf632a687acd65aafb8a50c18c0cdd6ac03709deae2fce72d');
588598
}));
589599

590-
it('should generate an TRON unsigned sweep', co(function *() {
600+
it('should generate an unsigned sweep', co(function *() {
601+
const recoveryTx = yield baseCoin.recover({
602+
userKey: '{"iv":"QPX3xtGROshqHW8kGPAYCw==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"LJ4YYCyClRE=","ct":"hlJH8lWk/FaciymG8UsscxVFCnOduLRjoWxaK8xU7TjsqUDXsQjj0BpH7aNm64p6ldueaGoU2/VfrrzX9lWrcVmXspFp2oON5EyK45JbI13hirqG2dkOqoT8G8mrMydMp6zG5iOA+EtXRy69kYDCI1Re6mR7k1c="}',
603+
backupKey: 'xpub661MyMwAqRbcF2zqeVjGdDJgEoZMFi5Vksfk3DtD9v4sBraTdgTzV3rTifJGWWudUxswBza3RotmQGxDCVKLNcRh7nW8ECB3BNSU6Xx91fL',
604+
bitgoKey: 'xpub661MyMwAqRbcFcaxCPsEyhj79VUuVVThWinZnjhvAPnFLB1SBp7Yk4gvqWsGE3MHdw1tPRLnHRRQLNcrKqaCyBnFK5XTrZUrLyY94LXn4v9',
605+
walletPassphrase: TestBitGo.V2.TEST_RECOVERY_PASSCODE,
606+
recoveryDestination: 'TYBTURKpanKxnx91uyfvvtztNeHE3EQf6G',
607+
});
608+
609+
should.exist(recoveryTx);
591610

611+
recoveryTx.txID.should.equal('55d76a068b97933a98e5d02e6fecd4c2971f1d37f0bb850a919b17def906a239');
612+
recoveryTx.raw_data_hex.should.equal('0a023ffb2208c1647593403d263b40b8b2e6fce72d5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15414d0941161d0f7e1da0c8989b1566c9d9b43e1226121541f3a3d6d514e7d43fbbf632a687acd65aafb8a50c18c0cdd6ac03709deae2fce72d');
592613
}));
593614
});
594615

0 commit comments

Comments
 (0)