Skip to content

Commit ed90e7d

Browse files
committed
feat: add support for withdrawals from receive addr for ADA
TICKET: WIN-3537
1 parent d816d13 commit ed90e7d

File tree

9 files changed

+96
-6
lines changed

9 files changed

+96
-6
lines changed

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import {
3030
BaseTssUtils,
3131
KeyType,
3232
SendManyOptions,
33+
PopulatedIntent,
34+
TxRequestVersion,
3335
} from '@bitgo/sdk-core';
3436

3537
import { TestBitGo } from '@bitgo/sdk-test';
@@ -46,6 +48,12 @@ require('should-sinon');
4648

4749
nock.disableNetConnect();
4850

51+
type CreateTxRequestBody = {
52+
intent: PopulatedIntent;
53+
apiversion: TxRequestVersion;
54+
preview?: boolean;
55+
};
56+
4957
describe('V2 Wallet:', function () {
5058
const reqId = new RequestTracer();
5159
const bitgo = TestBitGo.decorate(BitGo, { env: 'test' });
@@ -4387,5 +4395,46 @@ describe('V2 Wallet:', function () {
43874395
sinon.stub(BaseTssUtils.default.prototype, 'sendTxRequest').resolves('sendTxResponse');
43884396
await adaWallet.sendMany(sendManyParams);
43894397
});
4398+
4399+
it('Should send senderAddress in payment intent when using sendmany', async function () {
4400+
const sendManyParams = {
4401+
type: 'transfer',
4402+
recipients: [
4403+
{
4404+
address: 'address',
4405+
amount: '1000',
4406+
},
4407+
],
4408+
senderAddress: 'senderAddr1',
4409+
};
4410+
4411+
nock(bgUrl)
4412+
.post(`/api/v2/wallet/${adaWallet.id()}/txrequests`)
4413+
.reply((url, body: nock.Body) => {
4414+
const createTxRequestBody = body as CreateTxRequestBody;
4415+
createTxRequestBody.intent.intentType.should.equal('payment');
4416+
createTxRequestBody.intent.senderAddress?.should.equal('senderAddr1');
4417+
4418+
return [
4419+
200,
4420+
{
4421+
apiVersion: 'lite',
4422+
unsignedTxs: [
4423+
{
4424+
unsignedTx: {
4425+
serializedTxHex: 'serializedTxHex',
4426+
feeInfo: 'fee info',
4427+
},
4428+
},
4429+
],
4430+
},
4431+
];
4432+
});
4433+
4434+
sinon.stub(adaWallet.baseCoin, 'verifyTransaction').resolves(true);
4435+
sinon.stub(adaWallet, 'signTransaction').resolves({ txRequestId: 'txRequestId' });
4436+
sinon.stub(BaseTssUtils.default.prototype, 'sendTxRequest').resolves('sendTxResponse');
4437+
await adaWallet.sendMany(sendManyParams).should.be.resolved();
4438+
});
43904439
});
43914440
});

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import {
2727
MPCUnsignedTx,
2828
MPCSweepRecoveryOptions,
2929
MPCTxs,
30+
PopulatedIntent,
31+
PrebuildTransactionWithIntentOptions,
3032
} from '@bitgo/sdk-core';
3133
import { KeyPair as AdaKeyPair, Transaction, TransactionBuilderFactory, Utils } from './lib';
3234
import { BaseCoin as StaticsBaseCoin, CoinFamily, coins } from '@bitgo/statics';
@@ -613,4 +615,10 @@ export class Ada extends BaseCoin {
613615
private getBuilder(): TransactionBuilderFactory {
614616
return new TransactionBuilderFactory(coins.get(this.getBaseChain()));
615617
}
618+
619+
/** inherited doc */
620+
setCoinSpecificFieldsInIntent(intent: PopulatedIntent, params: PrebuildTransactionWithIntentOptions): void {
621+
intent.unspents = params.unspents;
622+
intent.senderAddress = params.senderAddress;
623+
}
616624
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import {
2525
TransactionExplanation,
2626
TssVerifyAddressOptions,
2727
VerifyTransactionOptions,
28+
PopulatedIntent,
29+
PrebuildTransactionWithIntentOptions,
2830
} from '@bitgo/sdk-core';
2931
import { BaseCoin as StaticsBaseCoin, BaseNetwork, coins, SuiCoin } from '@bitgo/statics';
3032
import BigNumber from 'bignumber.js';
@@ -791,4 +793,9 @@ export class Sui extends BaseCoin {
791793

792794
return { transactions: consolidationTransactions, lastScanIndex };
793795
}
796+
797+
/** inherited doc */
798+
setCoinSpecificFieldsInIntent(intent: PopulatedIntent, params: PrebuildTransactionWithIntentOptions): void {
799+
intent.unspents = params.unspents;
800+
}
794801
}

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import {
4545
} from './iBaseCoin';
4646
import { IInscriptionBuilder } from '../inscriptionBuilder';
4747
import { Hash } from 'crypto';
48-
import { MPCSweepRecoveryOptions, MPCTxs } from '../utils';
48+
import { MPCSweepRecoveryOptions, MPCTxs, PopulatedIntent, PrebuildTransactionWithIntentOptions } from '../utils';
4949

5050
export abstract class BaseCoin implements IBaseCoin {
5151
protected readonly bitgo: BitGoBase;
@@ -551,4 +551,15 @@ export abstract class BaseCoin implements IBaseCoin {
551551
async createBroadcastableSweepTransaction(params: MPCSweepRecoveryOptions): Promise<MPCTxs> {
552552
throw new NotImplementedError('createBroadcastableSweepTransaction is not supported for this coin');
553553
}
554+
555+
/**
556+
* Sets coinspecific fields in intent from input params.
557+
* This method should be overridden in coin-specific classes
558+
* to configure these fields in the intent
559+
* @param intent - intent in which coinspecific fields are to be set
560+
* @param params
561+
*/
562+
setCoinSpecificFieldsInIntent(intent: PopulatedIntent, params: PrebuildTransactionWithIntentOptions): void {
563+
return;
564+
}
554565
}

modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import { IMarkets } from '../market';
77
import { IPendingApprovals } from '../pendingApproval';
88
import { InitiateRecoveryOptions } from '../recovery';
99
import { EcdsaMPCv2Utils, EcdsaUtils } from '../utils/tss/ecdsa';
10-
import EddsaUtils, { TxRequest } from '../utils/tss/eddsa';
10+
import EddsaUtils, { PrebuildTransactionWithIntentOptions, TxRequest } from '../utils/tss/eddsa';
1111
import { CustomSigningFunction, IWallet, IWallets, Wallet, WalletData } from '../wallet';
1212

1313
import { IWebhooks } from '../webhook/iWebhooks';
1414
import { TransactionType } from '../../account-lib';
1515
import { IInscriptionBuilder } from '../inscriptionBuilder';
1616
import { Hash } from 'crypto';
17-
import { MPCTx } from '../utils';
17+
import { MPCTx, PopulatedIntent } from '../utils';
1818

1919
export interface Output extends ITransactionRecipient {
2020
address: string;
@@ -537,4 +537,5 @@ export interface IBaseCoin {
537537
buildNftTransferData(params: BuildNftTransferDataOptions): string;
538538
getHashFunction(): Hash;
539539
broadcastTransaction(params: BaseBroadcastTransactionOptions): Promise<BaseBroadcastTransactionResult>;
540+
setCoinSpecificFieldsInIntent(intent: PopulatedIntent, params: PrebuildTransactionWithIntentOptions): void;
540541
}

modules/sdk-core/src/bitgo/utils/mpcUtils.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,7 @@ export abstract class MpcUtils {
169169
}
170170
}
171171

172-
if (['ada', 'sui'].includes(baseCoin.getFamily()) && params.unspents) {
173-
baseIntent.unspents = params.unspents;
174-
}
172+
this.baseCoin.setCoinSpecificFieldsInIntent(baseIntent, params);
175173

176174
if (params.feeOptions !== undefined) {
177175
return {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ export interface PrebuildTransactionWithIntentOptions extends IntentOptionsBase
195195
custodianTransactionId?: string;
196196
receiveAddress?: string;
197197
unspents?: string[];
198+
/**
199+
* The receive address from which funds will be withdrawn.
200+
* This feature is supported only for specific coins, like ADA.
201+
*/
202+
senderAddress?: string;
198203
}
199204
export interface IntentRecipient {
200205
address: {
@@ -233,6 +238,11 @@ export interface PopulatedIntent extends PopulatedIntentBase {
233238
token?: string;
234239
enableTokens?: TokenEnablement[];
235240
unspents?: string[];
241+
/**
242+
* The receive address from which funds will be withdrawn.
243+
* This feature is supported only for specific coins, like ADA.
244+
*/
245+
senderAddress?: string;
236246
// ETH & ETH-like params
237247
selfSend?: boolean;
238248
feeOptions?: FeeOption | EIP1559FeeOptions;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ export interface PrebuildTransactionOptions {
106106
gasPrice?: number;
107107
noSplitChange?: boolean;
108108
unspents?: any[];
109+
/**
110+
* The receive address from which funds will be withdrawn.
111+
* This feature is supported only for specific coins, like ADA.
112+
*/
113+
senderAddress?: string;
109114
changeAddress?: string;
110115
allowExternalChangeAddress?: boolean;
111116
type?: string;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,6 +3135,7 @@ export class Wallet implements IWallet {
31353135
feeOptions,
31363136
custodianTransactionId: params.custodianTransactionId,
31373137
unspents: params.unspents,
3138+
senderAddress: params.senderAddress,
31383139
},
31393140
apiVersion,
31403141
params.preview

0 commit comments

Comments
 (0)