import { Bip32Path } from "@iota/crypto.js" ; import { Converter } from "@iota/util.js" ; import { Ed25519Address } from "../addressTypes/ed25519Address" ; import { SingleNodeClient } from "../clients/singleNodeClient" ; import type { IBip44GeneratorState } from "../models/IBip44GeneratorState" ; import type { IClient } from "../models/IClient" ; import { ED25519_ADDRESS_TYPE } from "../models/IEd25519Address" ; import type { IKeyPair } from "../models/IKeyPair" ; import type { IMessage } from "../models/IMessage" ; import type { ISeed } from "../models/ISeed" ; import { IUTXOInput , UTXO_INPUT_TYPE } from "../models/IUTXOInput" ; import { Bech32Helper } from "../utils/bech32Helper" ; import { generateBip44Address } from "./addresses" ; import { sendAdvanced } from "./sendAdvanced" ; param client param seed param accountIndex param addressBech32 param amount param indexation param indexation . key param indexation . data param addressOptions param addressOptions . startIndex param addressOptions . zeroCount returns export async function send ( client , seed , accountIndex , addressBech32 , amount , indexation ? , addressOptions ? ) { return sendMultiple ( client , seed , accountIndex , [ { addressBech32 , amount } ] , indexation , addressOptions ) ; } param client param seed param accountIndex param addressEd25519 param amount param indexation param indexation . key param indexation . data param addressOptions param addressOptions . startIndex param addressOptions . zeroCount returns export async function sendEd25519 ( client , seed , accountIndex , addressEd25519 , amount , indexation ? , addressOptions ? ) { return sendMultipleEd25519 ( client , seed , accountIndex , [ { addressEd25519 , amount } ] , indexation , addressOptions ) ; } param client param seed param accountIndex param outputs param indexation param indexation . key param indexation . data param addressOptions param addressOptions . startIndex param addressOptions . zeroCount returns export async function sendMultiple ( client , seed , accountIndex , outputs , indexation ? , addressOptions ? ) { const localClient = typeof client === "string" ? new SingleNodeClient ( client ) : client ; const nodeInfo = await localClient . info ( ) ; const hexOutputs = outputs . map ( output => { const bech32Details = Bech32Helper . fromBech32 ( output . addressBech32 , nodeInfo . bech32HRP ) ; if ( ! bech32Details ) { throw new Error ( "Unable to decode bech32 address" ) ; } return { address : Converter . bytesToHex ( bech32Details . addressBytes ) , addressType : bech32Details . addressType , amount : output . amount , isDustAllowance : output . isDustAllowance } ; } ) ; return sendWithAddressGenerator < IBip44GeneratorState > ( client , seed , { accountIndex , addressIndex : addressOptions ?. startIndex ?? 0 , isInternal : false } , generateBip44Address , hexOutputs , indexation , addressOptions ?. zeroCount ) ; } param client param seed param accountIndex param outputs param indexation param indexation . key param indexation . data param addressOptions param addressOptions . startIndex param addressOptions . zeroCount returns export async function sendMultipleEd25519 ( client , seed , accountIndex , outputs , indexation ? , addressOptions ? ) { const hexOutputs = outputs . map ( output => ( { address : output . addressEd25519 , addressType : ED25519_ADDRESS_TYPE , amount : output . amount , isDustAllowance : output . isDustAllowance } ) ) ; return sendWithAddressGenerator < IBip44GeneratorState > ( client , seed , { accountIndex , addressIndex : addressOptions ?. startIndex ?? 0 , isInternal : false } , generateBip44Address , hexOutputs , indexation , addressOptions ?. zeroCount ) ; } param client param seed param initialAddressState param nextAddressPath param outputs param indexation param indexation . key param indexation . data param zeroCount returns export async function sendWithAddressGenerator < T > ( client , seed , initialAddressState , nextAddressPath , outputs , indexation ? , zeroCount ? ) { const inputsAndKeys = await calculateInputs ( client , seed , initialAddressState , nextAddressPath , outputs , zeroCount ) ; const response = await sendAdvanced ( client , inputsAndKeys , outputs , indexation ) ; return { messageId : response . messageId , message : response . message } ; } param client param seed param initialAddressState param nextAddressPath param outputs param zeroCount returns export async function calculateInputs < T > ( client , seed , initialAddressState , nextAddressPath , outputs , zeroCount = 5 ) { const localClient = typeof client === "string" ? new SingleNodeClient ( client ) : client ; let requiredBalance = 0 ; for ( const output of outputs ) { requiredBalance += output . amount ; } let consumedBalance = 0 ; const inputsAndSignatureKeyPairs = [ ] ; let finished = false ; let zeroBalance = 0 ; do { const path = nextAddressPath ( initialAddressState ) ; const addressSeed = seed . generateSeedFromPath ( new Bip32Path ( path ) ) ; const addressKeyPair = addressSeed . keyPair ( ) ; const ed25519Address = new Ed25519Address ( addressKeyPair . publicKey ) ; const address = Converter . bytesToHex ( ed25519Address . toAddress ( ) ) ; const addressOutputIds = await localClient . addressEd25519Outputs ( address ) ; if ( addressOutputIds . count === 0 ) { zeroBalance ++ ; if ( zeroBalance >= zeroCount ) { finished = true ; } } else { for ( const addressOutputId of addressOutputIds . outputIds ) { const addressOutput = await localClient . output ( addressOutputId ) ; if ( ! addressOutput . isSpent && consumedBalance < requiredBalance ) { if ( addressOutput . output . amount === 0 ) { zeroBalance ++ ; if ( zeroBalance >= zeroCount ) { finished = true ; } } else { consumedBalance += addressOutput . output . amount ; const input = { type : UTXO_INPUT_TYPE , transactionId : addressOutput . transactionId , transactionOutputIndex : addressOutput . outputIndex } ; inputsAndSignatureKeyPairs . push ( { input , addressKeyPair } ) ; if ( consumedBalance >= requiredBalance ) { if ( consumedBalance - requiredBalance > 0 ) { outputs . push ( { amount : consumedBalance - requiredBalance , address : addressOutput . output . address . address , addressType : addressOutput . output . address . type } ) ; } finished = true ; } } } } } } while ( ! finished ) ; if ( consumedBalance < requiredBalance ) { throw new Error ( "There are not enough funds in the inputs for the required balance" ) ; } return inputsAndSignatureKeyPairs ; }