Skip to content

Commit 2f31fb4

Browse files
feat(sdk-coin-flrp): add createPairedWallet method to Flrp
Add CreatePairedWalletParams and CreatePairedWalletResponse interfaces to iface.ts. Add createPairedWallet() method to the Flrp class that POSTs to /api/v2/flrp/wallet/:walletId/create-paired-wallet. Add unit tests covering label/no-label and error cases. Closes #8578
1 parent eb28af8 commit 2f31fb4

3 files changed

Lines changed: 113 additions & 1 deletion

File tree

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
} from '@bitgo/sdk-core';
2323
import * as FlrpLib from './lib';
2424
import {
25+
CreatePairedWalletParams,
26+
CreatePairedWalletResponse,
2527
FlrpEntry,
2628
FlrpExplainTransactionOptions,
2729
FlrpSignTransactionOptions,
@@ -436,4 +438,12 @@ export class Flrp extends BaseCoin {
436438
auditDecryptedKey(params: AuditDecryptedKeyParams): void {
437439
throw new MethodNotImplementedError();
438440
}
441+
442+
async createPairedWallet(params: CreatePairedWalletParams): Promise<CreatePairedWalletResponse> {
443+
const { walletId, label } = params;
444+
return this.bitgo
445+
.post(this.url(`/wallet/${walletId}/create-paired-wallet`))
446+
.send(label ? { label } : {})
447+
.result();
448+
}
439449
}

modules/sdk-coin-flrp/src/lib/iface.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,34 @@ export interface ExportEVMOptions {
176176
threshold: number;
177177
locktime: bigint;
178178
}
179+
180+
/**
181+
* Parameters for creating a paired FLR C-chain wallet from an FLR P-chain wallet.
182+
*/
183+
export interface CreatePairedWalletParams {
184+
/** The ID of the source FLRP (FLR P-chain) MPC wallet. */
185+
walletId: string;
186+
/** Optional label for the new FLR C-chain wallet. */
187+
label?: string;
188+
}
189+
190+
/**
191+
* Response from the create-paired-wallet endpoint.
192+
*/
193+
export interface CreatePairedWalletResponse {
194+
id: string;
195+
coin: string;
196+
label: string;
197+
keys: string[];
198+
keySignatures: Record<string, string>;
199+
m: number;
200+
n: number;
201+
type: string;
202+
multisigType: string;
203+
coinSpecific: {
204+
pairedWalletId?: string;
205+
baseAddress?: string;
206+
[key: string]: unknown;
207+
};
208+
[key: string]: unknown;
209+
}

modules/sdk-coin-flrp/test/unit/flrp.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import { EXPORT_IN_C } from '../resources/transactionData/exportInC';
99
import { EXPORT_IN_P } from '../resources/transactionData/exportInP';
1010
import { IMPORT_IN_P } from '../resources/transactionData/importInP';
1111
import { IMPORT_IN_C } from '../resources/transactionData/importInC';
12-
import { HalfSignedAccountTransaction, TransactionType, MPCAlgorithm } from '@bitgo/sdk-core';
12+
import { HalfSignedAccountTransaction, TransactionType, MPCAlgorithm, common } from '@bitgo/sdk-core';
1313
import { secp256k1 } from '@flarenetwork/flarejs';
1414
import { FlrpContext } from '@bitgo/public-types';
1515
import assert from 'assert';
16+
import nock from 'nock';
17+
import { CreatePairedWalletResponse } from '../../src/lib/iface';
1618

1719
describe('Flrp test cases', function () {
1820
const coinName = 'flrp';
@@ -960,4 +962,73 @@ describe('Flrp test cases', function () {
960962
});
961963
});
962964
});
965+
966+
describe('createPairedWallet', function () {
967+
const walletId = 'abc123def456abc123def456abc123de';
968+
969+
afterEach(function () {
970+
nock.cleanAll();
971+
});
972+
973+
it('should POST to create-paired-wallet and return new wallet', async function () {
974+
const bgUrl = common.Environments[bitgo.getEnv()].uri;
975+
const expectedResponse: CreatePairedWalletResponse = {
976+
id: 'newwalletid000000000000000000001',
977+
coin: 'tflr',
978+
label: 'My FLR C Wallet',
979+
keys: ['key1', 'key2', 'key3'],
980+
keySignatures: { backupPub: 'sig1', bitgoPub: 'sig2' },
981+
m: 2,
982+
n: 3,
983+
type: 'hot',
984+
multisigType: 'tss',
985+
coinSpecific: {
986+
pairedWalletId: walletId,
987+
baseAddress: '0x627306090abaB3A6e1400e9345bC60c78a8BEf57',
988+
},
989+
};
990+
991+
nock(bgUrl)
992+
.post(`/api/v2/tflrp/wallet/${walletId}/create-paired-wallet`, { label: 'My FLR C Wallet' })
993+
.reply(200, expectedResponse);
994+
995+
const result = await basecoin.createPairedWallet({ walletId, label: 'My FLR C Wallet' });
996+
result.should.deepEqual(expectedResponse);
997+
result.coin.should.equal('tflr');
998+
result.coinSpecific.pairedWalletId.should.equal(walletId);
999+
});
1000+
1001+
it('should POST without body when label is not provided', async function () {
1002+
const bgUrl = common.Environments[bitgo.getEnv()].uri;
1003+
const expectedResponse: CreatePairedWalletResponse = {
1004+
id: 'newwalletid000000000000000000002',
1005+
coin: 'tflr',
1006+
label: 'FLR C wallet (from tflrp wallet abc123def456abc123def456abc123de)',
1007+
keys: ['key1', 'key2', 'key3'],
1008+
keySignatures: {},
1009+
m: 2,
1010+
n: 3,
1011+
type: 'hot',
1012+
multisigType: 'tss',
1013+
coinSpecific: { pairedWalletId: walletId },
1014+
};
1015+
1016+
nock(bgUrl).post(`/api/v2/tflrp/wallet/${walletId}/create-paired-wallet`, {}).reply(200, expectedResponse);
1017+
1018+
const result = await basecoin.createPairedWallet({ walletId });
1019+
result.should.deepEqual(expectedResponse);
1020+
});
1021+
1022+
it('should propagate HTTP errors from the server', async function () {
1023+
const bgUrl = common.Environments[bitgo.getEnv()].uri;
1024+
1025+
nock(bgUrl)
1026+
.post(`/api/v2/tflrp/wallet/${walletId}/create-paired-wallet`)
1027+
.reply(400, { error: 'Source FLR P wallet is not MPC (multisigType: onchain)' });
1028+
1029+
await basecoin
1030+
.createPairedWallet({ walletId })
1031+
.should.be.rejectedWith('Source FLR P wallet is not MPC (multisigType: onchain)');
1032+
});
1033+
});
9631034
});

0 commit comments

Comments
 (0)