11#!/usr/bin/env -S deno run --allow-read --allow-env --allow-run --allow-write=/tmp/fadroma --allow-import=cdn.skypack.dev:443,deno.land:443 --allow-net=127.0.0.1:8941,liquidtestnet.com:443,blockstream.info:443
22import { deepStrictEqual as equal , rejects , throws , ok } from 'node:assert' ;
33import { Base16 , Fn , Test , Run , sleep } from '../../../library/index.ts' ;
4- import { pubECDSA } from 'npm:@scure/btc-signer/utils.js' ;
5- import Btc , { BtcRpc , Esplora , LiquidTestnet , ElementsRegtest } from '../../Bitcoin/index.ts' ;
4+ import Btc , { BtcRpc , LiquidTestnet , ElementsRegtest } from '../../Bitcoin/index.ts' ;
65import { SendFromWallet , AssertBalance } from '../../Bitcoin/test.ts' ;
7- import { Signer , Keypair , Program , Wasm , Arg , Args } from './sdk.ts' ;
6+ import { Signer , Program , Wasm , Arg , Args } from './sdk.ts' ;
87const { is, has } = Test ;
98const { CreateWallet, Rescan } = BtcRpc ;
109const { INITIAL_COINS , BITCOIN } = ElementsRegtest ;
@@ -48,7 +47,7 @@ export function TestOnLocalnet () {
4847 const BALANCE_INITIAL = { [ ElementsRegtest . ASSETS . REISSUE ] : 1 , bitcoin : Number ( INITIAL_COINS / BITCOIN ) } ;
4948 // Tests that run on temporary localnet:
5049 return Test ( 'elementsregtest' ,
51- ( ) => ElementsRegtest ( { debugs : true , debugexclude : [ 'libevent' ] } ) ,
50+ ( ) => ElementsRegtest ( { debugs : false , debugexclude : [ 'libevent' ] } ) ,
5251 Run . Verbose ( true ) , // Pipe the localnet's output to stderr
5352 CreateWallet ( 'test-simf' , AssertBalance ( BALANCE_EMPTY ) ) ,
5453 Rescan ( AssertBalance ( BALANCE_INITIAL ) ) ,
@@ -107,8 +106,6 @@ export function TestOnLocalnet () {
107106interface TestSend extends Btc {
108107 /** Chain-specific asset IDs. */
109108 ASSETS : { [ key : string ] : unknown } ,
110- /** Input transaction. */
111- tx : unknown
112109 /** To provide funds on testnet. */
113110 callFaucet ?: Fn . Returns < Fn . Async < { txid : string } > > ,
114111 /** Creates a P2WPKH address configured for the given network. */
@@ -119,28 +116,59 @@ interface TestSend extends Btc {
119116 recipient : string
120117}
121118
122- function TestSend ( signer1 = null , signer2 = null , amount = 3000n , fee = 12000n ) {
119+ function TestSend ( amount = 3000n , fee = 12000n ) {
123120 const keypair1 = keypair ( new Uint8Array ( Array ( 32 ) . fill ( 8 ) ) ) ;
124121 const keypair2 = keypair ( new Uint8Array ( Array ( 32 ) . fill ( 9 ) ) ) ;
125- return Fn . Name ( ' Test sendSigned' , testSend ) ;
122+ return Fn . Name ( ` Test sendSigned ${ amount } for ${ fee } ` , testSend ) ;
126123 async function testSend ( { debug = console . debug , ...context } : TestSend ) {
127- const { rpc, rest, esplora, callFaucet, tx : inputTx , ASSETS , P2WPKH } = context ;
128- const sender = P2WPKH ( keypair1 . publicKey ( ) ) . address ;
124+ const { rpc, rest, esplora, callFaucet, ASSETS , P2WPKH } = context ;
125+ const sender = P2WPKH ( keypair1 . publicKey ( ) ) . address ;
129126 const recipient = P2WPKH ( keypair2 . publicKey ( ) ) . address ;
130127 debug ( `Send ${ amount } from ${ sender } to ${ recipient } at ${ fee } ` ) ;
131- const unspent = await rpc . listunspent ( 0 , 9999999 , [ sender ] ) ; // TODO filter
132- const utxo = unspent [ 0 ] ; // { asset, txid, vout, value, address }
128+ const utxo = await findUtxo ( sender ) ;
133129 debug ( 'Input:' , utxo ) ;
134- const options = { sender, recipient, asset : utxo . asset , amount, fee, utxos : [ utxo ] } ;
135- const signed = sendSigned ( keypair1 , options ) ;
136- debug ( 'Signed:' , signed ) ;
137- try {
138- const id = await rpc ! . sendrawtransaction ( signed . hex ) ;
139- const tx = await rest ! . tx ( id ) ;
140- await rpc ! . rescanblockchain ( ) ;
141- } catch ( e ) {
142- await sleep ( 1000 ) ;
143- throw e
130+ const options = { recipient, sender, utxos : [ utxo ] , asset : utxo . asset , amount, fee } ;
131+ const signed = sendSigned ( keypair1 , options ) ;
132+ const tx = await sendSignedTransaction ( signed . hex ) ;
133+ console . log ( { tx} ) ;
134+
135+ async function sendSignedTransaction ( hex : string ) {
136+ debug ( 'Broadcasting signed transaction:' , signed ) ;
137+ if ( rpc && rest ) {
138+ const id = await rpc ! . sendrawtransaction ( hex ) ;
139+ await rpc ! . rescanblockchain ( ) ;
140+ const tx = await rest ! . tx ( id ) ;
141+ return tx ;
142+ } else if ( esplora ) {
143+ const id = await esplora . postTx ( hex ) ;
144+ while ( true ) {
145+ const mempool = await esplora . getMempoolTxids ( ) . then ( JSON . parse ) ;
146+ if ( mempool . includes ( id ) ) {
147+ debug ( 'TX still in mempool:' , id ) ;
148+ await sleep ( 1000 ) ;
149+ } else {
150+ return esplora . getTxInfo ( id ) ;
151+ }
152+ }
153+ } else {
154+ throw new Error ( 'need { rpc, rest } or { esplora } to broadcast signed transaction' ) ;
155+ }
156+ }
157+
158+ async function findUtxo ( address : string ) : { asset , txid , vout , amount , address } {
159+ if ( rpc ) {
160+ const unspent = await rpc . listunspent ( 0 , 9999999 , [ sender ] ) ; // TODO filter
161+ if ( ! unspent [ 0 ] ) throw new Error ( `no UTXOs for ${ sender } ` ) ;
162+ const { txid, vout, amount, asset } = unspent [ 0 ] ;
163+ return { asset, txid, vout, address, amount } ;
164+ } else if ( esplora ) {
165+ const unspent = await esplora . getAddressUtxos ( sender ) ;
166+ if ( ! unspent [ 0 ] ) throw new Error ( `no UTXOs for ${ sender } ` )
167+ const { txid, vout, value, asset } = unspent [ 0 ] ;
168+ return { asset, txid, vout, address, amount : BigInt ( value ) } ;
169+ } else {
170+ throw new Error ( 'need { rpc } or { esplora } to find unspent output' ) ;
171+ }
144172 }
145173 }
146174}
0 commit comments