1+ import * as _ from 'lodash' ;
12import {
23 BaseCoin ,
34 BitGoBase ,
@@ -6,14 +7,44 @@ import {
67 ParsedTransaction ,
78 ParseTransactionOptions ,
89 SignedTransaction ,
9- SignTransactionOptions ,
10+ SignTransactionOptions as BaseSignTransactionOptions ,
1011 VerifyAddressOptions ,
1112 VerifyTransactionOptions ,
1213} from '@bitgo/sdk-core' ;
1314import { BaseCoin as StaticsBaseCoin , CoinFamily } from '@bitgo/statics' ;
15+ import { Interface , KeyPair as SubstrateKeyPair , Utils } from './lib' ;
16+
17+ const utils = Utils . default ;
18+
19+ export const DEFAULT_SCAN_FACTOR = 20 ; // default number of receive addresses to scan for funds
20+
21+ export interface SignTransactionOptions extends BaseSignTransactionOptions {
22+ txPrebuild : TransactionPrebuild ;
23+ prv : string ;
24+ }
25+
26+ export interface TransactionPrebuild {
27+ txHex : string ;
28+ transaction : Interface . TxData ;
29+ }
30+
31+ export interface ExplainTransactionOptions {
32+ txPrebuild : TransactionPrebuild ;
33+ publicKey : string ;
34+ feeInfo : {
35+ fee : string ;
36+ } ;
37+ }
38+
39+ export interface VerifiedTransactionParameters {
40+ txHex : string ;
41+ prv : string ;
42+ }
1443
1544export class SubstrateCoin extends BaseCoin {
1645 protected readonly _staticsCoin : Readonly < StaticsBaseCoin > ;
46+ readonly MAX_VALIDITY_DURATION = 2400 ;
47+
1748 protected constructor ( bitgo : BitGoBase , staticsCoin ?: Readonly < StaticsBaseCoin > ) {
1849 super ( bitgo ) ;
1950
@@ -37,7 +68,7 @@ export class SubstrateCoin extends BaseCoin {
3768
3869 /** @inheritDoc **/
3970 getBaseFactor ( ) : string | number {
40- throw new Error ( 'Method not implemented' ) ;
71+ return Math . pow ( 10 , this . _staticsCoin . decimalPlaces ) ;
4172 }
4273
4374 /** @inheritDoc **/
@@ -67,12 +98,20 @@ export class SubstrateCoin extends BaseCoin {
6798
6899 /** @inheritDoc **/
69100 generateKeyPair ( seed ?: Buffer ) : KeyPair {
70- throw new Error ( 'Method not implemented' ) ;
101+ const keyPair = seed ? utils . keyPairFromSeed ( new Uint8Array ( seed ) ) : new SubstrateKeyPair ( ) ;
102+ const keys = keyPair . getKeys ( ) ;
103+ if ( ! keys . prv ) {
104+ throw new Error ( 'Missing prv in key generation.' ) ;
105+ }
106+ return {
107+ pub : keys . pub ,
108+ prv : keys . prv ,
109+ } ;
71110 }
72111
73112 /** @inheritDoc **/
74113 isValidPub ( pub : string ) : boolean {
75- throw new Error ( 'Method not implemented' ) ;
114+ return utils . isValidPublicKey ( pub ) ;
76115 }
77116
78117 /** @inheritDoc **/
@@ -86,17 +125,68 @@ export class SubstrateCoin extends BaseCoin {
86125 }
87126
88127 /** @inheritDoc **/
89- verifyTransaction ( params : VerifyTransactionOptions ) : Promise < boolean > {
90- throw new Error ( 'Method not implemented' ) ;
128+ async verifyTransaction ( params : VerifyTransactionOptions ) : Promise < boolean > {
129+ const { txParams } = params ;
130+ if ( Array . isArray ( txParams . recipients ) && txParams . recipients . length > 1 ) {
131+ throw new Error (
132+ `${ this . getChain ( ) } doesn't support sending to more than 1 destination address within a single transaction. Try again, using only a single recipient.`
133+ ) ;
134+ }
135+ return true ;
91136 }
92137
93138 /** @inheritDoc **/
94139 isValidAddress ( address : string ) : boolean {
95- throw new Error ( 'Method not implemented.' ) ;
140+ return utils . isValidAddress ( address ) ;
141+ }
142+
143+ verifySignTransactionParams ( params : SignTransactionOptions ) : VerifiedTransactionParameters {
144+ const prv = params . prv ;
145+
146+ const txHex = params . txPrebuild . txHex ;
147+
148+ if ( ! txHex ) {
149+ throw new Error ( 'missing txPrebuild parameter' ) ;
150+ }
151+
152+ if ( ! _ . isString ( txHex ) ) {
153+ throw new Error ( `txPrebuild must be an object, got type ${ typeof txHex } ` ) ;
154+ }
155+
156+ if ( ! prv ) {
157+ throw new Error ( 'missing prv parameter to sign transaction' ) ;
158+ }
159+
160+ if ( ! _ . isString ( prv ) ) {
161+ throw new Error ( `prv must be a string, got type ${ typeof prv } ` ) ;
162+ }
163+
164+ if ( ! _ . has ( params , 'pubs' ) ) {
165+ throw new Error ( 'missing public key parameter to sign transaction' ) ;
166+ }
167+
168+ return { txHex, prv } ;
96169 }
97170
98171 /** @inheritDoc **/
99- signTransaction ( params : SignTransactionOptions ) : Promise < SignedTransaction > {
100- throw new Error ( 'Method not implemented.' ) ;
172+ async signTransaction ( params : SignTransactionOptions ) : Promise < SignedTransaction > {
173+ const { txHex, prv } = this . verifySignTransactionParams ( params ) ;
174+ const factory = this . getBuilder ( ) ;
175+ const txBuilder = factory . from ( txHex ) ;
176+ const keyPair = new SubstrateKeyPair ( { prv : prv } ) ;
177+ const { referenceBlock, blockNumber, transactionVersion, sender } = params . txPrebuild . transaction ;
178+
179+ txBuilder
180+ . validity ( { firstValid : blockNumber , maxDuration : this . MAX_VALIDITY_DURATION } )
181+ . referenceBlock ( referenceBlock )
182+ . version ( transactionVersion )
183+ . sender ( { address : sender } )
184+ . sign ( { key : keyPair . getKeys ( ) . prv } ) ;
185+ const transaction = await txBuilder . build ( ) ;
186+ if ( ! transaction ) {
187+ throw new Error ( 'Invalid transaction' ) ;
188+ }
189+ const signedTxHex = transaction . toBroadcastFormat ( ) ;
190+ return { txHex : signedTxHex } ;
101191 }
102192}
0 commit comments