Skip to content
Merged
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
56 changes: 56 additions & 0 deletions modules/bitgo/test/v2/unit/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,62 @@ describe('V2 Wallet:', function () {
});
});

describe('Custody sBTC bridging/withdraw params pass-through', function () {
const bridgingParams = {
sbtc: {
amount: 100000,
stacksRecipient: 'SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7',
maxFee: 5000,
lockTime: 144,
},
};
const sbtcWithdrawParams = {
amount: '100000',
btcAddress: '2N9Ego9KidiZR8tMP82g6RaggQtcbR9zNzH',
maxFee: '5000',
};

afterEach(function () {
nock.cleanAll();
});

it('should pass bridgingParams through sendMany to tx/initiate for custodial wallets', async function () {
const custodialWallet = new Wallet(bitgo, bitgo.coin('tbtc'), {
id: '5b34252f1bf349930e34020a',
coin: 'tbtc',
type: 'custodial',
keys: ['5b3424f91bf349930e340175'],
});

const initiatePath = `/api/v2/${custodialWallet.coin()}/wallet/${custodialWallet.id()}/tx/initiate`;
const response = nock(bgUrl)
.post(initiatePath, _.matches({ type: 'bridging', bridgingParams }))
.reply(200, { status: 'accepted', txRequestId: 'mock-tx-request-id' });

const result = await custodialWallet.sendMany({ type: 'bridging', bridgingParams });
response.isDone().should.be.true();
(result as any).status.should.equal('accepted');
});

it('should pass sbtcWithdrawParams through sendMany to tx/initiate for custodial wallets', async function () {
const custodialWallet = new Wallet(bitgo, bitgo.coin('tbtc'), {
id: '5b34252f1bf349930e34020a',
coin: 'tbtc',
type: 'custodial',
keys: ['5b3424f91bf349930e340175'],
});

const initiatePath = `/api/v2/${custodialWallet.coin()}/wallet/${custodialWallet.id()}/tx/initiate`;
const response = nock(bgUrl)
.post(initiatePath, _.matches({ sbtcWithdrawParams }))
.reply(200, { status: 'accepted', txRequestId: 'mock-tx-request-id' });

const result = await custodialWallet.sendMany({ sbtcWithdrawParams } as any);
response.isDone().should.be.true();
(result as any).status.should.equal('accepted');
});
});

describe('Transaction prebuilds', function () {
let ethWallet;

Expand Down
2 changes: 1 addition & 1 deletion modules/sdk-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
]
},
"dependencies": {
"@bitgo/public-types": "6.53.0",
"@bitgo/public-types": "6.56.0",
"@bitgo/sdk-lib-mpc": "^10.15.0",
"@bitgo/secp256k1": "^1.11.0",
"@bitgo/sjcl": "^1.1.0",
Expand Down
13 changes: 12 additions & 1 deletion modules/sdk-core/test/unit/bitgo/wallet/BuildParams.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import * as assert from 'assert';
import { BuildParams, buildParamKeys, AttestationPayload } from '../../../../src/bitgo/wallet/BuildParams';
import {
BuildParams,
buildParamKeys,
AttestationPayload,
SbtcWithdrawParams,
} from '../../../../src/bitgo/wallet/BuildParams';

describe('BuildParams', function () {
it('enforces codec', function () {
Expand Down Expand Up @@ -106,4 +111,10 @@ describe('BuildParams', function () {
assert.strictEqual(AttestationPayload.is(valid), true);
assert.strictEqual(AttestationPayload.is({ ...valid, signature: undefined }), false);
});

it('SbtcWithdrawParams codec accepts partial string fields', function () {
assert.strictEqual(SbtcWithdrawParams.is({ amount: '100000', btcAddress: 'mtbtcaddr', maxFee: '5000' }), true);
assert.strictEqual(SbtcWithdrawParams.is({}), true);
assert.strictEqual(SbtcWithdrawParams.is({ amount: 100000 }), false); // must be string, not number
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,64 @@ describe('SendTransactionRequest', function () {
attestation,
});
});

it('preserves bridgingParams (CSHLD-1456: @bitgo/public-types TxSendBody declares it natively)', function () {
const bridgingParams = {
sbtc: {
amount: '100000',
stacksRecipient: 'SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7',
maxFee: '5000',
lockTime: 144,
},
};

assert.deepStrictEqual(TxSendBody.encode({ txHex: '00', bridgingParams } as any), {
txHex: '00',
bridgingParams,
});
});

it('preserves sbtcWithdrawParams (CSHLD-1456: @bitgo/public-types TxSendBody declares it natively)', function () {
const sbtcWithdrawParams = { amount: '100000', btcAddress: 'mtbtcaddr', maxFee: '5000' };

assert.deepStrictEqual(TxSendBody.encode({ txHex: '00', sbtcWithdrawParams } as any), {
txHex: '00',
sbtcWithdrawParams,
});
});

it('validates bridgingParams.sbtc as a complete shape', function () {
const valid = {
sbtc: {
amount: '100000',
stacksRecipient: 'SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7',
maxFee: '5000',
lockTime: 144,
},
};
assert.strictEqual(TxSendBody.is({ bridgingParams: valid }), true);
assert.strictEqual(TxSendBody.is({}), true); // bridgingParams itself is optional
assert.strictEqual(TxSendBody.is({ bridgingParams: {} }), true); // sbtc is optional within bridgingParams

// amount/maxFee accept string or number
assert.strictEqual(
TxSendBody.is({ bridgingParams: { sbtc: { ...valid.sbtc, amount: 100000, maxFee: 5000 } } }),
true
);

// sbtc, once present, requires all four fields
const missingAmount = {
stacksRecipient: valid.sbtc.stacksRecipient,
maxFee: valid.sbtc.maxFee,
lockTime: valid.sbtc.lockTime,
};
assert.strictEqual(TxSendBody.is({ bridgingParams: { sbtc: missingAmount } }), false);
});

it('validates sbtcWithdrawParams fields as strings', function () {
const valid = { amount: '100000', btcAddress: 'mtbtcaddr', maxFee: '5000' };
assert.strictEqual(TxSendBody.is({ sbtcWithdrawParams: valid }), true);
assert.strictEqual(TxSendBody.is({ sbtcWithdrawParams: {} }), true); // all fields optional
assert.strictEqual(TxSendBody.is({ sbtcWithdrawParams: { ...valid, amount: 100000 } }), false); // must be string
});
});
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1043,10 +1043,10 @@
monocle-ts "^2.3.13"
newtype-ts "^0.3.5"

"@bitgo/public-types@6.53.0":
version "6.53.0"
resolved "https://registry.npmjs.org/@bitgo/public-types/-/public-types-6.53.0.tgz#fedaf8dbdc7f5fbe25279e560fd76ed25d9443ed"
integrity sha512-nei+2f2fmrnqVZnQ2GBVSbHy0O5bZwcfp/R1jKpuYFOWQgeZtFmblVMhnbN1sfFVyAAGOdacZtx7d56+qZ0TNA==
"@bitgo/public-types@6.56.0":
version "6.56.0"
resolved "https://registry.npmjs.org/@bitgo/public-types/-/public-types-6.56.0.tgz#ddfdb65273334a320dfa11de3f4ad48beba23ce0"
integrity sha512-IF+qN5gqVfkyBLC8e1K85fxOX4chbYNF1EWQZexqMJjVQZsijMe3m6qkQG8IBJPCH34yhHLa3WcV/sEXKoCT2g==
dependencies:
fp-ts "^2.0.0"
io-ts "npm:@bitgo-forks/io-ts@2.1.4"
Expand Down
Loading