11import {
2- Address ,
32 Amount ,
43 EsploraClient ,
54 FeeRate ,
@@ -12,20 +11,26 @@ import {
1211 TxOrdering ,
1312} from "../../../pkg/bitcoindevkit" ;
1413
14+ // Network configuration via environment variables.
15+ // Defaults to Mutinynet signet for backward compatibility.
16+ // Set ESPLORA_URL and NETWORK to override (e.g. for regtest CI).
17+ const network : Network = ( process . env . NETWORK as Network ) || "signet" ;
18+ const esploraUrl = process . env . ESPLORA_URL || "https://mutinynet.com/api" ;
19+
20+ // Expected first external address per network (same descriptor, different bech32 HRP)
21+ const expectedAddress : Record < string , string > = {
22+ signet : "tb1qkn59f87tznmmjw5nu6ng8p7k6vcur2eme637rm" ,
23+ regtest : "bcrt1qkn59f87tznmmjw5nu6ng8p7k6vcur2emmngn5j" ,
24+ } ;
25+
1526// Tests are expected to run in order
16- describe ( " Esplora client" , ( ) => {
17- const stopGap = 2 ;
18- const parallelRequests = 10 ;
27+ describe ( ` Esplora client ( ${ network } )` , ( ) => {
28+ const stopGap = 5 ;
29+ const parallelRequests = network === "regtest" ? 1 : 10 ;
1930 const externalDescriptor =
2031 "wpkh(tprv8ZgxMBicQKsPd5puBG1xsJ5V53vVPfCy2gnZfsqzmDSDjaQx8LEW4REFvrj6PQMuer7NqZeBiy9iP9ucqJZiveeEGqQ5CvcfV6SPcy8LQR7/84'/1'/0'/0/*)#jjcsy5wd" ;
2132 const internalDescriptor =
2233 "wpkh(tprv8ZgxMBicQKsPd5puBG1xsJ5V53vVPfCy2gnZfsqzmDSDjaQx8LEW4REFvrj6PQMuer7NqZeBiy9iP9ucqJZiveeEGqQ5CvcfV6SPcy8LQR7/84'/1'/0'/1/*)#rxa3ep74" ;
23- const network : Network = "signet" ;
24- const esploraUrl = "https://mutinynet.com/api" ;
25- const recipientAddress = Address . from_string (
26- "tb1qd28npep0s8frcm3y7dxqajkcy2m40eysplyr9v" ,
27- network
28- ) ;
2934 const unixTimestamp = BigInt ( Math . floor ( Date . now ( ) / 1000 ) ) ;
3035
3136 let feeRate : FeeRate ;
@@ -34,9 +39,10 @@ describe("Esplora client", () => {
3439
3540 it ( "creates a new wallet" , ( ) => {
3641 wallet = Wallet . create ( network , externalDescriptor , internalDescriptor ) ;
37- expect ( wallet . peek_address ( "external" , 0 ) . address . toString ( ) ) . toBe (
38- "tb1qkn59f87tznmmjw5nu6ng8p7k6vcur2eme637rm"
39- ) ;
42+ const addr = wallet . peek_address ( "external" , 0 ) . address . toString ( ) ;
43+ if ( expectedAddress [ network ] ) {
44+ expect ( addr ) . toBe ( expectedAddress [ network ] ) ;
45+ }
4046 } ) ;
4147
4248 it ( "performs full scan on a wallet" , async ( ) => {
@@ -57,11 +63,14 @@ describe("Esplora client", () => {
5763 const feeEstimates = await esploraClient . get_fee_estimates ( ) ;
5864
5965 const fee = feeEstimates . get ( confirmationTarget ) ;
60- expect ( fee ) . toBeDefined ( ) ;
61- feeRate = new FeeRate ( BigInt ( Math . floor ( fee ) ) ) ;
66+ // Regtest may not have meaningful fee estimates; use a floor of 1 sat/vbyte
67+ const feeValue = fee ?? 1 ;
68+ feeRate = new FeeRate ( BigInt ( Math . max ( 1 , Math . floor ( feeValue ) ) ) ) ;
6269 } ) ;
6370
6471 it ( "sends a transaction" , async ( ) => {
72+ // Send to the wallet's own address at index 5 (self-contained, works on any network)
73+ const recipientAddress = wallet . peek_address ( "external" , 5 ) ;
6574 const sendAmount = Amount . from_sat ( BigInt ( 1000 ) ) ;
6675 expect ( wallet . balance . trusted_spendable . to_sat ( ) ) . toBeGreaterThan (
6776 sendAmount . to_sat ( )
@@ -71,10 +80,12 @@ describe("Esplora client", () => {
7180 const psbt = wallet
7281 . build_tx ( )
7382 . fee_rate ( feeRate )
74- . add_recipient ( new Recipient ( recipientAddress . script_pubkey , sendAmount ) )
83+ . add_recipient (
84+ new Recipient ( recipientAddress . address . script_pubkey , sendAmount )
85+ )
7586 . finish ( ) ;
7687
77- expect ( psbt . fee ( ) . to_sat ( ) ) . toBeGreaterThan ( 100 ) ; // We cannot know the exact fees
88+ expect ( psbt . fee ( ) . to_sat ( ) ) . toBeGreaterThan ( BigInt ( 0 ) ) ;
7889
7990 const finalized = wallet . sign ( psbt , new SignOptions ( ) ) ;
8091 expect ( finalized ) . toBeTruthy ( ) ;
@@ -85,7 +96,12 @@ describe("Esplora client", () => {
8596
8697 // Assert that we are aware of newly created addresses that were revealed during PSBT creation
8798 const currentDerivationIndex = wallet . derivation_index ( "internal" ) ;
88- expect ( initialDerivationIndex ) . toBeLessThan ( currentDerivationIndex ) ;
99+ if ( initialDerivationIndex !== undefined ) {
100+ expect ( initialDerivationIndex ) . toBeLessThan ( currentDerivationIndex ) ;
101+ } else {
102+ // Fresh wallet had no internal derivation index; after building a tx with change it should exist
103+ expect ( currentDerivationIndex ) . toBeDefined ( ) ;
104+ }
89105
90106 // Assert that the transaction is in the wallet
91107 wallet . apply_unconfirmed_txs ( [ new UnconfirmedTx ( tx , unixTimestamp ) ] ) ;
@@ -108,29 +124,32 @@ describe("Esplora client", () => {
108124 } ) . toThrow ( ) ;
109125 } ) ;
110126
111- it ( "fills inputs of an output-only Psbt" , ( ) => {
112- const psbtBase64 =
113- "cHNidP8BAI4CAAAAAAM1gwEAAAAAACJRIORP1Ndiq325lSC/jMG0RlhATHYmuuULfXgEHUM3u5i4AAAAAAAAAAAxai8AAUSx+i9Igg4HWdcpyagCs8mzuRCklgA7nRMkm69rAAAAAAAAAAAAAQACAAAAACp2AAAAAAAAFgAUtOhUn8sU97k6k+amg4fW0zHBqzsAAAAAAAAAAAA=" ;
114- const template = Psbt . from_string ( psbtBase64 ) ;
127+ // PSBT template test only runs on signet (the base64 encodes signet-specific data)
128+ if ( network === "signet" ) {
129+ it ( "fills inputs of an output-only Psbt" , ( ) => {
130+ const psbtBase64 =
131+ "cHNidP8BAI4CAAAAAAM1gwEAAAAAACJRIORP1Ndiq325lSC/jMG0RlhATHYmuuULfXgEHUM3u5i4AAAAAAAAAAAxai8AAUSx+i9Igg4HWdcpyagCs8mzuRCklgA7nRMkm69rAAAAAAAAAAAAAQACAAAAACp2AAAAAAAAFgAUtOhUn8sU97k6k+amg4fW0zHBqzsAAAAAAAAAAAA=" ;
132+ const template = Psbt . from_string ( psbtBase64 ) ;
115133
116- let builder = wallet
117- . build_tx ( )
118- . fee_rate ( new FeeRate ( BigInt ( 1 ) ) )
119- . ordering ( TxOrdering . Untouched ) ;
120-
121- for ( const txout of template . unsigned_tx . output ) {
122- if ( wallet . is_mine ( txout . script_pubkey ) ) {
123- builder = builder . drain_to ( txout . script_pubkey ) ;
124- } else {
125- const recipient = new Recipient ( txout . script_pubkey , txout . value ) ;
126- builder = builder . add_recipient ( recipient ) ;
134+ let builder = wallet
135+ . build_tx ( )
136+ . fee_rate ( new FeeRate ( BigInt ( 1 ) ) )
137+ . ordering ( TxOrdering . Untouched ) ;
138+
139+ for ( const txout of template . unsigned_tx . output ) {
140+ if ( wallet . is_mine ( txout . script_pubkey ) ) {
141+ builder = builder . drain_to ( txout . script_pubkey ) ;
142+ } else {
143+ const recipient = new Recipient ( txout . script_pubkey , txout . value ) ;
144+ builder = builder . add_recipient ( recipient ) ;
145+ }
127146 }
128- }
129147
130- const psbt = builder . finish ( ) ;
131- expect ( psbt . unsigned_tx . output ) . toHaveLength (
132- template . unsigned_tx . output . length
133- ) ;
134- expect ( psbt . unsigned_tx . tx_out ( 2 ) . value . to_btc ( ) ) . toBeGreaterThan ( 0 ) ;
135- } ) ;
148+ const psbt = builder . finish ( ) ;
149+ expect ( psbt . unsigned_tx . output ) . toHaveLength (
150+ template . unsigned_tx . output . length
151+ ) ;
152+ expect ( psbt . unsigned_tx . tx_out ( 2 ) . value . to_btc ( ) ) . toBeGreaterThan ( 0 ) ;
153+ } ) ;
154+ }
136155} ) ;
0 commit comments