Skip to content

Commit 42f353f

Browse files
ipelaez-simtlixsilalvado
authored andcommitted
feat(bitgo): add api version input
add api version input to prebuildTransactionTss method BG-57753
1 parent 70fb315 commit 42f353f

File tree

6 files changed

+91
-9
lines changed

6 files changed

+91
-9
lines changed

modules/bitgo/test/v2/unit/wallet.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,18 @@ describe('V2 Wallet:', function () {
16821682
}).should.be.rejectedWith('transaction type not supported: stake');
16831683
});
16841684

1685+
it('should fail for full api version compatibility', async function () {
1686+
await custodialTssWallet.prebuildTransaction({
1687+
reqId,
1688+
apiVersion: 'lite',
1689+
recipients: [{
1690+
address: '6DadkZcx9JZgeQUDbHh12cmqCpaqehmVxv6sGy49jrah',
1691+
amount: '1000',
1692+
}],
1693+
type: 'transfer',
1694+
}).should.be.rejectedWith(`Custodial and ECDSA MPC algorithm must always use 'full' api version`);
1695+
});
1696+
16851697
it('should build a single recipient transfer transaction for full', async function () {
16861698
const recipients = [{
16871699
address: '6DadkZcx9JZgeQUDbHh12cmqCpaqehmVxv6sGy49jrah',
@@ -1942,6 +1954,44 @@ describe('V2 Wallet:', function () {
19421954
intent.isTss!.should.equal(true);
19431955
intent.intentType.should.equal('fillNonce');
19441956
});
1957+
1958+
it('should build a single recipient transfer transaction providing apiVersion parameter as "full" ', async function () {
1959+
const recipients = [{
1960+
address: '6DadkZcx9JZgeQUDbHh12cmqCpaqehmVxv6sGy49jrah',
1961+
amount: '1000',
1962+
}];
1963+
1964+
const prebuildTxWithIntent = sandbox.stub(TssUtils.prototype, 'prebuildTxWithIntent');
1965+
prebuildTxWithIntent.resolves(txRequestFull);
1966+
prebuildTxWithIntent.calledOnceWithExactly({
1967+
reqId,
1968+
recipients,
1969+
intentType: 'payment',
1970+
}, 'full');
1971+
1972+
const txPrebuild = await custodialTssWallet.prebuildTransaction({
1973+
reqId,
1974+
apiVersion: 'full',
1975+
recipients,
1976+
type: 'transfer',
1977+
});
1978+
1979+
txPrebuild.should.deepEqual({
1980+
walletId: tssWallet.id(),
1981+
wallet: custodialTssWallet,
1982+
txRequestId: 'id',
1983+
txHex: 'ababcdcd',
1984+
buildParams: {
1985+
apiVersion: 'full',
1986+
recipients,
1987+
type: 'transfer',
1988+
},
1989+
feeInfo: {
1990+
fee: 5000,
1991+
feeString: '5000',
1992+
},
1993+
});
1994+
});
19451995
});
19461996

19471997
describe('Transaction signing', function () {

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,11 +453,21 @@ export class Sol extends BaseCoin {
453453

454454
await tssUtils!.deleteSignatureShares(txRequestId);
455455
const recreated = await tssUtils!.getTxRequest(txRequestId);
456+
let txHex = '';
457+
if (recreated.unsignedTxs) {
458+
txHex = recreated.unsignedTxs[0]?.serializedTxHex;
459+
} else {
460+
txHex = recreated.transactions ? recreated.transactions[0]?.unsignedTx.serializedTxHex : '';
461+
}
462+
463+
if (!txHex) {
464+
throw new Error('Missing serialized tx hex');
465+
}
456466

457467
return Promise.resolve({
458468
...params,
459469
txPrebuild: recreated,
460-
txHex: recreated.unsignedTxs[0].serializedTxHex,
470+
txHex,
461471
});
462472
}
463473

modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { SerializedKeyPair } from 'openpgp';
22
import { IRequestTracer } from '../../../api';
33
import { KeychainsTriplet } from '../../baseCoin';
44
import { ApiKeyShare, Keychain } from '../../keychain';
5-
import { Memo, WalletType } from '../../wallet';
5+
import { ApiVersion, Memo, WalletType } from '../../wallet';
66
import { EDDSA, GShare, SignShare, YShare } from '../../../account-lib/mpc/tss';
77
import { KeyShare } from './ecdsa';
88

@@ -227,6 +227,7 @@ export type TSSParams = {
227227
txRequest: string | TxRequest; // can be either a string or TxRequest
228228
prv: string;
229229
reqId: IRequestTracer;
230+
apiVersion?: ApiVersion;
230231
};
231232

232233
export type TSSParamsForMessage = TSSParams & {

modules/sdk-core/src/bitgo/utils/tss/eddsa/eddsa.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ export class EddsaUtils extends baseTSSUtils<KeyShare> {
457457
let txRequestResolved: TxRequest;
458458
let txRequestId: string;
459459

460-
const { txRequest, prv } = params;
460+
const { txRequest, prv, apiVersion } = params;
461461

462462
if (typeof txRequest === 'string') {
463463
txRequestResolved = await getTxRequest(this.bitgo, this.wallet.id(), txRequest);
@@ -495,7 +495,14 @@ export class EddsaUtils extends baseTSSUtils<KeyShare> {
495495
const bitgoGpgKey = await getBitgoGpgPubKey(this.bitgo);
496496
const encryptedSignerShare = await encryptText(signerShare, bitgoGpgKey);
497497

498-
await offerUserToBitgoRShare(this.bitgo, this.wallet.id(), txRequestId, userSignShare, encryptedSignerShare);
498+
await offerUserToBitgoRShare(
499+
this.bitgo,
500+
this.wallet.id(),
501+
txRequestId,
502+
userSignShare,
503+
encryptedSignerShare,
504+
apiVersion
505+
);
499506

500507
const bitgoToUserRShare = await getBitgoToUserRShare(this.bitgo, this.wallet.id(), txRequestId);
501508

@@ -507,7 +514,7 @@ export class EddsaUtils extends baseTSSUtils<KeyShare> {
507514
signablePayload
508515
);
509516

510-
await sendUserToBitgoGShare(this.bitgo, this.wallet.id(), txRequestId, userToBitGoGShare);
517+
await sendUserToBitgoGShare(this.bitgo, this.wallet.id(), txRequestId, userToBitGoGShare, apiVersion);
511518

512519
return await getTxRequest(this.bitgo, this.wallet.id(), txRequestId);
513520
}

modules/sdk-core/src/bitgo/wallet/iWallet.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export interface BuildTokenEnablementOptions extends PrebuildTransactionOptions
5252
enableTokens: TokenEnablement[];
5353
}
5454

55+
export type ApiVersion = 'lite' | 'full';
56+
5557
export interface PrebuildTransactionOptions {
5658
reqId?: IRequestTracer;
5759
recipients?: {
@@ -104,6 +106,7 @@ export interface PrebuildTransactionOptions {
104106
lowFeeTxid?: string;
105107
isTss?: boolean;
106108
custodianTransactionId?: string;
109+
apiVersion?: ApiVersion;
107110
}
108111

109112
export interface PrebuildAndSignTransactionOptions extends PrebuildTransactionOptions, WalletSignTransactionOptions {
@@ -143,6 +146,7 @@ export interface WalletSignTransactionOptions extends WalletSignBaseOptions {
143146
txPrebuild?: TransactionPrebuild;
144147
customRShareGeneratingFunction?: CustomRShareGeneratingFunction;
145148
customGShareGeneratingFunction?: CustomGShareGeneratingFunction;
149+
apiVersion?: ApiVersion;
146150
[index: string]: unknown;
147151
}
148152

modules/sdk-core/src/bitgo/wallet/wallet.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ export class Wallet implements IWallet {
151151
prebuildWhitelistedParams(): string[] {
152152
return [
153153
'addressType',
154+
'apiVersion',
154155
'changeAddress',
155156
'consolidateAddresses',
156157
'cpfpFeeRate',
@@ -1537,7 +1538,7 @@ export class Wallet implements IWallet {
15371538
* @return {*}
15381539
*/
15391540
async signTransaction(params: WalletSignTransactionOptions = {}): Promise<SignedTransaction | TxRequest> {
1540-
const { txPrebuild } = params;
1541+
const { txPrebuild, apiVersion } = params;
15411542

15421543
if (_.isFunction(params.customGShareGeneratingFunction) && _.isFunction(params.customRShareGeneratingFunction)) {
15431544
// invoke external signer TSS for EdDSA workflow
@@ -1555,7 +1556,7 @@ export class Wallet implements IWallet {
15551556
});
15561557

15571558
if (this._wallet.multisigType === 'tss') {
1558-
return this.signTransactionTss({ ...presign, prv: this.getUserPrv(presign as GetUserPrvOptions) });
1559+
return this.signTransactionTss({ ...presign, prv: this.getUserPrv(presign as GetUserPrvOptions), apiVersion });
15591560
}
15601561

15611562
let { pubs } = params;
@@ -2526,8 +2527,16 @@ export class Wallet implements IWallet {
25262527
private async prebuildTransactionTss(params: PrebuildTransactionOptions = {}): Promise<PrebuildTransactionResult> {
25272528
const reqId = params.reqId || new RequestTracer();
25282529
this.bitgo.setRequestTracer(reqId);
2530+
if (
2531+
params.apiVersion === 'lite' &&
2532+
(this._wallet.type === 'custodial' || this.baseCoin.getMPCAlgorithm() === 'ecdsa')
2533+
) {
2534+
throw new Error(`Custodial and ECDSA MPC algorithm must always use 'full' api version`);
2535+
}
2536+
25292537
const apiVersion =
2530-
this._wallet.type === 'custodial' || this.baseCoin.getMPCAlgorithm() === 'ecdsa' ? 'full' : 'lite';
2538+
params.apiVersion ||
2539+
(this._wallet.type === 'custodial' || this.baseCoin.getMPCAlgorithm() === 'ecdsa' ? 'full' : 'lite');
25312540

25322541
// Two options different implementations of fees seems to now be supported, for now we will support both to be backwards compatible
25332542
// TODO(BG-59685): deprecate one of these so that we have a single way to pass fees
@@ -2704,6 +2713,7 @@ export class Wallet implements IWallet {
27042713
txRequest: params.txPrebuild.txRequestId,
27052714
prv: params.prv,
27062715
reqId: params.reqId || new RequestTracer(),
2716+
apiVersion: params.apiVersion,
27072717
});
27082718
return {
27092719
txRequestId: signedTxRequest.txRequestId,
@@ -2789,7 +2799,7 @@ export class Wallet implements IWallet {
27892799
}
27902800

27912801
// ECDSA TSS uses TxRequestFull
2792-
if (this.baseCoin.getMPCAlgorithm() === 'ecdsa') {
2802+
if (this.baseCoin.getMPCAlgorithm() === 'ecdsa' || params.apiVersion === 'full') {
27932803
return signedTransaction;
27942804
}
27952805

0 commit comments

Comments
 (0)