Skip to content

Commit 4599120

Browse files
feat(sdk-core): make GoStakeOptions.walletPassphrase optional
2 parents 8d99089 + d1b529a commit 4599120

2 files changed

Lines changed: 69 additions & 1 deletion

File tree

modules/bitgo/test/v2/unit/staking/goStakingWalletCommon.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,70 @@ describe('Go Staking Wallet Common', function () {
124124
msScope1.isDone().should.be.True();
125125
msScope2.isDone().should.be.True();
126126
});
127+
128+
it('should stake without a wallet passphrase for an OFC wallet that signs remotely (userKeySigningRequired === false)', async function () {
129+
// OFC wallet signs remotely via the BitGo key instead of decrypting the user key locally.
130+
const remoteWallet = new Wallet(bitgo, baseCoin, {
131+
id: 'remoteWalletId',
132+
coin: ofcCoin,
133+
enterprise: enterprise.id,
134+
keys: ['5b3424f91bf349930e340175', '5b3424f91bf349930e340174', '5b3424f91bf349930e340173'],
135+
coinSpecific: { userKeySigningRequired: false },
136+
});
137+
const remoteStakingWallet = remoteWallet.toGoStakingWallet();
138+
139+
// prebuildAndSignTransaction still fetches the user keychain (index 0), but with no passphrase
140+
// the decrypt check is skipped and the key is never used to sign.
141+
nock(microservicesUri).get(`/api/v2/${ofcCoin}/key/${remoteStakingWallet.wallet.keyIds()[0]}`).reply(200, {
142+
id: remoteStakingWallet.wallet.keyIds()[0],
143+
pub: 'xpub661MyMwAqRbcFq65dvGMeEVb81KKDRRkWkawSVesWcyevGc5gr8V27LjNfkktaMuKtM362jhgKy2eu35RdArcmmEAoULzAvgKkJpWQPvLXM',
144+
source: 'user',
145+
coinSpecific: {},
146+
});
147+
148+
const preview = fixtures.previewGoStakingRequest(coin);
149+
const msScope1 = nock(microservicesUri)
150+
.post(`/api/go-staking/v1/${ofcCoin}/accounts/${remoteStakingWallet.accountId}/requests/preview`, {
151+
amount: '1',
152+
clientId: 'clientId',
153+
type: 'STAKE',
154+
})
155+
.reply(201, preview);
156+
157+
// remote signing: the BitGo key signs the payload and returns the signature
158+
const signature =
159+
'1f4f7e789ef485363b33dca7273717a4a4413330f2badbcaf302758bc404ff8e930943db81aa2c77007738afa23166934c2a3136bae281bea037095be7183c0602';
160+
const signScope = nock(microservicesUri)
161+
.post(`/api/v2/ofc/wallet/${remoteWallet.id()}/tx/sign`, { payload: preview.payload })
162+
.reply(200, { signature });
163+
164+
const expected = fixtures.finalizeGoStakingRequest(coin, 'STAKE');
165+
const msScope2 = nock(microservicesUri)
166+
.post(`/api/go-staking/v1/${ofcCoin}/accounts/${remoteStakingWallet.accountId}/requests/finalize`, {
167+
amount: '1',
168+
clientId: 'clientId',
169+
frontTransferSendRequest: {
170+
halfSigned: {
171+
payload: preview.payload,
172+
signature,
173+
},
174+
},
175+
type: 'STAKE',
176+
})
177+
.reply(201, expected);
178+
179+
const stakingRequest = await remoteStakingWallet.stake({
180+
amount: '1',
181+
clientId: 'clientId',
182+
});
183+
184+
should.exist(stakingRequest);
185+
186+
stakingRequest.should.deepEqual(expected);
187+
msScope1.isDone().should.be.True();
188+
signScope.isDone().should.be.True();
189+
msScope2.isDone().should.be.True();
190+
});
127191
});
128192

129193
describe('unstake', function () {

modules/sdk-core/src/bitgo/staking/goStakingInterfaces.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ interface GoStakingRequestProperties {
3232
export interface GoStakeOptions {
3333
amount: string;
3434
clientId?: string;
35-
walletPassphrase: string;
35+
/**
36+
* Passphrase used to decrypt the user key and sign locally. Optional: omitted for OFC wallets that
37+
* sign remotely via the BitGo key (userKeySigningRequired === false).
38+
*/
39+
walletPassphrase?: string;
3640
}
3741

3842
export interface BaseGoStakeOptions {

0 commit comments

Comments
 (0)