22
33import * as _ from 'lodash' ;
44import { Constants } from './constants' ;
5+ import { Deriver , Transactions } from 'crypto-wallet-core' ;
56import { Defaults } from './defaults' ;
67
78var $ = require ( 'preconditions' ) . singleton ( ) ;
@@ -11,7 +12,8 @@ var Stringify = require('json-stable-stringify');
1112var Bitcore = require ( 'bitcore-lib' ) ;
1213var Bitcore_ = {
1314 btc : Bitcore ,
14- bch : require ( 'bitcore-lib-cash' )
15+ bch : require ( 'bitcore-lib-cash' ) ,
16+ eth : Bitcore
1517} ;
1618var PrivateKey = Bitcore . PrivateKey ;
1719var PublicKey = Bitcore . PublicKey ;
@@ -135,6 +137,13 @@ export class Utils {
135137 return [ toAddress , amount , message || '' , payProUrl || '' ] . join ( '|' ) ;
136138 }
137139
140+ static parseDerivationPath = function ( path : string ) {
141+ const pathIndex = / m \/ ( [ 0 - 9 ] * ) \/ ( [ 0 - 9 ] * ) / ;
142+ const [ _input , changeIndex , addressIndex ] = path . match ( pathIndex ) ;
143+ const isChange = Number . parseInt ( changeIndex ) > 0 ;
144+ return { _input, addressIndex, isChange } ;
145+ }
146+
138147 static deriveAddress ( scriptType , publicKeyRing , path , m , network , coin ) {
139148 $ . checkArgument ( _ . includes ( _ . values ( Constants . SCRIPT_TYPES ) , scriptType ) ) ;
140149
@@ -152,7 +161,19 @@ export class Utils {
152161 break ;
153162 case Constants . SCRIPT_TYPES . P2PKH :
154163 $ . checkState ( _ . isArray ( publicKeys ) && publicKeys . length == 1 ) ;
155- bitcoreAddress = bitcore . Address . fromPublicKey ( publicKeys [ 0 ] , network ) ;
164+ if ( Constants . UTXO_COINS . includes ( coin ) ) {
165+ bitcoreAddress = bitcore . Address . fromPublicKey ( publicKeys [ 0 ] , network ) ;
166+ } else {
167+ const { addressIndex, isChange } = this . parseDerivationPath ( path ) ;
168+ const [ { xPubKey } ] = publicKeyRing ;
169+ bitcoreAddress = Deriver . deriveAddress (
170+ coin . toUpperCase ( ) ,
171+ network ,
172+ xPubKey ,
173+ addressIndex ,
174+ isChange
175+ ) ;
176+ }
156177 break ;
157178 }
158179
@@ -231,79 +252,81 @@ export class Utils {
231252 static buildTx ( txp ) {
232253 var coin = txp . coin || 'btc' ;
233254
234- var bitcore = Bitcore_ [ coin ] ;
255+ if ( Constants . UTXO_COINS . includes ( coin ) ) {
235256
236- var t = new bitcore . Transaction ( ) ;
257+ var bitcore = Bitcore_ [ coin ] ;
237258
238- $ . checkState ( _ . includes ( _ . values ( Constants . SCRIPT_TYPES ) , txp . addressType ) ) ;
259+ var t = new bitcore . Transaction ( ) ;
239260
240- switch ( txp . addressType ) {
241- case Constants . SCRIPT_TYPES . P2SH :
242- _ . each ( txp . inputs , i => {
243- t . from ( i , i . publicKeys , txp . requiredSignatures ) ;
244- } ) ;
245- break ;
246- case Constants . SCRIPT_TYPES . P2PKH :
247- t . from ( txp . inputs ) ;
248- break ;
249- }
261+ $ . checkState ( _ . includes ( _ . values ( Constants . SCRIPT_TYPES ) , txp . addressType ) ) ;
250262
251- if ( txp . toAddress && txp . amount && ! txp . outputs ) {
252- t . to ( txp . toAddress , txp . amount ) ;
253- } else if ( txp . outputs ) {
254- _ . each ( txp . outputs , o => {
255- $ . checkState (
256- o . script || o . toAddress ,
257- 'Output should have either toAddress or script specified'
258- ) ;
259- if ( o . script ) {
260- t . addOutput (
261- new bitcore . Transaction . Output ( {
263+ switch ( txp . addressType ) {
264+ case Constants . SCRIPT_TYPES . P2SH :
265+ _ . each ( txp . inputs , ( i ) => {
266+ t . from ( i , i . publicKeys , txp . requiredSignatures ) ;
267+ } ) ;
268+ break ;
269+ case Constants . SCRIPT_TYPES . P2PKH :
270+ t . from ( txp . inputs ) ;
271+ break ;
272+ }
273+
274+ if ( txp . toAddress && txp . amount && ! txp . outputs ) {
275+ t . to ( txp . toAddress , txp . amount ) ;
276+ } else if ( txp . outputs ) {
277+ _ . each ( txp . outputs , ( o ) => {
278+ $ . checkState ( o . script || o . toAddress , 'Output should have either toAddress or script specified' ) ;
279+ if ( o . script ) {
280+ t . addOutput ( new bitcore . Transaction . Output ( {
262281 script : o . script ,
263282 satoshis : o . amount
264- } )
265- ) ;
266- } else {
267- t . to ( o . toAddress , o . amount ) ;
268- }
269- } ) ;
270- }
283+ } ) ) ;
284+ } else {
285+ t . to ( o . toAddress , o . amount ) ;
286+ }
287+ } ) ;
288+ }
271289
272- t . fee ( txp . fee ) ;
273- t . change ( txp . changeAddress . address ) ;
290+ t . fee ( txp . fee ) ;
291+ t . change ( txp . changeAddress . address ) ;
274292
275- // Shuffle outputs for improved privacy
276- if ( t . outputs . length > 1 ) {
277- var outputOrder = _ . reject ( txp . outputOrder , order => {
278- return order >= t . outputs . length ;
279- } ) ;
280- $ . checkState ( t . outputs . length == outputOrder . length ) ;
281- t . sortOutputs ( outputs => {
282- return _ . map ( outputOrder , i => {
283- return outputs [ i ] ;
293+ // Shuffle outputs for improved privacy
294+ if ( t . outputs . length > 1 ) {
295+ var outputOrder = _ . reject ( txp . outputOrder , ( order ) => {
296+ return order >= t . outputs . length ;
284297 } ) ;
285- } ) ;
286- }
298+ $ . checkState ( t . outputs . length == outputOrder . length ) ;
299+ t . sortOutputs ( ( outputs ) => {
300+ return _ . map ( outputOrder , ( i ) => {
301+ return outputs [ i ] ;
302+ } ) ;
303+ } ) ;
304+ }
287305
288- // Validate inputs vs outputs independently of Bitcore
289- var totalInputs = _ . reduce (
290- txp . inputs ,
291- ( memo , i ) => {
306+ // Validate inputs vs outputs independently of Bitcore
307+ var totalInputs = _ . reduce ( txp . inputs , ( memo , i ) => {
292308 return + i . satoshis + memo ;
293- } ,
294- 0
295- ) ;
296- var totalOutputs = _ . reduce (
297- t . outputs ,
298- ( memo , o ) => {
309+ } , 0 ) ;
310+ var totalOutputs = _ . reduce ( t . outputs , ( memo , o ) => {
299311 return + o . satoshis + memo ;
300- } ,
301- 0
302- ) ;
303-
304- $ . checkState ( totalInputs - totalOutputs >= 0 ) ;
305- $ . checkState ( totalInputs - totalOutputs <= Defaults . MAX_TX_FEE ) ;
306-
307- return t ;
312+ } , 0 ) ;
313+
314+ $ . checkState ( totalInputs - totalOutputs >= 0 ) ;
315+ $ . checkState ( totalInputs - totalOutputs <= Defaults . MAX_TX_FEE ) ;
316+
317+ return t ;
318+ } else {
319+ const { outputs, amount, from, nonce, gasPrice, data, gasLimit } = txp ;
320+ const rawTx = Transactions . create ( {
321+ chain : coin . toUpperCase ( ) ,
322+ recipients : [ { address : outputs [ 0 ] . toAddress , amount } ] ,
323+ from,
324+ nonce,
325+ fee : gasPrice ,
326+ data,
327+ gasLimit
328+ } ) ;
329+ return { uncheckedSerialize : ( ) => rawTx } ;
330+ }
308331 }
309332}
0 commit comments