Skip to content

feat: implement BitGo signing in SDK#8624

Merged
alextse-bg merged 4 commits intomasterfrom
WCN-217
Apr 28, 2026
Merged

feat: implement BitGo signing in SDK#8624
alextse-bg merged 4 commits intomasterfrom
WCN-217

Conversation

@alextse-bg
Copy link
Copy Markdown
Contributor

@alextse-bg alextse-bg commented Apr 23, 2026

Commit 1: allowing trading wallet transaction signing on Trading Account Objects

make wallet passphrase optional when signing OFC transactions.
if not present, the SDK attempts to sign using the wallet's BitGo key instead.

Commit 2: allowing trading wallet transaction signing on Wallet and Coins object

The following are all of the currently valid methods to create a signature on an OFC wallet's payload string

  1. ofcToken.signMessage({prv}, message): encrypts the message locally using prv
  2. ofcToken.signTransaction(params): signs a half signed transaction by calling the above method
  3. wallet.baseCoin.signMessage: see above
  4. wallet.baseCoin.signTransaction: see above
  5. wallet.signTransaction(params): signs a half signed transaction by getting the prv through a wallet passphrase then calling this.baseCoin.signTransaction
  6. wallet.prebuildAndSignTransaction(params): builds and sign a transaction by calling wallet.signTransaction
  7. all other wallet methods that calls wallet.prebuildAndSignTransaction (e.g. sendMany)
  8. wallet.toTradingAccount().signPayload: signs a half signed transaction using the wallet passphrase

Changes in commit 1 address path 8 already.

For paths that creates the signature using methods of wallet object (i.e. 5-7), all of them eventually calls wallet.signTransaction, which pass itself this as an argument to wallet.baseCoin.signTransaction (see here), allowing us to sign via BitGo key if we add the implementation to ofcToken

As for ofcToken.signMessage, add overloads to the method to allow SDK user to pass in the wallet object instead, which creates the signature via the BitGo key.

Note that the walletPassphrase is already an optional parameter when calling wallet level methods.

Ticket: WCN-217

@linear
Copy link
Copy Markdown

linear Bot commented Apr 23, 2026

@alextse-bg alextse-bg force-pushed the WCN-217 branch 2 times, most recently from 8fd8f9f to 3e4c1a5 Compare April 23, 2026 18:05
@alextse-bg alextse-bg marked this pull request as ready for review April 24, 2026 17:39
@alextse-bg alextse-bg requested review from a team as code owners April 24, 2026 17:39
Comment thread modules/sdk-core/src/bitgo/trading/iTradingAccount.ts
Comment thread modules/sdk-core/src/bitgo/trading/tradingAccount.ts
Comment thread modules/sdk-core/src/bitgo/trading/tradingAccount.ts Outdated
Comment thread modules/sdk-core/src/bitgo/trading/tradingAccount.ts Outdated
Comment thread modules/sdk-core/src/bitgo/trading/tradingAccount.ts
Comment thread modules/sdk-core/src/coins/ofc.ts Outdated
Comment thread modules/sdk-core/src/coins/ofc.ts Outdated
Comment thread modules/express/src/clientRoutes.ts
zahin-mohammad
zahin-mohammad previously approved these changes Apr 24, 2026
Copy link
Copy Markdown
Contributor

@zahin-mohammad zahin-mohammad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, just a few suggestions/comments.

allow wallet and coins object to sign using the BitGo key
if the passphrase is not provided during signing

Ticket: WCN-217-2
alextse-bg and others added 2 commits April 27, 2026 12:11
When no walletPassphrase is present in the request body or environment,
pass undefined to tradingAccount.signPayload() instead of throwing.
The SDK routes passphrase-less signing through KMS internally.

Ticket: WCN-215-1
@alextse-bg
Copy link
Copy Markdown
Contributor Author

Commit 3

Make wallet passphrase optional for preapreAllocation

Ticket: WCN-216

@kaustubhbitgo kaustubhbitgo removed their request for review April 28, 2026 05:07
@alextse-bg alextse-bg merged commit 1b2470e into master Apr 28, 2026
23 checks passed
Copy link
Copy Markdown
Contributor

@pranavjain97 pranavjain97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prv-as-walletPassphrase in ofcToken.signTransaction breaks the user-key signing path from wallet.signTransaction

let signature: string;
if (params.wallet) {
signature = await params.wallet.toTradingAccount().signPayload({ payload, walletPassphrase: params.prv });
} else if (params.prv) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

params.prv arriving here via wallet.signTransaction is already a decrypted key (from getUserPrv), not a passphrase. passing it as walletPassphrase to signPayload will cause signPayloadByUserKey to use it as a decryption password against encryptedPrv, which won't work

evmKeyRingReferenceWalletId?: string;
isParent?: boolean;
enabledChildChains?: string[];
userKeySigningRequired?: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userKeySigningRequired is typed string but the guard treats it as boolean. "false" from the API would incorrectly block BitGo signing. should be boolean

if (walletData.keys.length < 2) {
throw new Error(
'Wallet does not support BitGo signing. Please reach out to support@bitgo.com to resolve this issue.'
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when params.payload is a string, .send(string) sends a plain text body, not JSON. the user-key path stringifies first, this should match


async function getEncryptedPrivKey(path: string, walletId: string): Promise<string> {
const privKeyFile = await fs.readFile(path, { encoding: 'utf8' });
const encryptedPrivKey = JSON.parse(privKeyFile);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to zahin's thread: collapse findWalletPwFromEnv and getWalletPwFromEnv into one function

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update it in a follow up PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants