import { ASSET_ID , ASSETS } from "../consts" ; import { Fixed8 } from "../u" ; import { AssetBalance , Balance , getScriptHashFromAddress } from "../wallet" ; import { TransactionInput , TransactionOutput } from "./components" ; import { balancedApproach , calculationStrategyFunction } from "./strategy" ; export let defaultCalculationStrategy = balancedApproach ; param intents export function combineIntents ( intents ) { return intents . reduce ( ( assets , intent ) => { assets [ intent . assetId ] ? ( assets [ intent . assetId ] = assets [ intent . assetId ] . add ( intent . value ) ) : ( assets [ intent . assetId ] = intent . value ) ; return assets ; } , { } as Record < string , Fixed8 > ) ; } export function calculateInputsForAsset ( assetBalance , requiredAmt , assetId , address , strategy ) { const selectedInputs = strategy ( assetBalance , requiredAmt ) ; const selectedAmt = selectedInputs . reduce ( ( prev , curr ) => prev . add ( curr . value ) , new Fixed8 ( 0 ) ) ; const change = [ ] ; if ( selectedAmt . gt ( requiredAmt ) ) { change . push ( new TransactionOutput ( { assetId , value : selectedAmt . sub ( requiredAmt ) , scriptHash : getScriptHashFromAddress ( address ) , } ) ) ; } const inputs = selectedInputs . map ( ( input ) => { return new TransactionInput ( { prevHash : input . txid , prevIndex : input . index , } ) ; } ) ; return { inputs , change } ; } param balances param intents param fees param strategy return export function calculateInputs ( balances , intents = [ ] , fees = 0 , strategy ? ) { const chosenStrategy = strategy || defaultCalculationStrategy ; const fixed8Fees = new Fixed8 ( fees ) ; if ( fixed8Fees . gt ( 0 ) ) { intents = intents . slice ( ) ; intents . push ( new TransactionOutput ( { assetId : ASSET_ID . GAS , value : fees , scriptHash : getScriptHashFromAddress ( balances . address ) , } ) ) ; } const requiredAssets = combineIntents ( intents ) ; const inputsAndChange = Object . keys ( requiredAssets ) . map ( ( assetId ) => { const requiredAmt = requiredAssets [ assetId ] ; const assetSymbol = ASSETS [ assetId ] ; if ( balances . assetSymbols . indexOf ( assetSymbol ) === - 1 ) { throw new Error ( `This balance does not contain any ${ assetSymbol }!` ) ; } const assetBalance = balances . assets [ assetSymbol ] ; if ( assetBalance . balance . lt ( requiredAmt ) ) { throw new Error ( `Insufficient ${ ASSETS [ assetId ] }! Need ${ requiredAmt . toString ( ) } but only found ${ assetBalance . balance . toString ( ) }` ) ; } return calculateInputsForAsset ( new AssetBalance ( assetBalance ) , requiredAmt , assetId , balances . address , chosenStrategy ) ; } ) ; const output = inputsAndChange . reduce ( ( prev , curr ) => { return { inputs : prev . inputs . concat ( curr . inputs ) , change : prev . change . concat ( curr . change ) , } ; } , { inputs : [ ] , change : [ ] } ) ; return output ; }