Skip to content

Commit 9516bb8

Browse files
authored
Merge pull request #9216 from BitGo/WCN-539/withdrawal-flow-attestation-UI
feat(sdk-core): pass optional attestation through multisig send/initiate
2 parents 363af06 + dfc575d commit 9516bb8

7 files changed

Lines changed: 76 additions & 1 deletion

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ type PreApproveResult = {
3131
halfSigned?: string;
3232
};
3333

34+
// TODO(WCN-541): add optional attestation pass-through for PUT /pendingapprovals/:id (deferred
35+
// until multisig attestation, WCN-539, is verified end-to-end on staging).
3436
type ApprovePendingApprovalRequestBody = {
3537
state: 'approved';
3638
otp: string | undefined;

modules/sdk-core/src/bitgo/tss/common.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ export async function sendSignatureShare(
111111
const urlPath = '/wallet/' + walletId + '/txrequests/' + txRequestId + addendum + '/signatureshares';
112112
const reqTracer = reqId || new RequestTracer();
113113
bitgo.setRequestTracer(reqTracer);
114+
// TODO(WCN-541): add optional attestation pass-through for MPC /signatureshares, first round
115+
// only (deferred until multisig attestation, WCN-539, is verified end-to-end on staging).
114116
return bitgo
115117
.post(bitgo.url(urlPath, 2))
116118
.send({

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@ export default class BaseTssUtils<KeyShare> extends MpcUtils implements ITssUtil
514514
preview?: boolean,
515515
reqId?: IRequestTracer
516516
): Promise<TxRequest> {
517+
// TODO(WCN-541): add optional attestation pass-through for MPC /txrequests (deferred until
518+
// multisig attestation, WCN-539, is verified end-to-end on staging).
517519
const whitelistedParams = {
518520
intent: {
519521
...intentOptions,

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,27 @@ export const BuildParamsOffchain = t.partial({
6464
idfUserId: t.unknown,
6565
});
6666

67+
/**
68+
* WebAuthn attestation proving a passkey user signed off on this withdrawal intent.
69+
* Pure pass-through — the SDK does not validate or interpret this payload.
70+
*
71+
* @bitgo/public-types' TxSendBody now declares this field natively (WCN-539), so /tx/send and
72+
* /tx/initiate no longer need a local copy. This one remains for BuildParams (custodial
73+
* /tx/build), which has no upstream equivalent yet.
74+
*
75+
* TODO(WCN-541): add attestation pass-through for MPC (/txrequests, /signatureshares) and
76+
* /pendingapprovals — see the TODO(WCN-541) markers in baseTSSUtils.ts, common.ts, and
77+
* pendingApproval.ts.
78+
*/
79+
export const AttestationPayload = t.type({
80+
signature: t.string,
81+
credentialId: t.string,
82+
clientDataJSON: t.string,
83+
authenticatorData: t.string,
84+
});
85+
86+
export type AttestationPayload = t.TypeOf<typeof AttestationPayload>;
87+
6788
export const BuildParams = t.exact(
6889
t.intersection([
6990
BuildParamsUTXO,
@@ -140,6 +161,8 @@ export const BuildParams = t.exact(
140161
// Bridging parameters for cross-chain operations (e.g., BTC to sBTC)
141162
bridgingParams: t.unknown,
142163
defiParams: t.unknown,
164+
// WebAuthn attestation for the withdrawal intent (WCN-539) — pass-through only.
165+
attestation: AttestationPayload,
143166
}),
144167
])
145168
);

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
TxRequest,
3939
} from '../utils';
4040
import { SerializedNtilde } from '../../account-lib/mpc/tss/ecdsa/types';
41+
import { AttestationPayload } from './BuildParams';
4142
import { IAddressBook } from '../address-book';
4243
import { WalletUser, AddressQueryResult } from '@bitgo/public-types';
4344
import { SubmitTransactionResponse } from '../inscriptionBuilder';
@@ -203,6 +204,8 @@ export interface PrebuildTransactionOptions {
203204
idfUserId?: string;
204205
idfVersion?: number;
205206
comment?: string;
207+
/** WebAuthn attestation for the withdrawal intent (WCN-539) — pass-through only. */
208+
attestation?: AttestationPayload;
206209
[index: string]: unknown;
207210
tokenName?: string;
208211
nftCollectionId?: string;
@@ -883,6 +886,8 @@ export interface SubmitTransactionOptions {
883886
};
884887
comment?: string;
885888
txRequestId?: string;
889+
/** WebAuthn attestation for the withdrawal intent (WCN-539) — pass-through only. */
890+
attestation?: AttestationPayload;
886891
}
887892

888893
export interface SendOptions {

modules/sdk-core/test/unit/bitgo/wallet/BuildParams.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as assert from 'assert';
2-
import { BuildParams } from '../../../../src/bitgo/wallet/BuildParams';
2+
import { BuildParams, buildParamKeys, AttestationPayload } from '../../../../src/bitgo/wallet/BuildParams';
33

44
describe('BuildParams', function () {
55
it('enforces codec', function () {
@@ -74,4 +74,36 @@ describe('BuildParams', function () {
7474
}
7575
);
7676
});
77+
78+
it('should whitelist attestation (WCN-539) while stripping unrelated unknown params', function () {
79+
const attestation = {
80+
signature: 'sig',
81+
credentialId: 'cred-id',
82+
clientDataJSON: 'client-data',
83+
authenticatorData: 'auth-data',
84+
};
85+
assert.deepStrictEqual(
86+
BuildParams.encode({
87+
recipients: [{ amount: '10000', address: '2N9Ego9KidiZR8tMP82g6RaggQtcbR9zNzH' }],
88+
attestation,
89+
unknownField: 'should be stripped',
90+
} as any),
91+
{
92+
recipients: [{ amount: '10000', address: '2N9Ego9KidiZR8tMP82g6RaggQtcbR9zNzH' }],
93+
attestation,
94+
}
95+
);
96+
assert.ok(buildParamKeys.includes('attestation'), 'buildParamKeys must include attestation');
97+
});
98+
99+
it('AttestationPayload codec requires all four fields', function () {
100+
const valid = {
101+
signature: 'sig',
102+
credentialId: 'cred-id',
103+
clientDataJSON: 'client-data',
104+
authenticatorData: 'auth-data',
105+
};
106+
assert.strictEqual(AttestationPayload.is(valid), true);
107+
assert.strictEqual(AttestationPayload.is({ ...valid, signature: undefined }), false);
108+
});
77109
});

modules/sdk-core/test/unit/bitgo/wallet/SendTransactionRequest.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,13 @@ describe('SendTransactionRequest', function () {
2424
addressType: 'p2sh',
2525
});
2626
});
27+
28+
it('preserves attestation (WCN-539: @bitgo/public-types TxSendBody declares it natively)', function () {
29+
const attestation = { signature: 'sig', credentialId: 'c', clientDataJSON: 'cd', authenticatorData: 'ad' };
30+
31+
assert.deepStrictEqual(TxSendBody.encode({ txHex: '00', attestation } as any), {
32+
txHex: '00',
33+
attestation,
34+
});
35+
});
2736
});

0 commit comments

Comments
 (0)