UNPKG

ecash-agora

Version:

Library for interacting with the eCash Agora protocol

154 lines 6.34 kB
"use strict"; // Copyright (c) 2025 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. Object.defineProperty(exports, "__esModule", { value: true }); exports.getAgoraAdFuelSats = exports.getAgoraCancelFuelInputs = exports.getAgoraOneshotAcceptFuelInputs = exports.getAgoraPartialAcceptFuelInputs = exports.DUMMY_KEYPAIR = void 0; const ecash_lib_1 = require("ecash-lib"); const DUMMY_TXID = '1111111111111111111111111111111111111111111111111111111111111111'; const DUMMY_WALLET_HASH = (0, ecash_lib_1.fromHex)('12'.repeat(20)); const DUMMY_SUFFICIENT_CANCEL_VALUE = 10000n; const DUMMY_SCRIPT = ecash_lib_1.Script.p2pkh(DUMMY_WALLET_HASH); exports.DUMMY_KEYPAIR = { sk: (0, ecash_lib_1.fromHex)('33'.repeat(32)), pk: (0, ecash_lib_1.fromHex)('023c72addb4fdf09af94f0c94d7fe92a386a7e70cf8a1d85916386bb2535c7b1b1'), }; // Used for accept and cancel fee estimation of agora partial offers const DUMMY_INPUT = { input: { prevOut: { txid: DUMMY_TXID, outIdx: 1, }, signData: { sats: DUMMY_SUFFICIENT_CANCEL_VALUE, outputScript: DUMMY_SCRIPT, }, }, signatory: (0, ecash_lib_1.P2PKHSignatory)(exports.DUMMY_KEYPAIR.sk, exports.DUMMY_KEYPAIR.pk, ecash_lib_1.ALL_BIP143), }; /** * Determine input utxos to cover an Agora Partial accept offer */ const getAgoraPartialAcceptFuelInputs = (agoraOffer, utxos, acceptedAtoms, feePerKb = ecash_lib_1.DEFAULT_FEE_SATS_PER_KB) => { const fuelInputs = []; const dummyInputs = []; let inputSatoshis = 0n; for (const utxo of utxos) { // Accumulative utxo selection fuelInputs.push(utxo); // Match our fuelInput count with dummyInputs dummyInputs.push(DUMMY_INPUT); inputSatoshis += utxo.sats; const askedSats = agoraOffer.askedSats(BigInt(acceptedAtoms)); // Get the tx fee for this tx const acceptFeeSats = agoraOffer.acceptFeeSats({ recipientScript: DUMMY_SCRIPT, extraInputs: dummyInputs, acceptedAtoms, feePerKb, }); // We need to cover the tx fee and the asking price const requiredSats = acceptFeeSats + askedSats; if (inputSatoshis >= requiredSats) { return fuelInputs; } } throw new Error('Insufficient utxos to accept this offer'); }; exports.getAgoraPartialAcceptFuelInputs = getAgoraPartialAcceptFuelInputs; /** * Determine input utxos to cover an Agora ONESHOT accept offer * Note: we could refactor getAgoraPartialAcceptFuelInputs to work with ONESHOT offers * However there is some ambiguity involved with the acceptedAtoms param * Cleaner to keep distinct functions */ const getAgoraOneshotAcceptFuelInputs = (agoraOffer, utxos, feePerKb = ecash_lib_1.DEFAULT_FEE_SATS_PER_KB) => { const fuelInputs = []; const dummyInputs = []; let inputSatoshis = 0n; for (const utxo of utxos) { // Accumulative utxo selection fuelInputs.push(utxo); // Match our fuelInput count with dummyInputs dummyInputs.push(DUMMY_INPUT); inputSatoshis += utxo.sats; const askedSats = agoraOffer.askedSats(); // Get the tx fee for this tx const acceptFeeSats = agoraOffer.acceptFeeSats({ recipientScript: DUMMY_SCRIPT, extraInputs: dummyInputs, feePerKb, }); // We need to cover the tx fee and the asking price const requiredSats = acceptFeeSats + askedSats; if (inputSatoshis >= requiredSats) { return fuelInputs; } } throw new Error('Insufficient utxos to accept this offer'); }; exports.getAgoraOneshotAcceptFuelInputs = getAgoraOneshotAcceptFuelInputs; /** * Determine input utxos to cancel an Agora offer (Partial or ONESHOT) */ const getAgoraCancelFuelInputs = (agoraOffer, utxos, feePerKb = ecash_lib_1.DEFAULT_FEE_SATS_PER_KB) => { const fuelInputs = []; const dummyInputs = []; let inputSatoshis = 0n; for (const utxo of utxos) { // Accumulative utxo selection fuelInputs.push(utxo); // Match our fuelInput count with dummyInputs dummyInputs.push(DUMMY_INPUT); inputSatoshis += utxo.sats; // Get the tx fee for this tx // In practice, this is always bigger than dust // So we do not check to make sure the output we cover is at least dust const cancelFeeSats = agoraOffer.cancelFeeSats({ recipientScript: DUMMY_SCRIPT, extraInputs: dummyInputs, feePerKb, }); // There is no asking price for cancellation // cancelFeeSats is the size of the output we need if (inputSatoshis >= cancelFeeSats) { return fuelInputs; } } throw new Error('Insufficient utxos to cancel this offer'); }; exports.getAgoraCancelFuelInputs = getAgoraCancelFuelInputs; /** * Calculate the fee required for an offer transaction that spends an ad script output. * This is used to determine how much fuel needs to be included in the ad setup transaction. */ const getAgoraAdFuelSats = (redeemScript, signatory, offerOutputs, satsPerKb) => { // Build a dummy offer tx to measure its size const dummyOfferTx = new ecash_lib_1.TxBuilder({ inputs: [ { input: { prevOut: { // Use a placeholder 32-byte txid txid: DUMMY_TXID, // The outIdx will always be 1 in practice outIdx: 1, }, signData: { // Arbitrary value that we know will cover the fee for this tx sats: 100000n, redeemScript, }, }, signatory, }, ], outputs: offerOutputs, }); const measureTx = dummyOfferTx.sign({ ecc: new ecash_lib_1.EccDummy() }); const dummyOfferTxSats = BigInt(Math.ceil((measureTx.serSize() * Number(satsPerKb)) / 1000)); return dummyOfferTxSats; }; exports.getAgoraAdFuelSats = getAgoraAdFuelSats; //# sourceMappingURL=inputs.js.map