@@ -178,6 +178,108 @@ mod test_online {
178178 Txid :: from_str ( txid) . expect ( "broadcast: invalid txid" )
179179 }
180180
181+ #[ test]
182+ fn test_funded_wallet_unspent_and_transactions ( ) {
183+ let ( cli, mut cmd_init, env) = setup_online_wallet ( ) ;
184+ cmd_init. assert ( ) . success ( ) ;
185+ fund_and_sync_wallet ( & cli, & env) ;
186+
187+ // unspent: exactly one confirmed, unspent 50,000,000 sat UTXO
188+ let unspent = run_wallet_json ( & cli, & [ "unspent" ] ) ;
189+ assert_eq ! (
190+ unspent[ "count" ] . as_u64( ) ,
191+ Some ( 1 ) ,
192+ "funded wallet should report exactly one UTXO, got: {unspent}"
193+ ) ;
194+
195+ let utxo = & unspent[ "items" ] [ 0 ] ;
196+ assert_eq ! (
197+ utxo[ "txout" ] [ "value" ] . as_u64( ) ,
198+ Some ( 50_000_000 ) ,
199+ "the single UTXO should equal the 0.5 BTC funding amount"
200+ ) ;
201+ assert_eq ! (
202+ utxo[ "is_spent" ] . as_bool( ) ,
203+ Some ( false ) ,
204+ "the funding UTXO must be unspent"
205+ ) ;
206+ assert ! (
207+ utxo[ "outpoint" ] . as_str( ) . is_some_and( |o| o. contains( ':' ) ) ,
208+ "UTXO outpoint should be a `txid:vout` string, got: {}" ,
209+ utxo[ "outpoint" ]
210+ ) ;
211+ assert ! (
212+ utxo[ "derivation_index" ] . is_number( ) ,
213+ "UTXO should expose a numeric derivation_index"
214+ ) ;
215+
216+ // transactions: exactly one relevant tx, funding our address
217+ let txs = run_wallet_json ( & cli, & [ "transactions" ] ) ;
218+ assert_eq ! (
219+ txs[ "count" ] . as_u64( ) ,
220+ Some ( 1 ) ,
221+ "funded wallet should report exactly one transaction, got: {txs}"
222+ ) ;
223+
224+ let tx = & txs[ "items" ] [ 0 ] ;
225+ assert_eq ! (
226+ tx[ "is_coinbase" ] . as_bool( ) ,
227+ Some ( false ) ,
228+ "the funding transaction is a normal send, not a coinbase"
229+ ) ;
230+ assert ! (
231+ tx[ "txid" ] . as_str( ) . is_some_and( |t| t. len( ) == 64 ) ,
232+ "transaction should expose a 64-char hex txid, got: {}" ,
233+ tx[ "txid" ]
234+ ) ;
235+ // The funding tx must contain the output that paid us 0.5 BTC.
236+ let outputs = tx[ "outputs" ]
237+ . as_array ( )
238+ . expect ( "transaction outputs should be a JSON array" ) ;
239+ assert ! (
240+ outputs
241+ . iter( )
242+ . any( |o| o[ "value" ] . as_u64( ) == Some ( 50_000_000 ) ) ,
243+ "funding tx should contain a 50,000,000 sat output to the wallet"
244+ ) ;
245+ }
246+
247+ #[ test]
248+ fn test_create_tx_send_all_drains_wallet ( ) {
249+ let ( cli, mut cmd_init, env) = setup_online_wallet ( ) ;
250+ cmd_init. assert ( ) . success ( ) ;
251+ fund_and_sync_wallet ( & cli, & env) ;
252+
253+ let unsigned_psbt = run_wallet_json (
254+ & cli,
255+ & [ "create_tx" , "--send_all" , "--to" , & format ! ( "{RECIPIENT}:0" ) ] ,
256+ ) [ "psbt" ]
257+ . as_str ( )
258+ . expect ( "create_tx: missing 'psbt' field" )
259+ . to_string ( ) ;
260+
261+ let ( signed_psbt, finalized) = cli_sign ( & cli, & unsigned_psbt) ;
262+ assert ! ( finalized, "drain PSBT should be finalized after signing" ) ;
263+
264+ let raw_tx = cli_extract_psbt ( & cli, & signed_psbt) ;
265+ let drain_txid = cli_broadcast ( & cli, & raw_tx) ;
266+ env. rpc_client ( )
267+ . get_mempool_entry ( & drain_txid)
268+ . expect ( "drain tx not found in node mempool" ) ;
269+
270+ env. mine_blocks ( 1 , None )
271+ . expect ( "Failed to mine drain confirmation block" ) ;
272+ env. wait_until_electrum_sees_block ( Duration :: from_secs ( 10 ) )
273+ . expect ( "Electrum did not catch up to drain confirmation" ) ;
274+
275+ cli_sync ( & cli) ;
276+ assert_eq ! (
277+ cli_balance( & cli) ,
278+ 0 ,
279+ "send_all should leave a zero confirmed balance"
280+ ) ;
281+ }
282+
181283 #[ test]
182284 fn test_full_online_transaction_lifecycle ( ) {
183285 let ( cli, mut cmd_init, env) = setup_online_wallet ( ) ;
0 commit comments