Skip to content

Commit

Permalink
Merge pull request #3957 from BitGo/WP-799-add-new-method-to-sign-tss-tx
Browse files Browse the repository at this point in the history


feat(sdk-core): add new method to sign tss txs
  • Loading branch information
alebusse authored Oct 5, 2023
2 parents 80fa21e + 3e2654d commit b89bae4
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
84 changes: 84 additions & 0 deletions modules/bitgo/test/v2/unit/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2707,6 +2707,90 @@ describe('V2 Wallet:', function () {
});
});

describe('getUserKeyAndSignTssTransaction', function () {
['eddsa', 'ecdsa'].forEach((keyCurve: string) => {
describe(keyCurve, () => {
const wallet = keyCurve === 'eddsa' ? tssSolWallet : tssEthWallet;
let getKeysStub: sinon.SinonStub;
let signTransactionStub: sinon.SinonStub;
beforeEach(function () {
getKeysStub = sandbox.stub(Keychains.prototype, 'getKeysForSigning');

signTransactionStub = sandbox
.stub(Wallet.prototype, 'signTransaction')
.resolves({ ...txRequestFull, state: 'signed' });
});

afterEach(function () {
sandbox.verifyAndRestore();
});
it('should sign transaction', async function () {
getKeysStub.resolves([
{
commonKeychain: 'test',
id: '',
pub: '',
type: 'tss',
encryptedPrv:
'{"iv":"15FsbDVI1zG9OggD8YX+Hg==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"hHbNH3Sz/aU=","ct":"WoNVKz7afiRxXI2w/YkzMdMyoQg/B15u1Q8aQgi96jJZ9wk6TIaSEc6bXFH3AHzD9MdJCWJQUpRhoQc/rgytcn69scPTjKeeyVMElGCxZdFVS/psQcNE+lue3//2Zlxj+6t1NkvYO+8yAezSMRBK5OdftXEjNQI="}',
},
]);
const params = {
walletPassphrase: TestBitGo.V2.TEST_ETH_WALLET_PASSPHRASE as string,
txRequestId: 'id',
};

const response = await wallet.getUserKeyAndSignTssTransaction(params);
response.should.deepEqual({ ...txRequestFull, state: 'signed' });

getKeysStub.calledOnce.should.be.true();
signTransactionStub.calledOnce.should.be.true();
});

it('should throw if the keychain doesnt have the encryptedKey', async function () {
getKeysStub.resolves([{ commonKeychain: 'test', id: '', pub: '', type: 'tss' }]);
const params = {
walletPassphrase: TestBitGo.V2.TEST_ETH_WALLET_PASSPHRASE as string,
txRequestId: 'id',
};

await wallet
.getUserKeyAndSignTssTransaction(params)
.should.be.rejectedWith('the user keychain does not have property encryptedPrv');

getKeysStub.calledOnce.should.be.true();
signTransactionStub.notCalled.should.be.true();
});

it('should throw if password is invalid', async function () {
getKeysStub.resolves([
{
commonKeychain: 'test',
id: '',
pub: '',
type: 'tss',
encryptedPrv:
'{"iv":"15FsbDVI1zG9OggD8YX+Hg==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"hHbNH3Sz/aU=","ct":"WoNVKz7afiRxXI2w/YkzMdMyoQg/B15u1Q8aQgi96jJZ9wk6TIaSEc6bXFH3AHzD9MdJCWJQUpRhoQc/rgytcn69scPTjKeeyVMElGCxZdFVS/psQcNE+lue3//2Zlxj+6t1NkvYO+8yAezSMRBK5OdftXEjNQI="}',
},
]);
const params = {
walletPassphrase: 'randompass',
txRequestId: 'id',
};

await wallet
.getUserKeyAndSignTssTransaction(params)
.should.be.rejectedWith(
`unable to decrypt keychain with the given wallet passphrase. Error: {"message":"password error - ccm: tag doesn't match"}`
);

getKeysStub.calledOnce.should.be.true();
signTransactionStub.notCalled.should.be.true();
});
});
});
});

describe('Message Signing', function () {
const txHash = '0xrrrsss1b';
const txRequestForMessageSigning: TxRequest = {
Expand Down
37 changes: 37 additions & 0 deletions modules/sdk-core/src/bitgo/wallet/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,43 @@ export class Wallet implements IWallet {
return prebuild as PrebuildTransactionResult;
}

/**
* Gets the User Keychain and sign a TSS transaction
* @param txRequestId The transaction request id
* @param walletPassphrase The wallet passphrase
* @return Promise<SignedTransaction>
*/
async getUserKeyAndSignTssTransaction({
txRequestId,
walletPassphrase,
}: {
txRequestId: string;
walletPassphrase: string;
}): Promise<SignedTransaction> {
if (this._wallet.multisigType !== 'tss') {
throw new Error('getUserKeyAndSignTssTransaction is only supported for TSS wallets');
}
const reqId = new RequestTracer();
const keychains = await this.baseCoin.keychains().getKeysForSigning({ wallet: this, reqId });

// Doing a sanity check for password here to avoid doing further work if we know it's wrong
const userKeychain = keychains[0];
if (!userKeychain || !userKeychain.encryptedPrv) {
throw new Error('the user keychain does not have property encryptedPrv');
}
try {
this.bitgo.decrypt({ input: userKeychain.encryptedPrv, password: walletPassphrase });
} catch (e) {
const error: any = new Error(
`unable to decrypt keychain with the given wallet passphrase. Error: ${JSON.stringify(e)}`
);
error.code = 'wallet_passphrase_incorrect';
throw error;
}

return this.signTransaction({ txPrebuild: { txRequestId }, walletPassphrase, reqId, keychain: userKeychain });
}

/**
* Sign a transaction
* @param params
Expand Down

0 comments on commit b89bae4

Please sign in to comment.