@@ -8,18 +8,31 @@ import (
88 "sync"
99 "time"
1010
11+ "bytes"
12+
1113 "github.com/btcsuite/btcd/btcutil"
14+ "github.com/btcsuite/btcd/btcutil/psbt"
15+ "github.com/lightninglabs/taproot-assets/asset"
1216 "github.com/lightninglabs/taproot-assets/tapcfg"
17+ "github.com/lightninglabs/taproot-assets/tappsbt"
1318 "github.com/lightninglabs/taproot-assets/taprpc"
19+ wrpc "github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc"
20+ "github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
1421 "github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc"
1522 "github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
1623 "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
24+ "github.com/lightninglabs/taproot-assets/taprpc/tapdevrpc"
1725 "github.com/lightninglabs/taproot-assets/taprpc/universerpc"
26+ "github.com/lightninglabs/taproot-assets/tapsend"
27+ "github.com/lightningnetwork/lnd/keychain"
1828 "github.com/lightningnetwork/lnd/lnrpc"
29+ "github.com/lightningnetwork/lnd/lnwallet/chainfee"
1930 "github.com/lightningnetwork/lnd/lnwire"
2031 "github.com/lightningnetwork/lnd/macaroons"
2132 "google.golang.org/grpc"
33+ "google.golang.org/grpc/codes"
2234 "google.golang.org/grpc/credentials"
35+ "google.golang.org/grpc/status"
2336 "gopkg.in/macaroon.v2"
2437)
2538
@@ -63,7 +76,10 @@ type TapdClient struct {
6376 tapchannelrpc.TaprootAssetChannelsClient
6477 priceoraclerpc.PriceOracleClient
6578 rfqrpc.RfqClient
79+ wrpc.AssetWalletClient
80+ mintrpc.MintClient
6681 universerpc.UniverseClient
82+ tapdevrpc.TapDevClient
6783
6884 cfg * TapdConfig
6985 assetNameCache map [string ]string
@@ -242,3 +258,231 @@ func getClientConn(config *TapdConfig) (*grpc.ClientConn, error) {
242258
243259 return conn , nil
244260}
261+
262+ // FundAndSignVpacket funds ands signs a vpacket.
263+ func (t * TapdClient ) FundAndSignVpacket (ctx context.Context ,
264+ vpkt * tappsbt.VPacket ) (* tappsbt.VPacket , error ) {
265+
266+ // Fund the packet.
267+ var buf bytes.Buffer
268+ err := vpkt .Serialize (& buf )
269+ if err != nil {
270+ return nil , err
271+ }
272+
273+ fundResp , err := t .FundVirtualPsbt (
274+ ctx , & wrpc.FundVirtualPsbtRequest {
275+ Template : & wrpc.FundVirtualPsbtRequest_Psbt {
276+ Psbt : buf .Bytes (),
277+ },
278+ },
279+ )
280+ if err != nil {
281+ return nil , err
282+ }
283+
284+ // Sign the packet.
285+ signResp , err := t .SignVirtualPsbt (
286+ ctx , & wrpc.SignVirtualPsbtRequest {
287+ FundedPsbt : fundResp .FundedPsbt ,
288+ },
289+ )
290+ if err != nil {
291+ return nil , err
292+ }
293+
294+ return tappsbt .NewFromRawBytes (
295+ bytes .NewReader (signResp .SignedPsbt ), false ,
296+ )
297+ }
298+
299+ // PrepareAndCommitVirtualPsbts prepares and commits virtual psbts.
300+ func (t * TapdClient ) PrepareAndCommitVirtualPsbts (ctx context.Context ,
301+ vpkt * tappsbt.VPacket , feeRateSatPerKVByte chainfee.SatPerVByte ) (
302+ * psbt.Packet , []* tappsbt.VPacket , []* tappsbt.VPacket ,
303+ * wrpc.CommitVirtualPsbtsResponse , error ) {
304+
305+ htlcVPackets , err := tappsbt .Encode (vpkt )
306+ if err != nil {
307+ return nil , nil , nil , nil , err
308+ }
309+
310+ htlcBtcPkt , err := tapsend .PrepareAnchoringTemplate (
311+ []* tappsbt.VPacket {vpkt },
312+ )
313+ if err != nil {
314+ return nil , nil , nil , nil , err
315+ }
316+
317+ var buf bytes.Buffer
318+ err = htlcBtcPkt .Serialize (& buf )
319+ if err != nil {
320+ return nil , nil , nil , nil , err
321+ }
322+
323+ commitResponse , err := t .AssetWalletClient .CommitVirtualPsbts (
324+ ctx , & wrpc.CommitVirtualPsbtsRequest {
325+ AnchorPsbt : buf .Bytes (),
326+ Fees : & wrpc.CommitVirtualPsbtsRequest_SatPerVbyte {
327+ SatPerVbyte : uint64 (feeRateSatPerKVByte ),
328+ },
329+ AnchorChangeOutput : & wrpc.CommitVirtualPsbtsRequest_Add {
330+ Add : true ,
331+ },
332+ VirtualPsbts : [][]byte {
333+ htlcVPackets ,
334+ },
335+ },
336+ )
337+ if err != nil {
338+ return nil , nil , nil , nil , err
339+ }
340+
341+ fundedPacket , err := psbt .NewFromRawBytes (
342+ bytes .NewReader (commitResponse .AnchorPsbt ), false ,
343+ )
344+ if err != nil {
345+ return nil , nil , nil , nil , err
346+ }
347+
348+ activePackets := make (
349+ []* tappsbt.VPacket , len (commitResponse .VirtualPsbts ),
350+ )
351+ for idx := range commitResponse .VirtualPsbts {
352+ activePackets [idx ], err = tappsbt .Decode (
353+ commitResponse .VirtualPsbts [idx ],
354+ )
355+ if err != nil {
356+ return nil , nil , nil , nil , err
357+ }
358+ }
359+
360+ passivePackets := make (
361+ []* tappsbt.VPacket , len (commitResponse .PassiveAssetPsbts ),
362+ )
363+ for idx := range commitResponse .PassiveAssetPsbts {
364+ passivePackets [idx ], err = tappsbt .Decode (
365+ commitResponse .PassiveAssetPsbts [idx ],
366+ )
367+ if err != nil {
368+ return nil , nil , nil , nil , err
369+ }
370+ }
371+
372+ return fundedPacket , activePackets , passivePackets , commitResponse , nil
373+ }
374+
375+ // LogAndPublish logs and publishes the virtual psbts.
376+ func (t * TapdClient ) LogAndPublish (ctx context.Context , btcPkt * psbt.Packet ,
377+ activeAssets []* tappsbt.VPacket , passiveAssets []* tappsbt.VPacket ,
378+ commitResp * wrpc.CommitVirtualPsbtsResponse ) (* taprpc.SendAssetResponse ,
379+ error ) {
380+
381+ var buf bytes.Buffer
382+ err := btcPkt .Serialize (& buf )
383+ if err != nil {
384+ return nil , err
385+ }
386+
387+ request := & wrpc.PublishAndLogRequest {
388+ AnchorPsbt : buf .Bytes (),
389+ VirtualPsbts : make ([][]byte , len (activeAssets )),
390+ PassiveAssetPsbts : make ([][]byte , len (passiveAssets )),
391+ ChangeOutputIndex : commitResp .ChangeOutputIndex ,
392+ LndLockedUtxos : commitResp .LndLockedUtxos ,
393+ }
394+
395+ for idx := range activeAssets {
396+ request .VirtualPsbts [idx ], err = tappsbt .Encode (
397+ activeAssets [idx ],
398+ )
399+ if err != nil {
400+ return nil , err
401+ }
402+ }
403+ for idx := range passiveAssets {
404+ request .PassiveAssetPsbts [idx ], err = tappsbt .Encode (
405+ passiveAssets [idx ],
406+ )
407+ if err != nil {
408+ return nil , err
409+ }
410+ }
411+
412+ resp , err := t .PublishAndLogTransfer (ctx , request )
413+ if err != nil {
414+ return nil , err
415+ }
416+
417+ return resp , nil
418+ }
419+
420+ // CheckBalanceById checks the balance of an asset by its id.
421+ func (t * TapdClient ) CheckBalanceById (ctx context.Context , assetId []byte ,
422+ requestedBalance btcutil.Amount ) error {
423+
424+ // Check if we have enough funds to do the swap.
425+ balanceResp , err := t .ListBalances (
426+ ctx , & taprpc.ListBalancesRequest {
427+ GroupBy : & taprpc.ListBalancesRequest_AssetId {
428+ AssetId : true ,
429+ },
430+ AssetFilter : assetId ,
431+ },
432+ )
433+ if err != nil {
434+ return err
435+ }
436+
437+ // Check if we have enough funds to do the swap.
438+ balance , ok := balanceResp .AssetBalances [hex .EncodeToString (
439+ assetId ,
440+ )]
441+ if ! ok {
442+ return status .Error (
443+ codes .Internal , "internal error" ,
444+ )
445+ }
446+ if balance .Balance < uint64 (requestedBalance ) {
447+ return status .Error (
448+ codes .Internal , "internal error" ,
449+ )
450+ }
451+
452+ return nil
453+ }
454+
455+ // DeriveNewKeys derives a new internal and script key.
456+ func (t * TapdClient ) DeriveNewKeys (ctx context.Context ) (asset.ScriptKey ,
457+ keychain.KeyDescriptor , error ) {
458+ scriptKeyDesc , err := t .NextScriptKey (
459+ ctx , & wrpc.NextScriptKeyRequest {
460+ KeyFamily : uint32 (asset .TaprootAssetsKeyFamily ),
461+ },
462+ )
463+ if err != nil {
464+ return asset.ScriptKey {}, keychain.KeyDescriptor {}, err
465+ }
466+
467+ scriptKey , err := taprpc .UnmarshalScriptKey (scriptKeyDesc .ScriptKey )
468+ if err != nil {
469+ return asset.ScriptKey {}, keychain.KeyDescriptor {}, err
470+ }
471+
472+ internalKeyDesc , err := t .NextInternalKey (
473+ ctx , & wrpc.NextInternalKeyRequest {
474+ KeyFamily : uint32 (asset .TaprootAssetsKeyFamily ),
475+ },
476+ )
477+ if err != nil {
478+ return asset.ScriptKey {}, keychain.KeyDescriptor {}, err
479+ }
480+ internalKeyLnd , err := taprpc .UnmarshalKeyDescriptor (
481+ internalKeyDesc .InternalKey ,
482+ )
483+ if err != nil {
484+ return asset.ScriptKey {}, keychain.KeyDescriptor {}, err
485+ }
486+
487+ return * scriptKey , internalKeyLnd , nil
488+ }
0 commit comments