Skip to content

Commit ac915a5

Browse files
committed
chore: build and sign message sample script
TICKET: COIN-4593
1 parent 2fadd8c commit ac915a5

File tree

7 files changed

+144
-55
lines changed

7 files changed

+144
-55
lines changed

examples/ts/build-message.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Pre-build a message from the wallet
3+
*
4+
* This tool will help you see how to use the BitGo API to easily build
5+
* a message from a wallet.
6+
*
7+
* Copyright 2025, BitGo, Inc. All Rights Reserved.
8+
*/
9+
10+
import {BitGoAPI} from '@bitgo/sdk-api';
11+
import {Hteth} from "@bitgo/sdk-coin-eth";
12+
import {MessageStandardType} from "@bitgo/sdk-core"; // Replace with your given coin (e.g. Ltc, Tltc)
13+
require('dotenv').config({ path: '../../.env' });
14+
15+
const bitgo = new BitGoAPI({
16+
accessToken: process.env.TESTNET_ACCESS_TOKEN,
17+
env: 'test', // Change this to env: 'production' when you are ready for production
18+
});
19+
20+
// Set the coin name to match the blockchain and network
21+
// doge = dogecoin, tdoge = testnet dogecoin
22+
const coin = 'hteth';
23+
bitgo.register(coin, Hteth.createInstance);
24+
25+
const id = '';
26+
27+
async function main() {
28+
const wallet = await bitgo.coin(coin).wallets().get({ id });
29+
console.log(`Wallet label: ${wallet.label()}`);
30+
31+
const txRequest = await wallet.buildSignMessageRequest({
32+
message: {
33+
messageRaw: 'Hello, BitGo!',
34+
messageStandardType: MessageStandardType.EIP191,
35+
},
36+
});
37+
console.dir(txRequest);
38+
}
39+
40+
main().catch((e) => console.log(e));

examples/ts/sign-message.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Sign a Message from an MPC wallet at BitGo.
3+
*
4+
* Copyright 2025, BitGo, Inc. All Rights Reserved.
5+
*/
6+
import { BitGo } from 'bitgo';
7+
import { MessageStandardType } from '@bitgo/sdk-core';
8+
9+
const bitgo = new BitGo({ env: 'test' });
10+
11+
const coin = 'hteth';
12+
const basecoin = bitgo.coin(coin);
13+
const accessToken = '';
14+
const walletId = '';
15+
const walletPassphrase = '';
16+
17+
async function signMessage(): Promise<void> {
18+
await bitgo.authenticateWithAccessToken({ accessToken });
19+
const walletInstance = await basecoin.wallets().get({ id: walletId });
20+
21+
const messageTxn = await walletInstance.signMessage({
22+
message: {
23+
messageRaw: 'Hello BitGo!',
24+
messageStandardType: MessageStandardType.EIP191,
25+
},
26+
walletPassphrase,
27+
});
28+
29+
console.log(messageTxn);
30+
}
31+
32+
signMessage().catch(console.error);

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
Keychains,
2020
KeyType,
2121
ManageUnspentsOptions,
22+
MessageStandardType,
2223
MessageTypes,
2324
PopulatedIntent,
2425
PrebuildTransactionWithIntentOptions,
@@ -3480,8 +3481,11 @@ describe('V2 Wallet:', function () {
34803481

34813482
it('sol create signMessage tx request', async function () {
34823483
await tssSolWallet
3483-
.createSignMessageRequest({
3484-
messageRaw,
3484+
.buildSignMessageRequest({
3485+
message: {
3486+
messageRaw,
3487+
messageStandardType: MessageStandardType.EIP191,
3488+
},
34853489
})
34863490
.should.be.rejectedWith('Message signing not supported for Testnet Solana');
34873491
});
@@ -3496,13 +3500,16 @@ describe('V2 Wallet:', function () {
34963500
it('should create tx Request with signMessage intent', async function () {
34973501
nock(bgUrl).post(`/api/v2/wallet/${tssEthWallet.id()}/msgrequests`).reply(200, txRequestForMessageSigning);
34983502

3499-
const txRequest = await tssEthWallet.createSignMessageRequest({
3500-
messageRaw,
3503+
const txRequest = await tssEthWallet.buildSignMessageRequest({
3504+
message: {
3505+
messageRaw,
3506+
messageStandardType: MessageStandardType.EIP191,
3507+
},
35013508
});
35023509
txRequest.should.deepEqual(txRequestForMessageSigning);
35033510
});
35043511

3505-
it('should sign message', async function () {
3512+
it(`[${coinName}] should sign message`, async function () {
35063513
const signMessageTssSpy = sinon.spy(tssEthWallet, 'signMessageTss' as any);
35073514
nock(bgUrl)
35083515
.get(
@@ -3514,7 +3521,7 @@ describe('V2 Wallet:', function () {
35143521

35153522
const signMessage = await tssEthWallet.signMessage({
35163523
reqId,
3517-
message: { messageRaw, txRequestId },
3524+
message: { messageRaw, txRequestId, messageStandardType: MessageStandardType.EIP191 },
35183525
prv: 'secretKey',
35193526
});
35203527
signMessage.should.deepEqual(expectedWithCoinField);
@@ -3524,7 +3531,7 @@ describe('V2 Wallet:', function () {
35243531
);
35253532
});
35263533

3527-
it('should sign message when custodianMessageId is provided', async function () {
3534+
it(`[${coinName}] should sign message when custodianMessageId is provided`, async function () {
35283535
const signMessageTssSpy = sinon.spy(tssEthWallet, 'signMessageTss' as any);
35293536
nock(bgUrl).post(`/api/v2/wallet/${tssEthWallet.id()}/txrequests`).reply(200, txRequestForMessageSigning);
35303537

@@ -3541,7 +3548,7 @@ describe('V2 Wallet:', function () {
35413548
);
35423549
});
35433550

3544-
it('should sign message when txRequestId not provided', async function () {
3551+
it(`[${coinName}] should sign message when txRequestId not provided`, async function () {
35453552
const signMessageTssSpy = sinon.spy(tssEthWallet, 'signMessageTss' as any);
35463553
nock(bgUrl).post(`/api/v2/wallet/${tssEthWallet.id()}/txrequests`).reply(200, txRequestForMessageSigning);
35473554

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { IWebhooks } from '../webhook/iWebhooks';
1414
import { TransactionType } from '../../account-lib';
1515
import { IInscriptionBuilder } from '../inscriptionBuilder';
1616
import { Hash } from 'crypto';
17-
import { MPCTx, PopulatedIntent, TokenType } from '../utils';
17+
import { MessageStandardType, MPCTx, PopulatedIntent, TokenType } from '../utils';
1818

1919
export const multisigTypes = {
2020
onchain: 'onchain',
@@ -301,6 +301,7 @@ export interface TransactionPrebuild extends BaseSignable {
301301
export interface Message extends BaseSignable {
302302
messageRaw: string;
303303
messageEncoded?: string;
304+
messageStandardType?: MessageStandardType;
304305
}
305306

306307
export interface MessageTypeProperty {
@@ -418,6 +419,7 @@ export interface SignedMessage {
418419
signature: string;
419420
messageRaw: string;
420421
messageEncoded?: string;
422+
messageStandardType?: MessageStandardType;
421423
txRequestId: string;
422424
}
423425

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

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { IRequestTracer } from '../../../api';
2+
import * as openpgp from 'openpgp';
23
import { Key, readKey, SerializedKeyPair } from 'openpgp';
34
import { IBaseCoin, KeychainsTriplet } from '../../baseCoin';
45
import { BitGoBase } from '../../bitgoBase';
@@ -10,40 +11,40 @@ import * as _ from 'lodash';
1011
import {
1112
BitgoGPGPublicKey,
1213
BitgoHeldBackupKeyShare,
14+
CommitmentShareRecord,
15+
CreateBitGoKeychainParamsBase,
16+
CreateKeychainParamsBase,
17+
CustomCommitmentGeneratingFunction,
1318
CustomGShareGeneratingFunction,
19+
CustomKShareGeneratingFunction,
20+
CustomMPCv2SigningRound1GeneratingFunction,
21+
CustomMPCv2SigningRound2GeneratingFunction,
22+
CustomMPCv2SigningRound3GeneratingFunction,
23+
CustomMuDeltaShareGeneratingFunction,
24+
CustomPaillierModulusGetterFunction,
1425
CustomRShareGeneratingFunction,
26+
CustomSShareGeneratingFunction,
27+
EncryptedSignerShareRecord,
28+
IntentOptionsForMessage,
29+
IntentOptionsForTypedData,
1530
ITssUtils,
31+
PopulatedIntentForMessageSigning,
32+
PopulatedIntentForTypedDataSigning,
1633
PrebuildTransactionWithIntentOptions,
34+
RequestType,
1735
SignatureShareRecord,
1836
TSSParams,
19-
TxRequest,
20-
TxRequestVersion,
21-
CreateKeychainParamsBase,
22-
IntentOptionsForMessage,
23-
PopulatedIntentForMessageSigning,
24-
IntentOptionsForTypedData,
25-
PopulatedIntentForTypedDataSigning,
26-
CreateBitGoKeychainParamsBase,
27-
CommitmentShareRecord,
28-
EncryptedSignerShareRecord,
29-
CustomCommitmentGeneratingFunction,
3037
TSSParamsForMessage,
31-
RequestType,
32-
CustomPaillierModulusGetterFunction,
33-
CustomKShareGeneratingFunction,
34-
CustomMuDeltaShareGeneratingFunction,
35-
CustomSShareGeneratingFunction,
36-
CustomMPCv2SigningRound1GeneratingFunction,
37-
CustomMPCv2SigningRound2GeneratingFunction,
38-
CustomMPCv2SigningRound3GeneratingFunction,
3938
TSSParamsWithPrv,
39+
TxRequest,
40+
TxRequestVersion,
4041
} from './baseTypes';
4142
import { GShare, SignShare } from '../../../account-lib/mpc/tss';
4243
import { RequestTracer } from '../util';
43-
import * as openpgp from 'openpgp';
4444
import { envRequiresBitgoPubGpgKeyConfig, getBitgoMpcGpgPubKey } from '../../tss/bitgoPubKeys';
4545
import { getBitgoGpgPubKey } from '../opengpgUtils';
4646
import assert from 'assert';
47+
import { MessageStandardType } from '../messageTypes';
4748

4849
/**
4950
* BaseTssUtil class which different signature schemes have to extend
@@ -356,6 +357,7 @@ export default class BaseTssUtils<KeyShare> extends MpcUtils implements ITssUtil
356357

357358
/**
358359
* Create a tx request from params for message signing
360+
* @deprecated Use createSignMessageRequest instead
359361
*
360362
* @param params
361363
* @param apiVersion
@@ -386,7 +388,7 @@ export default class BaseTssUtils<KeyShare> extends MpcUtils implements ITssUtil
386388
* @param params - the parameters for the sign message request
387389
* @param apiVersion - the API version to use, defaults to 'full'
388390
*/
389-
async createSignMessageRequest(
391+
async buildSignMessageRequest(
390392
params: IntentOptionsForMessage,
391393
apiVersion: TxRequestVersion = 'full'
392394
): Promise<TxRequest> {
@@ -402,11 +404,11 @@ export default class BaseTssUtils<KeyShare> extends MpcUtils implements ITssUtil
402404
memo: params.memo?.value,
403405
isTss: params.isTss,
404406
messageRaw: params.messageRaw,
405-
messageStandardType: params.messageStandardType,
407+
messageStandardType: params.messageStandardType ?? MessageStandardType.UNKNOWN,
406408
messageEncoded: params.messageEncoded ?? '',
407409
};
408410

409-
return this.createSignMessageRequestBase(intent, apiVersion, params.reqId);
411+
return this.buildSignMessageRequestBase(intent, apiVersion, params.reqId);
410412
}
411413

412414
/**
@@ -467,7 +469,7 @@ export default class BaseTssUtils<KeyShare> extends MpcUtils implements ITssUtil
467469
*
468470
* @private
469471
*/
470-
private async createSignMessageRequestBase(
472+
private async buildSignMessageRequestBase(
471473
intent: PopulatedIntentForMessageSigning,
472474
apiVersion: TxRequestVersion,
473475
reqId?: IRequestTracer

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
CustomSShareGeneratingFunction,
2828
TokenEnablement,
2929
TokenTransferRecipientParams,
30+
TxRequest,
3031
} from '../utils';
3132
import { SerializedNtilde } from '../../account-lib/mpc/tss/ecdsa/types';
3233
import { IAddressBook } from '../address-book';
@@ -909,6 +910,7 @@ export interface IWallet {
909910
sendTokenEnablement(params?: PrebuildAndSignTransactionOptions): Promise<any>;
910911
sendTokenEnablements(params?: BuildTokenEnablementOptions): Promise<any>;
911912
signMessage(params: WalletSignMessageOptions): Promise<SignedMessage>;
913+
buildSignMessageRequest(params: WalletSignMessageOptions): Promise<TxRequest>;
912914
signTypedData(params: WalletSignTypedDataOptions): Promise<SignedMessage>;
913915
fetchCrossChainUTXOs(params: FetchCrossChainUTXOsOptions): Promise<CrossChainUTXO[]>;
914916
getChallengesForEcdsaSigning(): Promise<WalletEcdsaChallenges>;

0 commit comments

Comments
 (0)