@@ -2147,3 +2147,133 @@ func testCustomChannelsBalanceConsistency(_ context.Context,
21472147 assertNumAssetOutputs (t .t , charlieTap , assetID , 1 )
21482148 assertNumAssetOutputs (t .t , daveTap , assetID , 1 )
21492149}
2150+
2151+ // testCustomChannelsMultiInput tests whether it is possible to fund a channel
2152+ // using FundChannel that uses multiple inputs from the same asset.
2153+ func testCustomChannelsMultiInput (_ context.Context , net * NetworkHarness ,
2154+ t * harnessTest ) {
2155+
2156+ ctxb := context .Background ()
2157+ lndArgs := slices .Clone (lndArgsTemplate )
2158+ litdArgs := slices .Clone (litdArgsTemplate )
2159+
2160+ zane , err := net .NewNode (
2161+ t .t , "Zane" , lndArgs , false , true , litdArgs ... ,
2162+ )
2163+ require .NoError (t .t , err )
2164+
2165+ litdArgs = append (litdArgs , fmt .Sprintf (
2166+ "--taproot-assets.proofcourieraddr=%s://%s" ,
2167+ proof .UniverseRpcCourierType , zane .Cfg .LitAddr (),
2168+ ))
2169+
2170+ charlie , err := net .NewNode (
2171+ t .t , "Charlie" , lndArgs , false , true , litdArgs ... ,
2172+ )
2173+ require .NoError (t .t , err )
2174+ dave , err := net .NewNode (t .t , "Dave" , lndArgs , false , true , litdArgs ... )
2175+ require .NoError (t .t , err )
2176+
2177+ nodes := []* HarnessNode {charlie , dave }
2178+ connectAllNodes (t .t , net , nodes )
2179+ fundAllNodes (t .t , net , nodes )
2180+
2181+ charlieTap := newTapClient (t .t , charlie )
2182+ daveTap := newTapClient (t .t , dave )
2183+
2184+ // Mint an assets on Charlie and sync Dave to Charlie as the universe.
2185+ mintedAssets := itest .MintAssetsConfirmBatch (
2186+ t .t , t .lndHarness .Miner .Client , charlieTap ,
2187+ []* mintrpc.MintAssetRequest {
2188+ {
2189+ Asset : itestAsset ,
2190+ },
2191+ },
2192+ )
2193+ cents := mintedAssets [0 ]
2194+ assetID := cents .AssetGenesis .AssetId
2195+
2196+ t .Logf ("Minted %d lightning cents, syncing universes..." ,
2197+ cents .Amount )
2198+ syncUniverses (t .t , charlieTap , dave )
2199+ t .Logf ("Universes synced between all nodes, distributing assets..." )
2200+
2201+ // Charlie should have two balance outputs with the full balance.
2202+ assertAssetBalance (t .t , charlieTap , assetID , cents .Amount )
2203+
2204+ // Send assets to Dave so he can fund a channel.
2205+ halfCentsAmount := cents .Amount / 2
2206+ daveAddr1 , err := daveTap .NewAddr (ctxb , & taprpc.NewAddrRequest {
2207+ Amt : halfCentsAmount ,
2208+ AssetId : assetID ,
2209+ ProofCourierAddr : fmt .Sprintf (
2210+ "%s://%s" , proof .UniverseRpcCourierType ,
2211+ charlieTap .node .Cfg .LitAddr (),
2212+ ),
2213+ })
2214+ require .NoError (t .t , err )
2215+ daveAddr2 , err := daveTap .NewAddr (ctxb , & taprpc.NewAddrRequest {
2216+ Amt : halfCentsAmount ,
2217+ AssetId : assetID ,
2218+ ProofCourierAddr : fmt .Sprintf (
2219+ "%s://%s" , proof .UniverseRpcCourierType ,
2220+ charlieTap .node .Cfg .LitAddr (),
2221+ ),
2222+ })
2223+ require .NoError (t .t , err )
2224+
2225+ t .Logf ("Sending %v asset units to Dave twice..." , halfCentsAmount )
2226+
2227+ // Send the first asset to Dave.
2228+ itest .AssertAddrCreated (t .t , daveTap , cents , daveAddr1 )
2229+ sendResp , err := charlieTap .SendAsset (ctxb , & taprpc.SendAssetRequest {
2230+ TapAddrs : []string {daveAddr1 .Encoded },
2231+ })
2232+ require .NoError (t .t , err )
2233+ itest .ConfirmAndAssertOutboundTransfer (
2234+ t .t , t .lndHarness .Miner .Client , charlieTap , sendResp , assetID ,
2235+ []uint64 {cents .Amount - halfCentsAmount , halfCentsAmount },
2236+ 0 , 1 ,
2237+ )
2238+ itest .AssertNonInteractiveRecvComplete (t .t , daveTap , 1 )
2239+
2240+ // Send the second asset to Dave.
2241+ itest .AssertAddrCreated (t .t , daveTap , cents , daveAddr2 )
2242+ sendResp , err = charlieTap .SendAsset (ctxb , & taprpc.SendAssetRequest {
2243+ TapAddrs : []string {daveAddr2 .Encoded },
2244+ })
2245+ require .NoError (t .t , err )
2246+ itest .ConfirmAndAssertOutboundTransfer (
2247+ t .t , t .lndHarness .Miner .Client , charlieTap , sendResp , assetID ,
2248+ []uint64 {cents .Amount - 2 * halfCentsAmount , halfCentsAmount },
2249+ 1 , 2 ,
2250+ )
2251+ itest .AssertNonInteractiveRecvComplete (t .t , daveTap , 2 )
2252+
2253+ // Fund a channel using multiple inputs from the same asset.
2254+ fundRespCD , err := daveTap .FundChannel (
2255+ ctxb , & tchrpc.FundChannelRequest {
2256+ AssetAmount : 2 * halfCentsAmount ,
2257+ AssetId : assetID ,
2258+ PeerPubkey : charlieTap .node .PubKey [:],
2259+ FeeRateSatPerVbyte : 5 ,
2260+ PushSat : 0 ,
2261+ },
2262+ )
2263+ require .NoError (t .t , err )
2264+ t .Logf ("Funded channel between Charlie and Dave: %v" , fundRespCD )
2265+
2266+ // Let's confirm the channel.
2267+ mineBlocks (t , net , 6 , 1 )
2268+
2269+ // Tapd should not report any balance for Charlie, since the asset is
2270+ // used in a funding transaction. It should also not report any balance
2271+ // for Dave. All those balances are reported through channel balances.
2272+ assertAssetBalance (t .t , charlieTap , assetID , 0 )
2273+ assertAssetBalance (t .t , daveTap , assetID , 0 )
2274+
2275+ // Make sure the channel shows the correct asset information.
2276+ assertAssetChan (
2277+ t .t , charlieTap .node , daveTap .node , 2 * halfCentsAmount , assetID ,
2278+ )
2279+ }
0 commit comments