11import { fixedScriptWallet } from '@bitgo/wasm-utxo' ;
22import { Triple } from '@bitgo/sdk-core' ;
33
4- import type { FixedScriptWalletOutput , Output } from '../types' ;
4+ import type { FixedScriptWalletOutput , Output , BitGoPsbt } from '../types' ;
55
66import type { TransactionExplanationWasm } from './explainTransaction' ;
77
@@ -20,71 +20,164 @@ function isParsedExternalOutput(output: ParsedWalletOutput | ParsedExternalOutpu
2020 return output . scriptId === null ;
2121}
2222
23- function toChangeOutput ( output : ParsedWalletOutput ) : FixedScriptWalletOutput {
23+ function toChangeOutputBigInt ( output : ParsedWalletOutput ) : FixedScriptWalletOutput < bigint > {
2424 return {
2525 address : output . address ?? scriptToAddress ( output . script ) ,
26- amount : output . value . toString ( ) ,
26+ amount : output . value ,
2727 chain : output . scriptId . chain ,
2828 index : output . scriptId . index ,
2929 external : false ,
3030 } ;
3131}
3232
33- function toExternalOutput ( output : ParsedExternalOutput ) : Output {
33+ function toExternalOutputBigInt ( output : ParsedExternalOutput ) : Output < bigint > {
3434 return {
3535 address : output . address ?? scriptToAddress ( output . script ) ,
36- amount : output . value . toString ( ) ,
36+ amount : output . value ,
3737 external : true ,
3838 } ;
3939}
4040
41- export function explainPsbtWasm (
42- psbt : fixedScriptWallet . BitGoPsbt ,
41+ interface ExplainPsbtWasmParams {
42+ replayProtection : {
43+ checkSignature ?: boolean ;
44+ publicKeys : Buffer [ ] ;
45+ } ;
46+ customChangeWalletXpubs ?: Triple < string > | fixedScriptWallet . RootWalletKeys ;
47+ }
48+
49+ export interface ExplainedInput < TAmount = bigint > {
50+ address : string ;
51+ value : TAmount ;
52+ }
53+
54+ export interface TransactionExplanationBigInt {
55+ id : string ;
56+ inputs : ExplainedInput [ ] ;
57+ inputAmount : bigint ;
58+ outputs : Output < bigint > [ ] ;
59+ changeOutputs : FixedScriptWalletOutput < bigint > [ ] ;
60+ customChangeOutputs : FixedScriptWalletOutput < bigint > [ ] ;
61+ outputAmount : bigint ;
62+ changeAmount : bigint ;
63+ customChangeAmount : bigint ;
64+ fee : bigint ;
65+ }
66+
67+ export function explainPsbtWasmBigInt (
68+ psbt : BitGoPsbt ,
4369 walletXpubs : Triple < string > | fixedScriptWallet . RootWalletKeys ,
44- params : {
45- replayProtection : {
46- checkSignature ?: boolean ;
47- publicKeys : Buffer [ ] ;
48- } ;
49- customChangeWalletXpubs ?: Triple < string > | fixedScriptWallet . RootWalletKeys ;
50- }
51- ) : TransactionExplanationWasm {
70+ params : ExplainPsbtWasmParams
71+ ) : TransactionExplanationBigInt {
5272 const parsed = psbt . parseTransactionWithWalletKeys ( walletXpubs , { replayProtection : params . replayProtection } ) ;
5373
54- const changeOutputs : FixedScriptWalletOutput [ ] = [ ] ;
55- const outputs : Output [ ] = [ ] ;
74+ const changeOutputs : FixedScriptWalletOutput < bigint > [ ] = [ ] ;
75+ const outputs : Output < bigint > [ ] = [ ] ;
5676 const parsedCustomChangeOutputs = params . customChangeWalletXpubs
5777 ? psbt . parseOutputsWithWalletKeys ( params . customChangeWalletXpubs )
5878 : undefined ;
5979
60- const customChangeOutputs : FixedScriptWalletOutput [ ] = [ ] ;
80+ const customChangeOutputs : FixedScriptWalletOutput < bigint > [ ] = [ ] ;
6181
6282 parsed . outputs . forEach ( ( output , i ) => {
6383 const parseCustomChangeOutput = parsedCustomChangeOutputs ?. [ i ] ;
6484 if ( isParsedWalletOutput ( output ) ) {
65- // This is a change output
66- changeOutputs . push ( toChangeOutput ( output ) ) ;
85+ changeOutputs . push ( toChangeOutputBigInt ( output ) ) ;
6786 } else if ( parseCustomChangeOutput && isParsedWalletOutput ( parseCustomChangeOutput ) ) {
68- customChangeOutputs . push ( toChangeOutput ( parseCustomChangeOutput ) ) ;
87+ customChangeOutputs . push ( toChangeOutputBigInt ( parseCustomChangeOutput ) ) ;
6988 } else if ( isParsedExternalOutput ( output ) ) {
70- outputs . push ( toExternalOutput ( output ) ) ;
89+ outputs . push ( toExternalOutputBigInt ( output ) ) ;
7190 } else {
7291 throw new Error ( 'Invalid output' ) ;
7392 }
7493 } ) ;
7594
76- const outputAmount = outputs . reduce ( ( sum , output ) => sum + BigInt ( output . amount ) , BigInt ( 0 ) ) ;
77- const changeAmount = changeOutputs . reduce ( ( sum , output ) => sum + BigInt ( output . amount ) , BigInt ( 0 ) ) ;
78- const customChangeAmount = customChangeOutputs . reduce ( ( sum , output ) => sum + BigInt ( output . amount ) , BigInt ( 0 ) ) ;
95+ const inputs = parsed . inputs . map ( ( input ) => ( { address : input . address , value : input . value } ) ) ;
96+ const inputAmount = inputs . reduce ( ( sum , input ) => sum + input . value , 0n ) ;
97+ const outputAmount = outputs . reduce ( ( sum , output ) => sum + output . amount , 0n ) ;
98+ const changeAmount = changeOutputs . reduce ( ( sum , output ) => sum + output . amount , 0n ) ;
99+ const customChangeAmount = customChangeOutputs . reduce ( ( sum , output ) => sum + output . amount , 0n ) ;
79100
80101 return {
81102 id : psbt . unsignedTxId ( ) ,
82- outputAmount : outputAmount . toString ( ) ,
83- changeAmount : changeAmount . toString ( ) ,
84- customChangeAmount : customChangeAmount . toString ( ) ,
103+ inputs,
104+ inputAmount,
85105 outputs,
86106 changeOutputs,
87107 customChangeOutputs,
88- fee : parsed . minerFee . toString ( ) ,
108+ outputAmount,
109+ changeAmount,
110+ customChangeAmount,
111+ fee : parsed . minerFee ,
112+ } ;
113+ }
114+
115+ function stringifyOutput ( output : Output < bigint > ) : Output {
116+ return { ...output , amount : output . amount . toString ( ) } ;
117+ }
118+
119+ function stringifyChangeOutput ( output : FixedScriptWalletOutput < bigint > ) : FixedScriptWalletOutput {
120+ return { ...output , amount : output . amount . toString ( ) } ;
121+ }
122+
123+ export function explainPsbtWasm (
124+ psbt : BitGoPsbt ,
125+ walletXpubs : Triple < string > | fixedScriptWallet . RootWalletKeys ,
126+ params : ExplainPsbtWasmParams
127+ ) : TransactionExplanationWasm {
128+ const result = explainPsbtWasmBigInt ( psbt , walletXpubs , params ) ;
129+ return {
130+ id : result . id ,
131+ inputs : result . inputs . map ( ( i ) => ( { address : i . address , value : i . value . toString ( ) } ) ) ,
132+ inputAmount : result . inputAmount . toString ( ) ,
133+ outputAmount : result . outputAmount . toString ( ) ,
134+ changeAmount : result . changeAmount . toString ( ) ,
135+ customChangeAmount : result . customChangeAmount . toString ( ) ,
136+ outputs : result . outputs . map ( stringifyOutput ) ,
137+ changeOutputs : result . changeOutputs . map ( stringifyChangeOutput ) ,
138+ customChangeOutputs : result . customChangeOutputs . map ( stringifyChangeOutput ) ,
139+ fee : result . fee . toString ( ) ,
140+ } ;
141+ }
142+
143+ export interface AggregatedTransactionExplanation {
144+ inputCount : number ;
145+ outputCount : number ;
146+ changeOutputCount : number ;
147+ inputAmount : bigint ;
148+ outputAmount : bigint ;
149+ changeAmount : bigint ;
150+ fee : bigint ;
151+ }
152+
153+ export function aggregateTransactionExplanations (
154+ explanations : TransactionExplanationBigInt [ ]
155+ ) : AggregatedTransactionExplanation {
156+ let inputCount = 0 ;
157+ let outputCount = 0 ;
158+ let changeOutputCount = 0 ;
159+ let fee = 0n ;
160+ let inputAmount = 0n ;
161+ let outputAmount = 0n ;
162+ let changeAmount = 0n ;
163+
164+ for ( const e of explanations ) {
165+ inputCount += e . inputs . length ;
166+ outputCount += e . outputs . length ;
167+ changeOutputCount += e . changeOutputs . length ;
168+ fee += e . fee ;
169+ inputAmount += e . inputAmount ;
170+ outputAmount += e . outputAmount ;
171+ changeAmount += e . changeAmount ;
172+ }
173+
174+ return {
175+ inputCount,
176+ outputCount,
177+ changeOutputCount,
178+ inputAmount,
179+ outputAmount,
180+ changeAmount,
181+ fee,
89182 } ;
90183}
0 commit comments