diff --git a/modules/sdk-coin-canton/src/lib/constant.ts b/modules/sdk-coin-canton/src/lib/constant.ts index 789ba64a4d..0fefb27d03 100644 --- a/modules/sdk-coin-canton/src/lib/constant.ts +++ b/modules/sdk-coin-canton/src/lib/constant.ts @@ -12,3 +12,5 @@ export const SigningAlgorithmSpec = { export const PUBLIC_KEY_FORMAT = 'CRYPTO_KEY_FORMAT_RAW'; export const PUBLIC_KEY_SPEC = 'SIGNING_KEY_SPEC_EC_CURVE25519'; +export const SIGNATURE_FORMAT = 'SIGNATURE_FORMAT_RAW'; +export const SIGNATURE_ALGORITHM_SPEC = 'SIGNING_ALGORITHM_SPEC_ED25519'; diff --git a/modules/sdk-coin-canton/src/lib/iface.ts b/modules/sdk-coin-canton/src/lib/iface.ts index 24a79c56bd..ffda04ef8b 100644 --- a/modules/sdk-coin-canton/src/lib/iface.ts +++ b/modules/sdk-coin-canton/src/lib/iface.ts @@ -64,3 +64,20 @@ export interface OneStepEnablementRequest { actAs: string[]; readAs: string[]; } + +export interface OnboardingTransaction { + transaction: string; +} + +export interface MultiHashSignature { + format: string; + signature: string; + signedBy: string; + signingAlgorithmSpec: string; +} + +export interface WalletInitBroadcastData { + preparedParty: PreparedParty; + onboardingTransactions: OnboardingTransaction[]; + multiHashSignatures: MultiHashSignature[]; +} diff --git a/modules/sdk-coin-canton/src/lib/walletInitBuilder.ts b/modules/sdk-coin-canton/src/lib/walletInitBuilder.ts index 6939c5c103..291a0d74cc 100644 --- a/modules/sdk-coin-canton/src/lib/walletInitBuilder.ts +++ b/modules/sdk-coin-canton/src/lib/walletInitBuilder.ts @@ -1,6 +1,14 @@ import BigNumber from 'bignumber.js'; -import { BaseAddress, BaseKey, BaseTransactionBuilder, BuildTransactionError } from '@bitgo/sdk-core'; +import { + BaseAddress, + BaseKey, + BaseTransactionBuilder, + BuildTransactionError, + InvalidTransactionError, + PublicKey, + Signature, +} from '@bitgo/sdk-core'; import { BaseCoin as CoinConfig } from '@bitgo/statics'; import { KeyPair } from './keyPair'; @@ -11,6 +19,7 @@ import { PUBLIC_KEY_FORMAT, PUBLIC_KEY_SPEC } from './constant'; export class WalletInitBuilder extends BaseTransactionBuilder { private _transaction: WalletInitTransaction; + private _signatures: Signature[] = []; private _publicKey: IPublicKey; private _partyHint: string; @@ -91,6 +100,15 @@ export class WalletInitBuilder extends BaseTransactionBuilder { throw new Error('Not implemented'); } + /** @inheritDoc */ + addSignature(publicKey: PublicKey, signature: Buffer): void { + if (!this.transaction) { + throw new InvalidTransactionError('transaction is empty!'); + } + this._signatures.push({ publicKey, signature }); + this.transaction.signatures = signature.toString('base64'); + } + /** * Sets the public key used for signing. * diff --git a/modules/sdk-coin-canton/src/lib/walletInitialization/walletInitTransaction.ts b/modules/sdk-coin-canton/src/lib/walletInitialization/walletInitTransaction.ts index fe108d7259..6e536aa0b6 100644 --- a/modules/sdk-coin-canton/src/lib/walletInitialization/walletInitTransaction.ts +++ b/modules/sdk-coin-canton/src/lib/walletInitialization/walletInitTransaction.ts @@ -1,6 +1,13 @@ import { BaseKey, BaseTransaction, InvalidTransactionError, TransactionType } from '@bitgo/sdk-core'; import { BaseCoin as CoinConfig } from '@bitgo/statics'; -import { PreparedParty, WalletInitTxData } from '../iface'; +import { + MultiHashSignature, + OnboardingTransaction, + PreparedParty, + WalletInitBroadcastData, + WalletInitTxData, +} from '../iface'; +import { SIGNATURE_ALGORITHM_SPEC, SIGNATURE_FORMAT } from '../constant'; export class WalletInitTransaction extends BaseTransaction { private _preparedParty: PreparedParty; @@ -31,7 +38,29 @@ export class WalletInitTransaction extends BaseTransaction { if (!this._preparedParty) { throw new InvalidTransactionError('Empty transaction data'); } - return Buffer.from(JSON.stringify(this._preparedParty)).toString('base64'); + const multiHashSignatures: MultiHashSignature[] = []; + if (this.signature.length > 0) { + this.signature.map((signature) => { + const multiHashSignature: MultiHashSignature = { + format: SIGNATURE_FORMAT, + signature: signature, + signedBy: this._preparedParty.publicKeyFingerprint, + signingAlgorithmSpec: SIGNATURE_ALGORITHM_SPEC, + }; + multiHashSignatures.push(multiHashSignature); + }); + } + const walletInitBroadcastData: WalletInitBroadcastData = { + preparedParty: this._preparedParty, + onboardingTransactions: this._preparedParty.topologyTransactions.map((txn) => { + const onboardingTransaction: OnboardingTransaction = { + transaction: txn, + }; + return onboardingTransaction; + }), + multiHashSignatures: multiHashSignatures, + }; + return Buffer.from(JSON.stringify(walletInitBroadcastData)).toString('base64'); } toJson(): WalletInitTxData { @@ -55,10 +84,15 @@ export class WalletInitTransaction extends BaseTransaction { fromRawTransaction(rawTx: string): void { try { - const decoded: PreparedParty = JSON.parse(Buffer.from(rawTx, 'base64').toString('utf8')); - this._preparedParty = decoded; + const decoded: WalletInitBroadcastData = JSON.parse(Buffer.from(rawTx, 'base64').toString('utf8')); + this._preparedParty = decoded.preparedParty; this._type = TransactionType.WalletInitialization; - this._id = decoded.multiHash; + this._id = decoded.preparedParty.multiHash; + if (decoded.multiHashSignatures.length > 0) { + decoded.multiHashSignatures.map((multiHashSignature: MultiHashSignature) => { + this.signatures = multiHashSignature.signature; + }); + } } catch (e) { throw new InvalidTransactionError('Unable to parse raw transaction data'); } diff --git a/modules/sdk-coin-canton/test/unit/builder/walletInit/walletInitBuilder.ts b/modules/sdk-coin-canton/test/unit/builder/walletInit/walletInitBuilder.ts index 12d2ac8e34..173a66f6d2 100644 --- a/modules/sdk-coin-canton/test/unit/builder/walletInit/walletInitBuilder.ts +++ b/modules/sdk-coin-canton/test/unit/builder/walletInit/walletInitBuilder.ts @@ -3,8 +3,7 @@ import should from 'should'; import { coins } from '@bitgo/statics'; -import { WalletInitBuilder } from '../../../../src/lib/walletInitBuilder'; -import { WalletInitTransaction } from '../../../../src/lib/walletInitialization/walletInitTransaction'; +import { WalletInitBuilder, WalletInitTransaction } from '../../../../src'; import { WalletInitRequest } from '../../../../src/lib/iface'; import { GenerateTopologyResponse, InvalidGenerateTopologyResponse, WalletInitRequestData } from '../../../resources';