From f22f27075d48008d1cf15ae2999da7ea3def2250 Mon Sep 17 00:00:00 2001 From: Bhuvan R Date: Mon, 9 Mar 2026 14:27:53 +0530 Subject: [PATCH] feat: add sdk changes for mpc tss support for TRON TICKET: CHALO-33 --- modules/sdk-coin-trx/package.json | 1 + modules/sdk-coin-trx/src/lib/transaction.ts | 18 ++++++++ .../src/lib/transactionBuilder.ts | 6 +++ .../sdk-coin-trx/src/lib/wrappedBuilder.ts | 7 ++- modules/sdk-coin-trx/src/trx.ts | 44 +++++++++++++++++-- modules/statics/src/coinFeatures.ts | 4 ++ .../unit/fixtures/expectedColdFeatures.ts | 4 +- 7 files changed, 78 insertions(+), 6 deletions(-) diff --git a/modules/sdk-coin-trx/package.json b/modules/sdk-coin-trx/package.json index fe11183427..fd5ceeb134 100644 --- a/modules/sdk-coin-trx/package.json +++ b/modules/sdk-coin-trx/package.json @@ -47,6 +47,7 @@ }, "dependencies": { "@bitgo/sdk-core": "^36.33.2", + "@bitgo/sdk-lib-mpc": "^10.9.0", "@bitgo/secp256k1": "^1.10.0", "@bitgo/statics": "^58.29.0", "@stablelib/hex": "^1.0.0", diff --git a/modules/sdk-coin-trx/src/lib/transaction.ts b/modules/sdk-coin-trx/src/lib/transaction.ts index 1d798c8be3..5d5824cdfa 100644 --- a/modules/sdk-coin-trx/src/lib/transaction.ts +++ b/modules/sdk-coin-trx/src/lib/transaction.ts @@ -318,6 +318,24 @@ export class Transaction extends BaseTransaction { return this._inputs; } + /** @inheritDoc */ + get signablePayload(): Buffer { + if (!this._transaction) { + throw new ParseTransactionError('Empty transaction'); + } + return Buffer.from(this._transaction.raw_data_hex, 'hex'); + } + + addSignature(signature: Buffer): void { + if (!this._transaction) { + throw new ParseTransactionError('Empty transaction'); + } + if (!this._transaction.signature) { + this._transaction.signature = []; + } + this._transaction.signature.push(signature.toString('hex')); + } + /** @inheritdoc */ canSign(key: BaseKey): boolean { // Tron transaction do not contain the owners account address so it is not possible to check the diff --git a/modules/sdk-coin-trx/src/lib/transactionBuilder.ts b/modules/sdk-coin-trx/src/lib/transactionBuilder.ts index 45734ef1ff..36f88fbcbd 100644 --- a/modules/sdk-coin-trx/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-trx/src/lib/transactionBuilder.ts @@ -8,6 +8,7 @@ import { BuildTransactionError, InvalidTransactionError, ParseTransactionError, + PublicKey as BasePublicKey, SigningError, ExtendTransactionError, InvalidParameterValueError, @@ -162,6 +163,11 @@ export class TransactionBuilder extends BaseTransactionBuilder { return new Transaction(this._coinConfig, signedTransaction); } + /** @inheritDoc */ + addSignature(publicKey: BasePublicKey, signature: Buffer): void { + this.transaction.addSignature(signature); + } + /** @inheritdoc */ protected async buildImplementation(): Promise { // This is a no-op since Tron transactions are built from diff --git a/modules/sdk-coin-trx/src/lib/wrappedBuilder.ts b/modules/sdk-coin-trx/src/lib/wrappedBuilder.ts index 7e62527288..f9594501fe 100644 --- a/modules/sdk-coin-trx/src/lib/wrappedBuilder.ts +++ b/modules/sdk-coin-trx/src/lib/wrappedBuilder.ts @@ -1,6 +1,6 @@ import BigNumber from 'bignumber.js'; import { BaseCoin as CoinConfig } from '@bitgo/statics'; -import { BaseKey, BaseTransaction, InvalidTransactionError } from '@bitgo/sdk-core'; +import { BaseKey, BaseTransaction, InvalidTransactionError, PublicKey as BasePublicKey } from '@bitgo/sdk-core'; import { Transaction } from './transaction'; import { Address } from './address'; import { TransactionBuilder } from './transactionBuilder'; @@ -137,6 +137,11 @@ export class WrappedBuilder extends TransactionBuilder { this._builder.sign(key); } + /** @inheritDoc */ + addSignature(publicKey: BasePublicKey, signature: Buffer): void { + this._builder.addSignature(publicKey, signature); + } + /** @inheritdoc */ async build(): Promise { return this._builder.build(); diff --git a/modules/sdk-coin-trx/src/trx.ts b/modules/sdk-coin-trx/src/trx.ts index a1eb4fb8be..dfc13007c8 100644 --- a/modules/sdk-coin-trx/src/trx.ts +++ b/modules/sdk-coin-trx/src/trx.ts @@ -2,7 +2,7 @@ * @prettier */ import * as secp256k1 from 'secp256k1'; -import { randomBytes } from 'crypto'; +import { createHash, Hash, randomBytes } from 'crypto'; import { CoinFamily, BaseCoin as StaticsBaseCoin } from '@bitgo/statics'; import { bip32 } from '@bitgo/secp256k1'; import * as request from 'superagent'; @@ -16,6 +16,7 @@ import { KeyPair, KeyIndices, MethodNotImplementedError, + MPCAlgorithm, ParsedTransaction, ParseTransactionOptions, SignedTransaction, @@ -31,7 +32,10 @@ import { multisigTypes, AuditDecryptedKeyParams, AddressCoinSpecific, + verifyMPCWalletAddress, + isTssVerifyAddressOptions, } from '@bitgo/sdk-core'; +import { auditEcdsaPrivateKey } from '@bitgo/sdk-lib-mpc'; import { Interface, Utils, WrappedBuilder, KeyPair as TronKeyPair } from './lib'; import { ValueFields, TransactionReceipt } from './lib/iface'; import { getBuilder } from './lib/builder'; @@ -189,6 +193,21 @@ export class Trx extends BaseCoin { return multisigTypes.onchain; } + /** @inheritDoc */ + supportsTss(): boolean { + return true; + } + + /** @inheritDoc */ + getMPCAlgorithm(): MPCAlgorithm { + return 'ecdsa'; + } + + /** @inheritDoc */ + getHashFunction(): Hash { + return createHash('sha256'); + } + static createInstance(bitgo: BitGoBase, staticsCoin?: Readonly): BaseCoin { return new Trx(bitgo, staticsCoin); } @@ -269,6 +288,14 @@ export class Trx extends BaseCoin { async isWalletAddress(params: VerifyAddressOptions): Promise { const { address, keychains } = params; + if (isTssVerifyAddressOptions(params)) { + return verifyMPCWalletAddress( + { ...params, keyCurve: 'secp256k1' }, + this.isValidAddress.bind(this), + (pubKey: string) => new TronKeyPair({ pub: pubKey }).getAddress() + ); + } + if (!isTrxVerifyAddressOptions(params)) { throw new Error('Invalid or missing index for address verification'); } @@ -404,6 +431,13 @@ export class Trx extends BaseCoin { return true; } + /** @inheritDoc */ + async getSignablePayload(serializedTx: string): Promise { + const txBuilder = getBuilder(this.getChain()).from(serializedTx); + const rebuiltTransaction = await txBuilder.build(); + return rebuiltTransaction.signablePayload; + } + /** * Derive a user key using the chain path of the address * @param key @@ -1071,7 +1105,11 @@ export class Trx extends BaseCoin { } /** @inheritDoc */ - auditDecryptedKey(params: AuditDecryptedKeyParams) { - throw new MethodNotImplementedError(); + auditDecryptedKey({ multiSigType, publicKey, prv }: AuditDecryptedKeyParams) { + if (multiSigType === 'tss') { + auditEcdsaPrivateKey(prv as string, publicKey as string); + } else { + throw new MethodNotImplementedError(); + } } } diff --git a/modules/statics/src/coinFeatures.ts b/modules/statics/src/coinFeatures.ts index 6ac58e36c7..94290bd20f 100644 --- a/modules/statics/src/coinFeatures.ts +++ b/modules/statics/src/coinFeatures.ts @@ -433,6 +433,10 @@ export const TRX_FEATURES = [ CoinFeature.MULTISIG_COLD, CoinFeature.MULTISIG, CoinFeature.STAKING, + CoinFeature.TSS, + CoinFeature.TSS_COLD, + CoinFeature.MPCV2, + CoinFeature.SHA256_WITH_ECDSA_TSS, ]; export const COSMOS_SIDECHAIN_FEATURES = [ ...ACCOUNT_COIN_DEFAULT_FEATURES, diff --git a/modules/statics/test/unit/fixtures/expectedColdFeatures.ts b/modules/statics/test/unit/fixtures/expectedColdFeatures.ts index 6626148633..f43d07b27b 100644 --- a/modules/statics/test/unit/fixtures/expectedColdFeatures.ts +++ b/modules/statics/test/unit/fixtures/expectedColdFeatures.ts @@ -13,6 +13,8 @@ export const expectedColdFeatures = { 'tsoneium', 'flr', 'tflr', + 'trx', + 'ttrx', ], justMultiSig: [ 'algo', @@ -54,9 +56,7 @@ export const expectedColdFeatures = { 'thbar', 'tltc', 'trbtc', - 'trx', 'tstx', - 'ttrx', 'txlm', 'txrp', 'txtz',