Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions modules/abstract-eth/src/abstractEthLikeNewCoins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
verifyMPCWalletAddress,
TssVerifyAddressOptions,
isTssVerifyAddressOptions,
NO_RECIPIENT_TX_TYPES,
} from '@bitgo/sdk-core';
import { getDerivationPath } from '@bitgo/sdk-lib-mpc';
import { bip32 } from '@bitgo/secp256k1';
Expand Down Expand Up @@ -3104,33 +3105,28 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
);
};

if (!wallet || !txPrebuild) {
throw new Error('missing params');
}
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error('tx cannot be both a batch and hop transaction');
}

if (
!params.verification?.skipTssRecipientVerification &&
!txParams?.recipients &&
!(
txParams.prebuildTx?.consolidateId ||
txPrebuild?.consolidateId ||
(txParams.type &&
[
'acceleration',
'fillNonce',
'transferToken',
'tokenApproval',
'consolidate',
'bridgeFunds',
'enabletoken',
].includes(txParams.type))
txParams.stakingRequestId ||
txParams.prebuildTx?.stakingRequestId ||
(txParams.type && NO_RECIPIENT_TX_TYPES.has(txParams.type))
)
) {
throw new Error('missing txParams');
}
if (!wallet || !txPrebuild) {
throw new Error('missing params');
}
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error('tx cannot be both a batch and hop transaction');
}

if (txParams.type && ['transfer'].includes(txParams.type)) {
if (!params.verification?.skipTssRecipientVerification && txParams.type && ['transfer'].includes(txParams.type)) {
if (txParams.recipients && txParams.recipients.length === 1) {
const recipients = txParams.recipients;
const expectedAmount = recipients[0].amount.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ export const VerificationOptions = t.partial({
verifyTokenEnablement: t.boolean,
/** Verify consolidation to base address */
consolidationToBaseAddress: t.boolean,
/** Skip TSS recipient verification during signing */
skipTssRecipientVerification: t.boolean,
});

/**
Expand Down
28 changes: 20 additions & 8 deletions modules/sdk-coin-bsc/src/bsc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { BaseCoin, BitGoBase, common, MPCAlgorithm, MultisigType, multisigTypes } from '@bitgo/sdk-core';
import {
BaseCoin,
BitGoBase,
common,
MPCAlgorithm,
MultisigType,
multisigTypes,
NO_RECIPIENT_TX_TYPES,
} from '@bitgo/sdk-core';
import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics';
import {
AbstractEthLikeNewCoins,
Expand Down Expand Up @@ -66,21 +74,25 @@ export class Bsc extends AbstractEthLikeNewCoins {
*/
async verifyTssTransaction(params: VerifyEthTransactionOptions): Promise<boolean> {
const { txParams, txPrebuild, wallet } = params;
if (!wallet || !txPrebuild) {
throw new Error(`missing params`);
}
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error(`tx cannot be both a batch and hop transaction`);
}

if (
!params.verification?.skipTssRecipientVerification &&
!txParams?.recipients &&
!(
txParams.prebuildTx?.consolidateId ||
(txParams.type && ['acceleration', 'fillNonce', 'transferToken', 'tokenApproval'].includes(txParams.type))
txParams.stakingRequestId ||
txParams.prebuildTx?.stakingRequestId ||
(txParams.type && NO_RECIPIENT_TX_TYPES.has(txParams.type))
)
) {
throw new Error(`missing txParams`);
}
if (!wallet || !txPrebuild) {
throw new Error(`missing params`);
}
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error(`tx cannot be both a batch and hop transaction`);
}

return true;
}
Expand Down
20 changes: 12 additions & 8 deletions modules/sdk-coin-bsc/src/bscToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

import { EthLikeTokenConfig, coins } from '@bitgo/statics';
import { BitGoBase, CoinConstructor, NamedCoinConstructor, MPCAlgorithm } from '@bitgo/sdk-core';
import { BitGoBase, CoinConstructor, NamedCoinConstructor, MPCAlgorithm, NO_RECIPIENT_TX_TYPES } from '@bitgo/sdk-core';
import { CoinNames, EthLikeToken, VerifyEthTransactionOptions } from '@bitgo/abstract-eth';
import { TransactionBuilder } from './lib';

Expand Down Expand Up @@ -54,21 +54,25 @@ export class BscToken extends EthLikeToken {
*/
async verifyTssTransaction(params: VerifyEthTransactionOptions): Promise<boolean> {
const { txParams, txPrebuild, wallet } = params;
if (!wallet || !txPrebuild) {
throw new Error(`missing params`);
}
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error(`tx cannot be both a batch and hop transaction`);
}

if (
!params.verification?.skipTssRecipientVerification &&
!txParams?.recipients &&
!(
txParams.prebuildTx?.consolidateId ||
(txParams.type && ['acceleration', 'fillNonce', 'transferToken'].includes(txParams.type))
txParams.stakingRequestId ||
txParams.prebuildTx?.stakingRequestId ||
(txParams.type && NO_RECIPIENT_TX_TYPES.has(txParams.type))
)
) {
throw new Error(`missing txParams`);
}
if (!wallet || !txPrebuild) {
throw new Error(`missing params`);
}
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error(`tx cannot be both a batch and hop transaction`);
}

return true;
}
Expand Down
120 changes: 120 additions & 0 deletions modules/sdk-coin-bsc/test/unit/bsc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'should';
import assert from 'assert';

import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test';
import { BitGoAPI } from '@bitgo/sdk-api';
Expand Down Expand Up @@ -39,4 +40,123 @@ describe('Native BNB', function () {
tbsc.allowsAccountConsolidations().should.equal(true);
});
});

describe('verifyTssTransaction', function () {
let bsc: Bsc;

before(function () {
bsc = bitgo.coin('bsc') as Bsc;
});

const baseTxPrebuild = { txHex: '0xdeadbeef' } as any;
const baseWallet = {} as any;

it('returns true immediately when skipTssRecipientVerification is true', async function () {
const result = await bsc.verifyTssTransaction({
txParams: {} as any,
txPrebuild: baseTxPrebuild,
wallet: baseWallet,
verification: { skipTssRecipientVerification: true },
});
assert.strictEqual(result, true);
});

it('throws when no recipients and skipTssRecipientVerification is false', async function () {
await assert.rejects(
() =>
bsc.verifyTssTransaction({
txParams: {} as any,
txPrebuild: baseTxPrebuild,
wallet: baseWallet,
verification: { skipTssRecipientVerification: false },
}),
/missing txParams/
);
});

it('throws when no recipients and verification is not set', async function () {
await assert.rejects(
() =>
bsc.verifyTssTransaction({
txParams: {} as any,
txPrebuild: baseTxPrebuild,
wallet: baseWallet,
}),
/missing txParams/
);
});

it('returns true for exempt type without skipTssRecipientVerification', async function () {
const result = await bsc.verifyTssTransaction({
txParams: { type: 'delegate' } as any,
txPrebuild: baseTxPrebuild,
wallet: baseWallet,
});
assert.strictEqual(result, true);
});

it('returns true when recipients are present without flag', async function () {
const result = await bsc.verifyTssTransaction({
txParams: { recipients: [{ address: '0xabc', amount: '100' }] } as any,
txPrebuild: baseTxPrebuild,
wallet: baseWallet,
});
assert.strictEqual(result, true);
});

it('still throws missing params when wallet is missing even with skipTssRecipientVerification', async function () {
await assert.rejects(
() =>
bsc.verifyTssTransaction({
txParams: {} as any,
txPrebuild: baseTxPrebuild,
wallet: undefined as any,
verification: { skipTssRecipientVerification: true },
}),
/missing params/
);
});

it('still throws missing params when txPrebuild is missing even with skipTssRecipientVerification', async function () {
await assert.rejects(
() =>
bsc.verifyTssTransaction({
txParams: {} as any,
txPrebuild: undefined as any,
wallet: baseWallet,
verification: { skipTssRecipientVerification: true },
}),
/missing params/
);
});

it('still throws hop error even with skipTssRecipientVerification', async function () {
await assert.rejects(
() =>
bsc.verifyTssTransaction({
txParams: {
hop: true,
recipients: [
{ address: '0xabc', amount: '100' },
{ address: '0xdef', amount: '200' },
],
} as any,
txPrebuild: baseTxPrebuild,
wallet: baseWallet,
verification: { skipTssRecipientVerification: true },
}),
/tx cannot be both a batch and hop transaction/
);
});

it('skips recipient check but passes other validation with skipTssRecipientVerification', async function () {
const result = await bsc.verifyTssTransaction({
txParams: {} as any,
txPrebuild: baseTxPrebuild,
wallet: baseWallet,
verification: { skipTssRecipientVerification: true },
});
assert.strictEqual(result, true);
});
});
});
25 changes: 14 additions & 11 deletions modules/sdk-coin-evm/src/evmCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
MPCAlgorithm,
MultisigType,
multisigTypes,
NO_RECIPIENT_TX_TYPES,
} from '@bitgo/sdk-core';
import { BaseCoin as StaticsBaseCoin, CoinFeature, coins, CoinFamily } from '@bitgo/statics';
import {
Expand Down Expand Up @@ -112,26 +113,28 @@ export class EvmCoin extends AbstractEthLikeNewCoins {
private async verifyLegacyTssTransaction(params: VerifyEthTransactionOptions): Promise<boolean> {
const { txParams, txPrebuild, wallet } = params;

// Basic validation for legacy transactions only
if (!wallet || !txPrebuild) {
throw new Error(`missing params`);
}

if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error(`tx cannot be both a batch and hop transaction`);
}

// Only enforce recipient presence when skipTssRecipientVerification is not set
if (
!params.verification?.skipTssRecipientVerification &&
!txParams?.recipients &&
!(
txParams.prebuildTx?.consolidateId ||
(txParams.type &&
['acceleration', 'fillNonce', 'transferToken', 'tokenApproval', 'bridgeFunds'].includes(txParams.type))
txParams.stakingRequestId ||
txParams.prebuildTx?.stakingRequestId ||
(txParams.type && NO_RECIPIENT_TX_TYPES.has(txParams.type))
)
) {
throw new Error(`missing txParams`);
}

if (!wallet || !txPrebuild) {
throw new Error(`missing params`);
}

if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error(`tx cannot be both a batch and hop transaction`);
}

// If validation passes, consider it verified
return true;
}
Expand Down
29 changes: 20 additions & 9 deletions modules/sdk-coin-xdc/src/xdc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { BaseCoin, BitGoBase, common, MPCAlgorithm, MultisigType, multisigTypes } from '@bitgo/sdk-core';
import {
BaseCoin,
BitGoBase,
common,
MPCAlgorithm,
MultisigType,
multisigTypes,
NO_RECIPIENT_TX_TYPES,
} from '@bitgo/sdk-core';
import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics';
import {
AbstractEthLikeNewCoins,
Expand Down Expand Up @@ -58,22 +66,25 @@ export class Xdc extends AbstractEthLikeNewCoins {
*/
async verifyTssTransaction(params: VerifyEthTransactionOptions): Promise<boolean> {
const { txParams, txPrebuild, wallet } = params;
if (!wallet || !txPrebuild) {
throw new Error(`missing params`);
}
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error(`tx cannot be both a batch and hop transaction`);
}

if (
!params.verification?.skipTssRecipientVerification &&
!txParams?.recipients &&
!(
txParams.prebuildTx?.consolidateId ||
(txParams.type &&
['acceleration', 'fillNonce', 'transferToken', 'tokenApproval', 'consolidate'].includes(txParams.type))
txParams.stakingRequestId ||
txParams.prebuildTx?.stakingRequestId ||
(txParams.type && NO_RECIPIENT_TX_TYPES.has(txParams.type))
)
) {
throw new Error(`missing txParams`);
}
if (!wallet || !txPrebuild) {
throw new Error(`missing params`);
}
if (txParams.hop && txParams.recipients && txParams.recipients.length > 1) {
throw new Error(`tx cannot be both a batch and hop transaction`);
}

return true;
}
Expand Down
Loading
Loading