UNPKG

@xlink-network/xlink-sdk

Version:
117 lines (100 loc) 3.25 kB
import { hasAny, sortBy } from "../utils/arrayHelpers" import { MAX_BIGINT, sum } from "../utils/bigintHelpers" import { isSameUTXO, sumUTXO, UTXOBasic, UTXOConfirmed, UTXOSpendable, } from "./bitcoinHelpers" import { decodeHex } from "../utils/hexHelpers" import { isNotNull } from "../utils/typeHelpers" import { ReselectSpendableUTXOsFn } from "./prepareTransaction" export type GetConfirmedSpendableUTXOFn = ( utxo: UTXOBasic, ) => Promise<undefined | (UTXOSpendable & UTXOConfirmed)> export const reselectSpendableUTXOsFactory = ( availableUTXOs: UTXOBasic[], getUTXOSpendable: GetConfirmedSpendableUTXOFn, ): ReselectSpendableUTXOsFn => { return async (satsToSend, pinnedUTXOs, _lastTimeSelectedUTXOs) => { const lastTimeSelectedUTXOs = await Promise.all( _lastTimeSelectedUTXOs.map(getUTXOSpendable), ).then(utxos => utxos.filter(isNotNull)) const otherAvailableUTXOs = await Promise.all( availableUTXOs .filter( availableUTXO => !lastTimeSelectedUTXOs.find(selectedUTXO => isSameUTXO(availableUTXO, selectedUTXO), ), ) .map(getUTXOSpendable), ).then(utxos => utxos.filter(isNotNull)) return selectUTXOs(satsToSend, lastTimeSelectedUTXOs, otherAvailableUTXOs) } } export const reselectSpendableUTXOsWithSafePadFactory = ( availableUTXOs: UTXOBasic[], getUTXOSpendable: GetConfirmedSpendableUTXOFn, ): ReselectSpendableUTXOsFn => { const reselect = reselectSpendableUTXOsFactory( availableUTXOs, getUTXOSpendable, ) return async (satsToSend, pinnedUTXOs, lastTimeSelectedUTXOs) => { const utxos = await reselect(satsToSend, pinnedUTXOs, lastTimeSelectedUTXOs) const selectedAmount = sumUTXO(utxos) const difference = satsToSend - selectedAmount if (difference > 0n) { return utxos.concat({ addressType: "p2pkh", txId: "0000000000000000000000000000000000000000000000000000000000000000", index: 0, amount: MAX_BIGINT, /** * OutScript.encode({ * type: 'pkh', * hash: hash160(secp256k1.getPublicKey( * hex.decode('0000000000000000000000000000000000000000000000000000000000000001'), * false, * )) * }) */ scriptPubKey: decodeHex( "76a91491b24bf9f5288532960ac687abb035127b1d28a588ac", ), isPublicKeyCompressed: false, }) } return utxos } } export function selectUTXOs<T extends UTXOConfirmed>( satsToSend: bigint, selectedUTXOs: T[], otherAvailableUTXOs: T[], ): T[] { const inputs: Array<T> = [] let sumValue = 0n otherAvailableUTXOs = otherAvailableUTXOs.slice() if (hasAny(selectedUTXOs)) { inputs.push(...selectedUTXOs) sumValue = sum([sumValue, ...selectedUTXOs.map(o => o.amount)]) } // Sort UTXOs: // 1. By amount in descending order // 2. By block height in ascending order otherAvailableUTXOs = sortBy( [o => -o.amount, o => o.blockHeight], otherAvailableUTXOs, ) for (const utxo of otherAvailableUTXOs) { inputs.push(utxo) sumValue = sumValue + utxo.amount if (sumValue >= satsToSend) { break } } return inputs }