@@ -2147,3 +2147,133 @@ func testCustomChannelsBalanceConsistency(_ context.Context,
2147
2147
assertNumAssetOutputs (t .t , charlieTap , assetID , 1 )
2148
2148
assertNumAssetOutputs (t .t , daveTap , assetID , 1 )
2149
2149
}
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