Skip to content

Commit 9bce8b9

Browse files
committed
feat(sdk-core): create message sign request
TICKET: COIN-4593
1 parent 114557f commit 9bce8b9

File tree

4 files changed

+154
-23
lines changed

4 files changed

+154
-23
lines changed

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

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,34 @@ import * as nock from 'nock';
99
import * as _ from 'lodash';
1010

1111
import {
12+
BaseTssUtils,
1213
common,
1314
CustomSigningFunction,
15+
Ecdsa,
1416
ECDSAUtils,
1517
EDDSAUtils,
18+
GetUserPrvOptions,
19+
Keychains,
20+
KeyType,
21+
ManageUnspentsOptions,
22+
MessageType,
23+
MessageTypes,
24+
PopulatedIntent,
25+
PrebuildTransactionWithIntentOptions,
1626
RequestTracer,
27+
SendManyOptions,
28+
SignatureShareType,
29+
SignedMessage,
30+
SignTypedDataVersion,
1731
TokenType,
1832
TssUtils,
1933
TxRequest,
20-
Wallet,
21-
SignatureShareType,
22-
Ecdsa,
23-
Keychains,
34+
TxRequestVersion,
2435
TypedData,
2536
TypedMessage,
26-
MessageTypes,
27-
SignTypedDataVersion,
28-
GetUserPrvOptions,
29-
ManageUnspentsOptions,
30-
SignedMessage,
31-
BaseTssUtils,
32-
KeyType,
33-
SendManyOptions,
34-
PopulatedIntent,
35-
TxRequestVersion,
37+
Wallet,
3638
WalletSignMessageOptions,
3739
WalletSignTypedDataOptions,
38-
PrebuildTransactionWithIntentOptions,
3940
} from '@bitgo/sdk-core';
4041

4142
import { TestBitGo } from '@bitgo/sdk-test';
@@ -3467,14 +3468,25 @@ describe('V2 Wallet:', function () {
34673468
nock.cleanAll();
34683469
});
34693470

3470-
it('should throw error for unsupported coins', async function () {
3471-
await tssSolWallet
3472-
.signMessage({
3473-
reqId,
3474-
message: { messageRaw },
3475-
prv: 'secretKey',
3476-
})
3477-
.should.be.rejectedWith('Message signing not supported for Testnet Solana');
3471+
describe('should throw error for unsupported coins', function () {
3472+
it('sol signMessage', async function () {
3473+
await tssSolWallet
3474+
.signMessage({
3475+
reqId,
3476+
message: { messageRaw },
3477+
prv: 'secretKey',
3478+
})
3479+
.should.be.rejectedWith('Message signing not supported for Testnet Solana');
3480+
});
3481+
3482+
it('sol create signMessage tx request', async function () {
3483+
await tssSolWallet
3484+
.createSignMessageRequest({
3485+
messageRaw,
3486+
messageType: MessageType.STRING,
3487+
})
3488+
.should.be.rejectedWith('Message signing not supported for Testnet Solana');
3489+
});
34783490
});
34793491

34803492
messageSigningCoins.map((coinName) => {
@@ -3483,6 +3495,16 @@ describe('V2 Wallet:', function () {
34833495
tssEthWallet = new Wallet(bitgo, bitgo.coin(coinName), ethWalletData);
34843496
const txRequestId = txRequestForMessageSigning.txRequestId;
34853497

3498+
it('should create tx Request with signMessage intent', async function () {
3499+
nock(bgUrl).post(`/api/v2/wallet/${tssEthWallet.id()}/msgrequests`).reply(200, txRequestForMessageSigning);
3500+
3501+
const txRequest = await tssEthWallet.createSignMessageRequest({
3502+
messageRaw,
3503+
messageType: MessageType.STRING,
3504+
});
3505+
txRequest.should.deepEqual(txRequestForMessageSigning);
3506+
});
3507+
34863508
it('should sign message', async function () {
34873509
const signMessageTssSpy = sinon.spy(tssEthWallet, 'signMessageTss' as any);
34883510
nock(bgUrl)

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { RequestTracer } from '../util';
4343
import * as openpgp from 'openpgp';
4444
import { envRequiresBitgoPubGpgKeyConfig, getBitgoMpcGpgPubKey } from '../../tss/bitgoPubKeys';
4545
import { getBitgoGpgPubKey } from '../opengpgUtils';
46+
import assert from 'assert';
4647

4748
/**
4849
* BaseTssUtil class which different signature schemes have to extend
@@ -379,6 +380,35 @@ export default class BaseTssUtils<KeyShare> extends MpcUtils implements ITssUtil
379380
return this.createTxRequestBase(intentOptions, apiVersion, preview, params.reqId);
380381
}
381382

383+
/**
384+
* Create a sign message request
385+
*
386+
* @param params - the parameters for the sign message request
387+
* @param apiVersion - the API version to use, defaults to 'full'
388+
*/
389+
async createSignMessageRequest(
390+
params: IntentOptionsForMessage,
391+
apiVersion: TxRequestVersion = 'full'
392+
): Promise<TxRequest> {
393+
assert(
394+
params.intentType === 'signMessage',
395+
'Intent type must be signMessage for createMsgRequestWithSignMessageIntent'
396+
);
397+
const intent: PopulatedIntentForMessageSigning = {
398+
custodianMessageId: params.custodianMessageId,
399+
intentType: params.intentType,
400+
sequenceId: params.sequenceId,
401+
comment: params.comment,
402+
memo: params.memo?.value,
403+
isTss: params.isTss,
404+
messageRaw: params.messageRaw,
405+
messageType: params.messageType,
406+
messageEncoded: params.messageEncoded ?? '',
407+
};
408+
409+
return this.createSignMessageRequestBase(intent, apiVersion, params.reqId);
410+
}
411+
382412
/**
383413
* Create a tx request from params for type data signing
384414
*
@@ -432,6 +462,31 @@ export default class BaseTssUtils<KeyShare> extends MpcUtils implements ITssUtil
432462
.result();
433463
}
434464

465+
/**
466+
* Calls Bitgo API to create msg request.
467+
*
468+
* @private
469+
*/
470+
private async createSignMessageRequestBase(
471+
intent: PopulatedIntentForMessageSigning,
472+
apiVersion: TxRequestVersion,
473+
reqId?: IRequestTracer
474+
): Promise<TxRequest> {
475+
const whitelistedParams = {
476+
intent: {
477+
...intent,
478+
},
479+
apiVersion,
480+
};
481+
482+
const reqTracer = reqId || new RequestTracer();
483+
this.bitgo.setRequestTracer(reqTracer);
484+
return this.bitgo
485+
.post(this.bitgo.url(`/wallet/${this.wallet.id()}/msgrequests`, 2))
486+
.send(whitelistedParams)
487+
.result();
488+
}
489+
435490
/**
436491
* Call delete signature shares for a txRequest, the endpoint delete the signatures and return them
437492
*

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ export enum MPCType {
5454
ECDSA = 'ecdsa',
5555
}
5656

57+
export enum MessageType {
58+
STRING = 'string',
59+
EIP712 = 'eip712',
60+
CIP8 = 'cip8',
61+
}
62+
5763
export interface CustomPaillierModulusGetterFunction {
5864
(params: { txRequest: TxRequest }): Promise<{
5965
userPaillierModulus: string;
@@ -172,6 +178,7 @@ interface IntentOptionsBase {
172178
export interface IntentOptionsForMessage extends IntentOptionsBase {
173179
messageRaw: string;
174180
messageEncoded?: string;
181+
messageType?: MessageType | string;
175182
}
176183

177184
export interface IntentOptionsForTypedData extends IntentOptionsBase {
@@ -226,6 +233,7 @@ export interface PopulatedIntentForMessageSigning extends PopulatedIntentBase {
226233
messageRaw: string;
227234
messageEncoded: string;
228235
custodianMessageId?: string;
236+
messageType?: MessageType | string;
229237
}
230238

231239
export interface PopulatedIntentForTypedDataSigning extends PopulatedIntentBase {

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
inferAddressType,
3535
IntentOptionsForMessage,
3636
IntentOptionsForTypedData,
37+
MessageType,
3738
RequestTracer,
3839
RequestType,
3940
TokenTransferRecipientParams,
@@ -2093,6 +2094,51 @@ export class Wallet implements IWallet {
20932094
return this.signMessageTss(presign);
20942095
}
20952096

2097+
/**
2098+
* Prepares and creates a sign message request for TSS wallets, that can be used later for signing.
2099+
*
2100+
* @param params - Parameters for creating the sign message request
2101+
* @returns Promise<TxRequest> - The created transaction request for signing a message
2102+
*/
2103+
async createSignMessageRequest(params: {
2104+
messageRaw: string;
2105+
messageType?: MessageType | string;
2106+
custodianMessageId?: string;
2107+
reqId?: RequestTracer;
2108+
}): Promise<TxRequest> {
2109+
if (this._wallet.multisigType !== 'tss') {
2110+
throw new Error('Message signing only supported for TSS wallets');
2111+
}
2112+
2113+
if (!this.baseCoin.supportsMessageSigning()) {
2114+
throw new Error(`Message signing not supported for ${this.baseCoin.getFullName()}`);
2115+
}
2116+
2117+
if (!params.messageRaw) {
2118+
throw new Error('message required to create message sign request');
2119+
}
2120+
2121+
const reqId = params.reqId || new RequestTracer();
2122+
2123+
try {
2124+
const intentOption: IntentOptionsForMessage = {
2125+
custodianMessageId: params.custodianMessageId,
2126+
reqId,
2127+
intentType: 'signMessage',
2128+
isTss: true,
2129+
messageRaw: params.messageRaw,
2130+
messageType: params.messageType,
2131+
};
2132+
2133+
if (!this.tssUtils) {
2134+
throw new Error('TSS utilities not available for this wallet');
2135+
}
2136+
return await this.tssUtils.createSignMessageRequest(intentOption);
2137+
} catch (error) {
2138+
throw new Error(`Failed to create message sign request: ${error}`);
2139+
}
2140+
}
2141+
20962142
/**
20972143
* Get the user private key from either a derivation or an encrypted keychain
20982144
* @param [params.keychain / params.key] (object) or params.prv (string)

0 commit comments

Comments
 (0)