diff --git a/assets/client.go b/assets/client.go index 88c23efe5..95052c7bc 100644 --- a/assets/client.go +++ b/assets/client.go @@ -1,6 +1,7 @@ package assets import ( + "bytes" "context" "encoding/hex" "fmt" @@ -9,19 +10,38 @@ import ( "time" "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/btcutil/psbt" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcwallet/wtxmgr" + "github.com/lightninglabs/lndclient" + tap "github.com/lightninglabs/taproot-assets" + "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightninglabs/taproot-assets/proof" "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightninglabs/taproot-assets/rpcutils" "github.com/lightninglabs/taproot-assets/tapcfg" + "github.com/lightninglabs/taproot-assets/tapfreighter" + "github.com/lightninglabs/taproot-assets/tappsbt" "github.com/lightninglabs/taproot-assets/taprpc" + "github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc" "github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc" "github.com/lightninglabs/taproot-assets/taprpc/rfqrpc" "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc" "github.com/lightninglabs/taproot-assets/taprpc/universerpc" + "github.com/lightninglabs/taproot-assets/tapsend" + "github.com/lightninglabs/taproot-assets/universe" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lnwallet/btcwallet" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/macaroons" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/status" "gopkg.in/macaroon.v2" ) @@ -29,7 +49,7 @@ var ( // maxMsgRecvSize is the largest message our client will receive. We // set this to 200MiB atm. - maxMsgRecvSize = grpc.MaxCallRecvMsgSize(1 * 1024 * 1024 * 200) + maxMsgRecvSize = grpc.MaxCallRecvMsgSize(200 * 1024 * 1024) // defaultRfqTimeout is the default timeout we wait for tapd peer to // accept RFQ. @@ -66,6 +86,7 @@ type TapdClient struct { priceoraclerpc.PriceOracleClient rfqrpc.RfqClient universerpc.UniverseClient + assetwalletrpc.AssetWalletClient cfg *TapdConfig assetNameCache map[string]string @@ -73,6 +94,43 @@ type TapdClient struct { cc *grpc.ClientConn } +func getClientConn(config *TapdConfig) (*grpc.ClientConn, error) { + // Load the specified TLS certificate and build transport credentials. + creds, err := credentials.NewClientTLSFromFile(config.TLSPath, "") + if err != nil { + return nil, err + } + + // Load the specified macaroon file. + macBytes, err := os.ReadFile(config.MacaroonPath) + if err != nil { + return nil, err + } + mac := &macaroon.Macaroon{} + if err := mac.UnmarshalBinary(macBytes); err != nil { + return nil, err + } + + macaroon, err := macaroons.NewMacaroonCredential(mac) + if err != nil { + return nil, err + } + // Create the DialOptions with the macaroon credentials. + opts := []grpc.DialOption{ + grpc.WithTransportCredentials(creds), + grpc.WithPerRPCCredentials(macaroon), + grpc.WithDefaultCallOptions(maxMsgRecvSize), + } + + // Dial the gRPC server. + conn, err := grpc.Dial(config.Host, opts...) + if err != nil { + return nil, err + } + + return conn, nil +} + // NewTapdClient returns a new taproot assets client. func NewTapdClient(config *TapdConfig) (*TapdClient, error) { // Create the client connection to the server. @@ -91,6 +149,7 @@ func NewTapdClient(config *TapdConfig) (*TapdClient, error) { PriceOracleClient: priceoraclerpc.NewPriceOracleClient(conn), RfqClient: rfqrpc.NewRfqClient(conn), UniverseClient: universerpc.NewUniverseClient(conn), + AssetWalletClient: assetwalletrpc.NewAssetWalletClient(conn), } return client, nil @@ -220,13 +279,15 @@ func (c *TapdClient) GetAssetPrice(ctx context.Context, assetID string, } if rfq.GetInvalidQuote() != nil { - return 0, fmt.Errorf("peer %v sent an invalid quote response %v for "+ - "asset %v", peerPubkey, rfq.GetInvalidQuote(), assetID) + return 0, fmt.Errorf("peer %v sent an invalid quote response "+ + "%v for asset %v", peerPubkey, rfq.GetInvalidQuote(), + assetID) } if rfq.GetRejectedQuote() != nil { return 0, fmt.Errorf("peer %v rejected the quote request for "+ - "asset %v, %v", peerPubkey, assetID, rfq.GetRejectedQuote()) + "asset %v, %v", peerPubkey, assetID, + rfq.GetRejectedQuote()) } acceptedRes := rfq.GetAcceptedQuote() @@ -255,6 +316,435 @@ func getSatsFromAssetAmt(assetAmt uint64, assetRate *rfqrpc.FixedPoint) ( return msatAmt.ToSatoshis(), nil } +// FundAndSignVpacket funds and signs a vpacket. +func (t *TapdClient) FundAndSignVpacket(ctx context.Context, + vpkt *tappsbt.VPacket) (*tappsbt.VPacket, error) { + + // Fund the packet. + var buf bytes.Buffer + err := vpkt.Serialize(&buf) + if err != nil { + return nil, err + } + + fundResp, err := t.FundVirtualPsbt( + ctx, &assetwalletrpc.FundVirtualPsbtRequest{ + Template: &assetwalletrpc.FundVirtualPsbtRequest_Psbt{ + Psbt: buf.Bytes(), + }, + }, + ) + if err != nil { + return nil, err + } + + // Sign the packet. + signResp, err := t.SignVirtualPsbt( + ctx, &assetwalletrpc.SignVirtualPsbtRequest{ + FundedPsbt: fundResp.FundedPsbt, + }, + ) + if err != nil { + return nil, err + } + + return tappsbt.NewFromRawBytes( + bytes.NewReader(signResp.SignedPsbt), false, + ) +} + +// addP2WPKHOutputToPsbt adds a normal bitcoin P2WPKH output to a psbt for the +// given key and amount. +func addP2WPKHOutputToPsbt(packet *psbt.Packet, keyDesc keychain.KeyDescriptor, + amount btcutil.Amount, params *chaincfg.Params) error { + + derivation, _, _ := btcwallet.Bip32DerivationFromKeyDesc( + keyDesc, params.HDCoinType, + ) + + // Convert to Bitcoin address. + pubKeyBytes := keyDesc.PubKey.SerializeCompressed() + pubKeyHash := btcutil.Hash160(pubKeyBytes) + address, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, params) + if err != nil { + return err + } + + // Generate the P2WPKH scriptPubKey. + scriptPubKey, err := txscript.PayToAddrScript(address) + if err != nil { + return err + } + + // Add the output to the packet. + packet.UnsignedTx.AddTxOut( + wire.NewTxOut(int64(amount), scriptPubKey), + ) + + packet.Outputs = append(packet.Outputs, psbt.POutput{ + Bip32Derivation: []*psbt.Bip32Derivation{ + derivation, + }, + }) + + return nil +} + +// PrepareAndCommitVirtualPsbts prepares and commits virtual psbt to a BTC +// template so that the underlying wallet can fund the transaction and add the +// necessary additional input to pay for fees as well as a change output if the +// change keydescriptor is not provided. +func (t *TapdClient) PrepareAndCommitVirtualPsbts(ctx context.Context, + vpkt *tappsbt.VPacket, feeRateSatPerVByte chainfee.SatPerVByte, + changeKeyDesc *keychain.KeyDescriptor, params *chaincfg.Params, + sponsoringInputs []lndclient.LeaseDescriptor, + customLockID *wtxmgr.LockID, lockExpiration time.Duration) ( + *psbt.Packet, []*tappsbt.VPacket, []*tappsbt.VPacket, + *assetwalletrpc.CommitVirtualPsbtsResponse, error) { + + encodedVpkt, err := tappsbt.Encode(vpkt) + if err != nil { + return nil, nil, nil, nil, err + } + + btcPkt, err := tapsend.PrepareAnchoringTemplate( + []*tappsbt.VPacket{vpkt}, + ) + if err != nil { + return nil, nil, nil, nil, err + } + + for _, lease := range sponsoringInputs { + btcPkt.UnsignedTx.TxIn = append( + btcPkt.UnsignedTx.TxIn, &wire.TxIn{ + PreviousOutPoint: lease.Outpoint, + }, + ) + + btcPkt.Inputs = append(btcPkt.Inputs, psbt.PInput{ + WitnessUtxo: wire.NewTxOut( + int64(lease.Value), + lease.PkScript, + ), + }) + } + + commitRequest := &assetwalletrpc.CommitVirtualPsbtsRequest{ + Fees: &assetwalletrpc.CommitVirtualPsbtsRequest_SatPerVbyte{ + SatPerVbyte: uint64(feeRateSatPerVByte), + }, + AnchorChangeOutput: &assetwalletrpc.CommitVirtualPsbtsRequest_Add{ //nolint:lll + Add: true, + }, + VirtualPsbts: [][]byte{ + encodedVpkt, + }, + LockExpirationSeconds: uint64(lockExpiration.Seconds()), + } + + if customLockID != nil { + commitRequest.CustomLockId = (*customLockID)[:] + } + + if feeRateSatPerVByte == 0 { + commitRequest.SkipFunding = true + } + + if changeKeyDesc != nil { + err := addP2WPKHOutputToPsbt( + btcPkt, *changeKeyDesc, btcutil.Amount(1), params, + ) + if err != nil { + return nil, nil, nil, nil, err + } + + commitRequest.AnchorChangeOutput = + &assetwalletrpc.CommitVirtualPsbtsRequest_ExistingOutputIndex{ //nolint:lll + ExistingOutputIndex: 1, + } + } else { + commitRequest.AnchorChangeOutput = + &assetwalletrpc.CommitVirtualPsbtsRequest_Add{ + Add: true, + } + } + var buf bytes.Buffer + err = btcPkt.Serialize(&buf) + if err != nil { + return nil, nil, nil, nil, err + } + + commitRequest.AnchorPsbt = buf.Bytes() + + commitResponse, err := t.AssetWalletClient.CommitVirtualPsbts( + ctx, commitRequest, + ) + if err != nil { + return nil, nil, nil, nil, err + } + + fundedPacket, err := psbt.NewFromRawBytes( + bytes.NewReader(commitResponse.AnchorPsbt), false, + ) + if err != nil { + return nil, nil, nil, nil, err + } + + activePackets := make( + []*tappsbt.VPacket, len(commitResponse.VirtualPsbts), + ) + for idx := range commitResponse.VirtualPsbts { + activePackets[idx], err = tappsbt.Decode( + commitResponse.VirtualPsbts[idx], + ) + if err != nil { + return nil, nil, nil, nil, err + } + } + + passivePackets := make( + []*tappsbt.VPacket, len(commitResponse.PassiveAssetPsbts), + ) + for idx := range commitResponse.PassiveAssetPsbts { + passivePackets[idx], err = tappsbt.Decode( + commitResponse.PassiveAssetPsbts[idx], + ) + if err != nil { + return nil, nil, nil, nil, err + } + } + + return fundedPacket, activePackets, passivePackets, commitResponse, nil +} + +// LogAndPublish logs and publishes a psbt with the given active and passive +// assets. +func (t *TapdClient) LogAndPublish(ctx context.Context, btcPkt *psbt.Packet, + activeAssets []*tappsbt.VPacket, passiveAssets []*tappsbt.VPacket, + commitResp *assetwalletrpc.CommitVirtualPsbtsResponse, + skipBoradcast bool) (*taprpc.SendAssetResponse, error) { + + var buf bytes.Buffer + err := btcPkt.Serialize(&buf) + if err != nil { + return nil, err + } + + request := &assetwalletrpc.PublishAndLogRequest{ + AnchorPsbt: buf.Bytes(), + VirtualPsbts: make([][]byte, len(activeAssets)), + PassiveAssetPsbts: make([][]byte, len(passiveAssets)), + ChangeOutputIndex: commitResp.ChangeOutputIndex, + LndLockedUtxos: commitResp.LndLockedUtxos, + SkipAnchorTxBroadcast: skipBoradcast, + } + + for idx := range activeAssets { + request.VirtualPsbts[idx], err = tappsbt.Encode( + activeAssets[idx], + ) + if err != nil { + return nil, err + } + } + for idx := range passiveAssets { + request.PassiveAssetPsbts[idx], err = tappsbt.Encode( + passiveAssets[idx], + ) + if err != nil { + return nil, err + } + } + + resp, err := t.PublishAndLogTransfer(ctx, request) + if err != nil { + return nil, err + } + + return resp, nil +} + +// GetAssetBalance checks the balance of an asset by its ID. +func (t *TapdClient) GetAssetBalance(ctx context.Context, assetId []byte) ( + uint64, error) { + + // Check if we have enough funds to do the swap. + balanceResp, err := t.ListBalances( + ctx, &taprpc.ListBalancesRequest{ + GroupBy: &taprpc.ListBalancesRequest_AssetId{ + AssetId: true, + }, + AssetFilter: assetId, + }, + ) + if err != nil { + return 0, err + } + + // Check if we have enough funds to do the swap. + balance, ok := balanceResp.AssetBalances[hex.EncodeToString( + assetId, + )] + if !ok { + return 0, status.Error(codes.Internal, "internal error") + } + + return balance.Balance, nil +} + +// GetUnEncumberedAssetBalance returns the total balance of the given asset for +// which the given client owns the script keys. +func (t *TapdClient) GetUnEncumberedAssetBalance(ctx context.Context, + assetID []byte) (uint64, error) { + + allAssets, err := t.ListAssets(ctx, &taprpc.ListAssetRequest{}) + if err != nil { + return 0, err + } + + var balance uint64 + for _, a := range allAssets.Assets { + // Only count assets from the given asset ID. + if !bytes.Equal(a.AssetGenesis.AssetId, assetID) { + continue + } + + // Non-local means we don't have the internal key to spend the + // asset. + if !a.ScriptKeyIsLocal { + continue + } + + // If the asset is not declared known or has a script path, we + // can't spend it directly. + if !a.ScriptKeyDeclaredKnown || a.ScriptKeyHasScriptPath { + continue + } + + balance += a.Amount + } + + return balance, nil +} + +// DeriveNewKeys derives a new internal and script key. +func (t *TapdClient) DeriveNewKeys(ctx context.Context) (asset.ScriptKey, + keychain.KeyDescriptor, error) { + + scriptKeyDesc, err := t.NextScriptKey( + ctx, &assetwalletrpc.NextScriptKeyRequest{ + KeyFamily: uint32(asset.TaprootAssetsKeyFamily), + }, + ) + if err != nil { + return asset.ScriptKey{}, keychain.KeyDescriptor{}, err + } + + scriptKey, err := rpcutils.UnmarshalScriptKey(scriptKeyDesc.ScriptKey) + if err != nil { + return asset.ScriptKey{}, keychain.KeyDescriptor{}, err + } + + internalKeyDesc, err := t.NextInternalKey( + ctx, &assetwalletrpc.NextInternalKeyRequest{ + KeyFamily: uint32(asset.TaprootAssetsKeyFamily), + }, + ) + if err != nil { + return asset.ScriptKey{}, keychain.KeyDescriptor{}, err + } + internalKeyLnd, err := rpcutils.UnmarshalKeyDescriptor( + internalKeyDesc.InternalKey, + ) + if err != nil { + return asset.ScriptKey{}, keychain.KeyDescriptor{}, err + } + + return *scriptKey, internalKeyLnd, nil +} + +// ImportProof inserts the given proof to the local tapd instance's database. +func (t *TapdClient) ImportProof(ctx context.Context, p *proof.Proof) error { + var proofBytes bytes.Buffer + err := p.Encode(&proofBytes) + if err != nil { + return err + } + + asset := p.Asset + + proofType := universe.ProofTypeTransfer + if asset.IsGenesisAsset() { + proofType = universe.ProofTypeIssuance + } + + uniID := universe.Identifier{ + AssetID: asset.ID(), + ProofType: proofType, + } + if asset.GroupKey != nil { + uniID.GroupKey = &asset.GroupKey.GroupPubKey + } + + rpcUniID, err := tap.MarshalUniID(uniID) + if err != nil { + return err + } + + outpoint := &universerpc.Outpoint{ + HashStr: p.AnchorTx.TxHash().String(), + Index: int32(p.InclusionProof.OutputIndex), + } + + scriptKey := p.Asset.ScriptKey.PubKey + leafKey := &universerpc.AssetKey{ + Outpoint: &universerpc.AssetKey_Op{ + Op: outpoint, + }, + ScriptKey: &universerpc.AssetKey_ScriptKeyBytes{ + ScriptKeyBytes: scriptKey.SerializeCompressed(), + }, + } + + _, err = t.InsertProof(ctx, &universerpc.AssetProof{ + Key: &universerpc.UniverseKey{ + Id: rpcUniID, + LeafKey: leafKey, + }, + AssetLeaf: &universerpc.AssetLeaf{ + Proof: proofBytes.Bytes(), + }, + }) + + return err +} + +// ImportProofFile imports the proof file and returns the last proof. +func (t *TapdClient) ImportProofFile(ctx context.Context, rawProofFile []byte) ( + *proof.Proof, error) { + + proofFile, err := proof.DecodeFile(rawProofFile) + if err != nil { + return nil, err + } + + var lastProof *proof.Proof + + for i := 0; i < proofFile.NumProofs(); i++ { + lastProof, err = proofFile.ProofAt(uint32(i)) + if err != nil { + return nil, err + } + + err = t.ImportProof(ctx, lastProof) + if err != nil { + return nil, err + } + } + + return lastProof, nil +} + // getPaymentMaxAmount returns the milisat amount we are willing to pay for the // payment. func getPaymentMaxAmount(satAmount btcutil.Amount, feeLimitMultiplier float64) ( @@ -277,39 +767,147 @@ func getPaymentMaxAmount(satAmount btcutil.Amount, feeLimitMultiplier float64) ( ) } -func getClientConn(config *TapdConfig) (*grpc.ClientConn, error) { - // Load the specified TLS certificate and build transport credentials. - creds, err := credentials.NewClientTLSFromFile(config.TLSPath, "") - if err != nil { - return nil, err - } +// TapReceiveEvent is a struct that holds the information about a receive event. +type TapReceiveEvent struct { + // Outpoint is the anchor outpoint containing the confirmed asset. + Outpoint wire.OutPoint - // Load the specified macaroon file. - macBytes, err := os.ReadFile(config.MacaroonPath) + // ConfirmationHeight is the height at which the asset transfer was + // confirmed. + ConfirmationHeight uint32 +} + +// WaitForReceiveComplete waits for a receive to complete returning a channel +// that will notify the caller when the receive is complete. The addr is +// the address to filter for, and startTs is the timestamp from which to +// start receiving events. +func (t *TapdClient) WaitForReceiveComplete(ctx context.Context, addr string, + startTs time.Time) (<-chan TapReceiveEvent, <-chan error, error) { + + receiveEventsClient, err := t.SubscribeReceiveEvents( + ctx, &taprpc.SubscribeReceiveEventsRequest{ + FilterAddr: addr, + StartTimestamp: startTs.UnixMicro(), + }, + ) if err != nil { - return nil, err + return nil, nil, err } - mac := &macaroon.Macaroon{} - if err := mac.UnmarshalBinary(macBytes); err != nil { - return nil, err + + resChan := make(chan TapReceiveEvent) + errChan := make(chan error, 1) + + go func() { + for { + select { + case <-receiveEventsClient.Context().Done(): + panic(receiveEventsClient.Context().Err()) + default: + } + event, err := receiveEventsClient.Recv() + if err != nil { + errChan <- err + + return + } + + done, err := handleReceiveEvent(event, resChan) + if err != nil { + errChan <- err + + return + } + + if done { + return + } + } + }() + + return resChan, errChan, err +} + +func handleReceiveEvent(event *taprpc.ReceiveEvent, + resChan chan<- TapReceiveEvent) (bool, error) { + + switch event.Status { + case taprpc.AddrEventStatus_ADDR_EVENT_STATUS_TRANSACTION_DETECTED: + + case taprpc.AddrEventStatus_ADDR_EVENT_STATUS_TRANSACTION_CONFIRMED: + + case taprpc.AddrEventStatus_ADDR_EVENT_STATUS_COMPLETED: + outpoint, err := wire.NewOutPointFromString(event.Outpoint) + if err != nil { + return false, err + } + + resChan <- TapReceiveEvent{ + Outpoint: *outpoint, + ConfirmationHeight: event.ConfirmationHeight, + } + + return true, nil + + default: } - macaroon, err := macaroons.NewMacaroonCredential(mac) + return false, nil +} + +// TapSendEvent is a struct that holds the information about a send event. +type TapSendEvent struct { + Transfer *taprpc.AssetTransfer +} + +// WaitForSendComplete waits for a send to complete returning a channel that +// will notify the caller when the send is complete. The filterScriptKey is +// the script key of the asset to filter for, and the filterLabel is an +// optional label to filter the send events by. +func (t *TapdClient) WaitForSendComplete(ctx context.Context, + filterScriptKey []byte, filterLabel string) (<-chan TapSendEvent, + <-chan error, error) { + + sendEventsClient, err := t.SubscribeSendEvents( + ctx, &taprpc.SubscribeSendEventsRequest{ + FilterScriptKey: filterScriptKey, + FilterLabel: filterLabel, + }, + ) if err != nil { - return nil, err - } - // Create the DialOptions with the macaroon credentials. - opts := []grpc.DialOption{ - grpc.WithTransportCredentials(creds), - grpc.WithPerRPCCredentials(macaroon), - grpc.WithDefaultCallOptions(maxMsgRecvSize), + return nil, nil, err } - // Dial the gRPC server. - conn, err := grpc.Dial(config.Host, opts...) - if err != nil { - return nil, err + resChan := make(chan TapSendEvent) + errChan := make(chan error, 1) + + go func() { + for { + event, err := sendEventsClient.Recv() + if err != nil { + errChan <- err + + return + } + + if handleSendEvent(event, resChan) { + return + } + } + }() + + return resChan, errChan, nil +} + +func handleSendEvent(event *taprpc.SendEvent, + resChan chan<- TapSendEvent) bool { + + if event.SendState == tapfreighter.SendStateComplete.String() { + resChan <- TapSendEvent{ + Transfer: event.Transfer, + } + + return true } - return conn, nil + return false } diff --git a/assets/htlc/script.go b/assets/htlc/script.go new file mode 100644 index 000000000..9ce7066ba --- /dev/null +++ b/assets/htlc/script.go @@ -0,0 +1,96 @@ +package htlc + +import ( + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/txscript" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" +) + +// GenSuccessPathScript constructs a script for the success path of the HTLC +// payment. Optionally includes a CHECKSEQUENCEVERIFY (CSV) of 1 if `csv` is +// true, to prevent potential pinning attacks when the HTLC is not part of a +// package relay. +func GenSuccessPathScript(receiverHtlcKey *btcec.PublicKey, + swapHash lntypes.Hash, csv bool) ([]byte, error) { + + builder := txscript.NewScriptBuilder() + + builder.AddData(schnorr.SerializePubKey(receiverHtlcKey)) + builder.AddOp(txscript.OP_CHECKSIGVERIFY) + builder.AddOp(txscript.OP_SIZE) + builder.AddInt64(32) + builder.AddOp(txscript.OP_EQUALVERIFY) + builder.AddOp(txscript.OP_HASH160) + builder.AddData(input.Ripemd160H(swapHash[:])) + builder.AddOp(txscript.OP_EQUALVERIFY) + + if csv { + builder.AddInt64(1) + builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY) + } + + return builder.Script() +} + +// GenTimeoutPathScript constructs an HtlcScript for the timeout payment path. +func GenTimeoutPathScript(senderHtlcKey *btcec.PublicKey, csvExpiry int64) ( + []byte, error) { + + builder := txscript.NewScriptBuilder() + builder.AddData(schnorr.SerializePubKey(senderHtlcKey)) + builder.AddOp(txscript.OP_CHECKSIGVERIFY) + builder.AddInt64(csvExpiry) + builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY) + return builder.Script() +} + +// GetOpTrueScript returns a script that always evaluates to true. +func GetOpTrueScript() ([]byte, error) { + return txscript.NewScriptBuilder().AddOp(txscript.OP_TRUE).Script() +} + +// CreateOpTrueLeaf creates a taproot leaf that always evaluates to true. +func CreateOpTrueLeaf() (asset.ScriptKey, txscript.TapLeaf, + *txscript.IndexedTapScriptTree, *txscript.ControlBlock, error) { + + // Create the taproot OP_TRUE script. + tapScript, err := GetOpTrueScript() + if err != nil { + return asset.ScriptKey{}, txscript.TapLeaf{}, nil, nil, err + } + + tapLeaf := txscript.NewBaseTapLeaf(tapScript) + tree := txscript.AssembleTaprootScriptTree(tapLeaf) + rootHash := tree.RootNode.TapHash() + tapKey := txscript.ComputeTaprootOutputKey( + asset.NUMSPubKey, rootHash[:], + ) + + merkleRootHash := tree.RootNode.TapHash() + + controlBlock := &txscript.ControlBlock{ + LeafVersion: txscript.BaseLeafVersion, + InternalKey: asset.NUMSPubKey, + } + tapScriptKey := asset.ScriptKey{ + PubKey: tapKey, + TweakedScriptKey: &asset.TweakedScriptKey{ + RawKey: keychain.KeyDescriptor{ + PubKey: asset.NUMSPubKey, + }, + Tweak: merkleRootHash[:], + }, + } + if tapKey.SerializeCompressed()[0] == + secp256k1.PubKeyFormatCompressedOdd { + + controlBlock.OutputKeyYIsOdd = true + } + + return tapScriptKey, tapLeaf, tree, controlBlock, nil +} diff --git a/assets/htlc/swapkit.go b/assets/htlc/swapkit.go new file mode 100644 index 000000000..0724d7ff9 --- /dev/null +++ b/assets/htlc/swapkit.go @@ -0,0 +1,465 @@ +package htlc + +import ( + "context" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/btcutil/psbt" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/lightninglabs/lndclient" + "github.com/lightninglabs/taproot-assets/address" + "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightninglabs/taproot-assets/commitment" + "github.com/lightninglabs/taproot-assets/proof" + "github.com/lightninglabs/taproot-assets/tappsbt" + "github.com/lightninglabs/taproot-assets/tapscript" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" +) + +// SwapKit holds information needed to facilitate an on-chain asset to offchain +// bitcoin atomic swap. The keys within the struct are the public keys of the +// sender and receiver that will be used to create the on-chain HTLC. +type SwapKit struct { + // SenderPubKey is the public key of the sender for the joint key + // that will be used to create the HTLC. + SenderPubKey *btcec.PublicKey + + // ReceiverPubKey is the public key of the receiver that will be used to + // create the HTLC. + ReceiverPubKey *btcec.PublicKey + + // AssetID is the identifier of the asset that will be swapped. + AssetID []byte + + // Amount is the amount of the asset that will be swapped. Note that + // we use btcutil.Amount here for simplicity, but the actual amount + // is in the asset's native unit. + Amount btcutil.Amount + + // SwapHash is the hash of the preimage in the swap HTLC. + SwapHash lntypes.Hash + + // CsvExpiry is the relative timelock in blocks for the swap. + CsvExpiry uint32 + + // AddressParams is the chain parameters of the chain the deposit is + // being created on. + AddressParams *address.ChainParams + + // CheckCSV indicates whether the success path script should include a + // CHECKSEQUENCEVERIFY check. This is used to prevent potential pinning + // attacks when the HTLC is not part of a package relay. + CheckCSV bool +} + +// GetSuccessScript returns the success path script of the swap HTLC. +func (s *SwapKit) GetSuccessScript() ([]byte, error) { + return GenSuccessPathScript(s.ReceiverPubKey, s.SwapHash, s.CheckCSV) +} + +// GetTimeoutScript returns the timeout path script of the swap HTLC. +func (s *SwapKit) GetTimeoutScript() ([]byte, error) { + return GenTimeoutPathScript(s.SenderPubKey, int64(s.CsvExpiry)) +} + +// GetAggregateKey returns the aggregate MuSig2 key used in the swap HTLC. +func (s *SwapKit) GetAggregateKey() (*btcec.PublicKey, error) { + aggregateKey, err := input.MuSig2CombineKeys( + input.MuSig2Version100RC2, + []*btcec.PublicKey{ + s.SenderPubKey, s.ReceiverPubKey, + }, + true, + &input.MuSig2Tweaks{}, + ) + if err != nil { + return nil, err + } + + return aggregateKey.PreTweakedKey, nil +} + +// GetTimeOutLeaf returns the timeout leaf of the swap. +func (s *SwapKit) GetTimeOutLeaf() (txscript.TapLeaf, error) { + timeoutScript, err := s.GetTimeoutScript() + if err != nil { + return txscript.TapLeaf{}, err + } + + timeoutLeaf := txscript.NewBaseTapLeaf(timeoutScript) + + return timeoutLeaf, nil +} + +// GetSuccessLeaf returns the success leaf of the swap. +func (s *SwapKit) GetSuccessLeaf() (txscript.TapLeaf, error) { + successScript, err := s.GetSuccessScript() + if err != nil { + return txscript.TapLeaf{}, err + } + + successLeaf := txscript.NewBaseTapLeaf(successScript) + + return successLeaf, nil +} + +// GetSiblingPreimage returns the sibling preimage of the HTLC bitcoin top level +// output. +func (s *SwapKit) GetSiblingPreimage() (commitment.TapscriptPreimage, error) { + timeOutLeaf, err := s.GetTimeOutLeaf() + if err != nil { + return commitment.TapscriptPreimage{}, err + } + + successLeaf, err := s.GetSuccessLeaf() + if err != nil { + return commitment.TapscriptPreimage{}, err + } + + branch := txscript.NewTapBranch(timeOutLeaf, successLeaf) + + siblingPreimage := commitment.NewPreimageFromBranch(branch) + + return siblingPreimage, nil +} + +// CreateHtlcVpkt creates the vpacket for the HTLC. +func (s *SwapKit) CreateHtlcVpkt() (*tappsbt.VPacket, error) { + assetId := asset.ID{} + copy(assetId[:], s.AssetID) + + btcInternalKey, err := s.GetAggregateKey() + if err != nil { + return nil, err + } + + siblingPreimage, err := s.GetSiblingPreimage() + if err != nil { + return nil, err + } + + tapScriptKey, _, _, _, err := CreateOpTrueLeaf() + if err != nil { + return nil, err + } + + pkt := &tappsbt.VPacket{ + Inputs: []*tappsbt.VInput{{ + PrevID: asset.PrevID{ + ID: assetId, + }, + }}, + Outputs: make([]*tappsbt.VOutput, 0, 2), + ChainParams: s.AddressParams, + Version: tappsbt.V1, + } + pkt.Outputs = append(pkt.Outputs, &tappsbt.VOutput{ + Amount: 0, + Type: tappsbt.TypeSplitRoot, + AnchorOutputIndex: 0, + ScriptKey: asset.NUMSScriptKey, + }) + pkt.Outputs = append(pkt.Outputs, &tappsbt.VOutput{ + AssetVersion: asset.V1, + Amount: uint64(s.Amount), + AnchorOutputIndex: 1, + ScriptKey: asset.NewScriptKey( + tapScriptKey.PubKey, + ), + AnchorOutputInternalKey: btcInternalKey, + AnchorOutputTapscriptSibling: &siblingPreimage, + }) + + return pkt, nil +} + +// GenTimeoutBtcControlBlock generates the control block for the timeout path of +// the swap. +func (s *SwapKit) GenTimeoutBtcControlBlock(taprootAssetRoot []byte) ( + *txscript.ControlBlock, error) { + + internalKey, err := s.GetAggregateKey() + if err != nil { + return nil, err + } + + successLeaf, err := s.GetSuccessLeaf() + if err != nil { + return nil, err + } + + successLeafHash := successLeaf.TapHash() + + btcControlBlock := &txscript.ControlBlock{ + InternalKey: internalKey, + LeafVersion: txscript.BaseLeafVersion, + InclusionProof: append( + successLeafHash[:], taprootAssetRoot..., + ), + } + + timeoutPathScript, err := s.GetTimeoutScript() + if err != nil { + return nil, err + } + + rootHash := btcControlBlock.RootHash(timeoutPathScript) + tapKey := txscript.ComputeTaprootOutputKey(internalKey, rootHash) + if tapKey.SerializeCompressed()[0] == + secp256k1.PubKeyFormatCompressedOdd { + + btcControlBlock.OutputKeyYIsOdd = true + } + + return btcControlBlock, nil +} + +// GenSuccessBtcControlBlock generates the control block for the timeout path of +// the swap. +func (s *SwapKit) GenSuccessBtcControlBlock(taprootAssetRoot []byte) ( + *txscript.ControlBlock, error) { + + internalKey, err := s.GetAggregateKey() + if err != nil { + return nil, err + } + + timeOutLeaf, err := s.GetTimeOutLeaf() + if err != nil { + return nil, err + } + + timeOutLeafHash := timeOutLeaf.TapHash() + + btcControlBlock := &txscript.ControlBlock{ + InternalKey: internalKey, + LeafVersion: txscript.BaseLeafVersion, + InclusionProof: append( + timeOutLeafHash[:], taprootAssetRoot..., + ), + } + + successPathScript, err := s.GetSuccessScript() + if err != nil { + return nil, err + } + + rootHash := btcControlBlock.RootHash(successPathScript) + tapKey := txscript.ComputeTaprootOutputKey(internalKey, rootHash) + if tapKey.SerializeCompressed()[0] == + secp256k1.PubKeyFormatCompressedOdd { + + btcControlBlock.OutputKeyYIsOdd = true + } + + return btcControlBlock, nil +} + +// GenTaprootAssetRootFromProof generates the taproot asset root from the proof +// of the swap. +func GenTaprootAssetRootFromProof(proof *proof.Proof) ([]byte, error) { + assetCopy := proof.Asset.CopySpendTemplate() + + version := commitment.TapCommitmentV2 + assetCommitment, err := commitment.FromAssets( + &version, assetCopy, + ) + if err != nil { + return nil, err + } + + assetCommitment, err = commitment.TrimSplitWitnesses( + &version, assetCommitment, + ) + if err != nil { + return nil, err + } + + taprootAssetRoot := assetCommitment.TapscriptRoot(nil) + + return taprootAssetRoot[:], nil +} + +// GetPkScriptFromAsset returns the toplevel bitcoin script with the given +// asset. +func (s *SwapKit) GetPkScriptFromAsset(asset *asset.Asset) ([]byte, error) { + assetCopy := asset.CopySpendTemplate() + + version := commitment.TapCommitmentV2 + assetCommitment, err := commitment.FromAssets( + &version, assetCopy, + ) + if err != nil { + return nil, err + } + + assetCommitment, err = commitment.TrimSplitWitnesses( + &version, assetCommitment, + ) + if err != nil { + return nil, err + } + + siblingPreimage, err := s.GetSiblingPreimage() + if err != nil { + return nil, err + } + + siblingHash, err := siblingPreimage.TapHash() + if err != nil { + return nil, err + } + + btcInternalKey, err := s.GetAggregateKey() + if err != nil { + return nil, err + } + + return tapscript.PayToAddrScript( + *btcInternalKey, siblingHash, *assetCommitment, + ) +} + +// CreatePreimageWitness creates a preimage witness for the swap. +func (s *SwapKit) CreatePreimageWitness(ctx context.Context, + signer lndclient.SignerClient, htlcProof *proof.Proof, + sweepBtcPacket *psbt.Packet, keyLocator keychain.KeyLocator, + preimage lntypes.Preimage) (wire.TxWitness, error) { + + assetTxOut := &wire.TxOut{ + PkScript: sweepBtcPacket.Inputs[0].WitnessUtxo.PkScript, + Value: sweepBtcPacket.Inputs[0].WitnessUtxo.Value, + } + feeTxOut := &wire.TxOut{ + PkScript: sweepBtcPacket.Inputs[1].WitnessUtxo.PkScript, + Value: sweepBtcPacket.Inputs[1].WitnessUtxo.Value, + } + + if s.CheckCSV { + sweepBtcPacket.UnsignedTx.TxIn[0].Sequence = 1 + } + + successScript, err := s.GetSuccessScript() + if err != nil { + return nil, err + } + + signDesc := &lndclient.SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + KeyLocator: keyLocator, + }, + SignMethod: input.TaprootScriptSpendSignMethod, + WitnessScript: successScript, + Output: assetTxOut, + InputIndex: 0, + } + sig, err := signer.SignOutputRaw( + ctx, sweepBtcPacket.UnsignedTx, + []*lndclient.SignDescriptor{ + signDesc, + }, + []*wire.TxOut{ + assetTxOut, feeTxOut, + }, + ) + if err != nil { + return nil, err + } + + taprootAssetRoot, err := GenTaprootAssetRootFromProof(htlcProof) + if err != nil { + return nil, err + } + + successControlBlock, err := s.GenSuccessBtcControlBlock( + taprootAssetRoot, + ) + if err != nil { + return nil, err + } + + controlBlockBytes, err := successControlBlock.ToBytes() + if err != nil { + return nil, err + } + + return wire.TxWitness{ + preimage[:], + sig[0], + successScript, + controlBlockBytes, + }, nil +} + +// CreateTimeoutWitness creates a timeout witness for the swap. +func (s *SwapKit) CreateTimeoutWitness(ctx context.Context, + signer lndclient.SignerClient, htlcProof *proof.Proof, + sweepBtcPacket *psbt.Packet, keyLocator keychain.KeyLocator) ( + wire.TxWitness, error) { + + assetTxOut := &wire.TxOut{ + PkScript: sweepBtcPacket.Inputs[0].WitnessUtxo.PkScript, + Value: sweepBtcPacket.Inputs[0].WitnessUtxo.Value, + } + feeTxOut := &wire.TxOut{ + PkScript: sweepBtcPacket.Inputs[1].WitnessUtxo.PkScript, + Value: sweepBtcPacket.Inputs[1].WitnessUtxo.Value, + } + + sweepBtcPacket.UnsignedTx.TxIn[0].Sequence = s.CsvExpiry + + timeoutScript, err := s.GetTimeoutScript() + if err != nil { + return nil, err + } + + signDesc := &lndclient.SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + KeyLocator: keyLocator, + }, + SignMethod: input.TaprootScriptSpendSignMethod, + WitnessScript: timeoutScript, + Output: assetTxOut, + InputIndex: 0, + } + sig, err := signer.SignOutputRaw( + ctx, sweepBtcPacket.UnsignedTx, + []*lndclient.SignDescriptor{ + signDesc, + }, + []*wire.TxOut{ + assetTxOut, feeTxOut, + }, + ) + if err != nil { + return nil, err + } + + taprootAssetRoot, err := GenTaprootAssetRootFromProof(htlcProof) + if err != nil { + return nil, err + } + + timeoutControlBlock, err := s.GenTimeoutBtcControlBlock( + taprootAssetRoot, + ) + if err != nil { + return nil, err + } + + controlBlockBytes, err := timeoutControlBlock.ToBytes() + if err != nil { + return nil, err + } + + return wire.TxWitness{ + sig[0], + timeoutScript, + controlBlockBytes, + }, nil +} diff --git a/assets/tapkit.go b/assets/tapkit.go new file mode 100644 index 000000000..c5498b47f --- /dev/null +++ b/assets/tapkit.go @@ -0,0 +1,158 @@ +package assets + +import ( + "context" + "fmt" + + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcutil/psbt" + "github.com/btcsuite/btcd/wire" + "github.com/lightninglabs/loop/assets/htlc" + "github.com/lightninglabs/taproot-assets/address" + "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightninglabs/taproot-assets/commitment" + "github.com/lightninglabs/taproot-assets/proof" + "github.com/lightninglabs/taproot-assets/tappsbt" + "github.com/lightninglabs/taproot-assets/tapsend" +) + +// GenTaprootAssetRootFromProof generates the taproot asset root from the proof +// of the swap. +func GenTaprootAssetRootFromProof(proof *proof.Proof) ([]byte, error) { + assetCopy := proof.Asset.CopySpendTemplate() + + version := commitment.TapCommitmentV2 + assetCommitment, err := commitment.FromAssets(&version, assetCopy) + if err != nil { + return nil, err + } + + assetCommitment, err = commitment.TrimSplitWitnesses( + &version, assetCommitment, + ) + if err != nil { + return nil, err + } + + taprootAssetRoot := assetCommitment.TapscriptRoot(nil) + + return taprootAssetRoot[:], nil +} + +// CreateOpTrueSweepVpkt creates a VPacket that sweeps the outputs associated +// with the passed in proofs, given that their TAP script is a simple OP_TRUE. +func CreateOpTrueSweepVpkt(ctx context.Context, proofs []*proof.Proof, + addr *address.Tap, chainParams *address.ChainParams) ( + *tappsbt.VPacket, error) { + + sweepVpkt, err := tappsbt.FromProofs(proofs, chainParams, tappsbt.V1) + if err != nil { + return nil, err + } + + total := uint64(0) + for i, proof := range proofs { + inputKey := proof.InclusionProof.InternalKey + + sweepVpkt.Inputs[i].Anchor.Bip32Derivation = + []*psbt.Bip32Derivation{ + { + PubKey: inputKey.SerializeCompressed(), + }, + } + sweepVpkt.Inputs[i].Anchor.TrBip32Derivation = + []*psbt.TaprootBip32Derivation{ + { + XOnlyPubKey: schnorr.SerializePubKey( + inputKey, + ), + }, + } + + total += proof.Asset.Amount + } + + // Sanity check that the amount that we're attempting to sweep matches + // the address amount. + if total != addr.Amount { + return nil, fmt.Errorf("total amount of proofs does not " + + "match the amount of the address") + } + + /* + addressRecvVpkt, err := tappsbt.FromAddresses([]*address.Tap{addr}, 0) + if err != nil { + return nil, err + } + + sweepVpkt.Outputs = addressRecvVpkt.Outputs + */ + + // If we are sending the full value of the input asset, or sending a + // collectible, we will need to create a split with un-spendable change. + // Since we don't have any inputs selected yet, we'll use the NUMS + // script key to avoid deriving a new key for each funding attempt. If + // we need a change output, this un-spendable script key will be + // identified as such and replaced with a real one during the funding + // process. + sweepVpkt.Outputs = append(sweepVpkt.Outputs, &tappsbt.VOutput{ + Amount: 0, + Interactive: false, + Type: tappsbt.TypeSplitRoot, + AnchorOutputIndex: 0, + ScriptKey: asset.NUMSScriptKey, + // TODO(bhandras): set this to the actual internal key derived + // from the sender node, otherwise they'll lose the 1000 sats + // of the tombstone output. + AnchorOutputInternalKey: asset.NUMSPubKey, + }) + + sweepVpkt.Outputs = append(sweepVpkt.Outputs, &tappsbt.VOutput{ + AssetVersion: addr.AssetVersion, + Amount: addr.Amount, + Interactive: false, + AnchorOutputIndex: 1, + ScriptKey: asset.NewScriptKey( + &addr.ScriptKey, + ), + AnchorOutputInternalKey: &addr.InternalKey, + AnchorOutputTapscriptSibling: addr.TapscriptSibling, + ProofDeliveryAddress: &addr.ProofCourierAddr, + }) + + err = tapsend.PrepareOutputAssets(ctx, sweepVpkt) + if err != nil { + return nil, err + } + + _, _, _, controlBlock, err := htlc.CreateOpTrueLeaf() + if err != nil { + return nil, err + } + + controlBlockBytes, err := controlBlock.ToBytes() + if err != nil { + return nil, err + } + + opTrueScript, err := htlc.GetOpTrueScript() + if err != nil { + return nil, err + } + + witness := wire.TxWitness{ + opTrueScript, + controlBlockBytes, + } + + err = sweepVpkt.Outputs[0].Asset.UpdateTxWitness(0, witness) + if err != nil { + return nil, fmt.Errorf("unable to update witness: %w", err) + } + + err = sweepVpkt.Outputs[1].Asset.UpdateTxWitness(0, witness) + if err != nil { + return nil, fmt.Errorf("unable to update witness: %w", err) + } + return sweepVpkt, nil +} diff --git a/swapserverrpc/asset_deposit.pb.go b/swapserverrpc/asset_deposit.pb.go new file mode 100644 index 000000000..7ff7886cd --- /dev/null +++ b/swapserverrpc/asset_deposit.pb.go @@ -0,0 +1,881 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2 +// protoc v3.21.12 +// source: asset_deposit.proto + +// We can't change this to swapserverrpc, it would be a breaking change because +// the package name is also contained in the HTTP URIs and old clients would +// call the wrong endpoints. Luckily with the go_package option we can have +// different golang and RPC package names to fix protobuf namespace conflicts. + +package swapserverrpc + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// AssetDepositProtocolVersion is the version of the asset deposit protocol. +type AssetDepositProtocolVersion int32 + +const ( + // V0 is the first version of the asset deposit protocol. + AssetDepositProtocolVersion_ASSET_DEPOSIT_V0 AssetDepositProtocolVersion = 0 +) + +// Enum value maps for AssetDepositProtocolVersion. +var ( + AssetDepositProtocolVersion_name = map[int32]string{ + 0: "ASSET_DEPOSIT_V0", + } + AssetDepositProtocolVersion_value = map[string]int32{ + "ASSET_DEPOSIT_V0": 0, + } +) + +func (x AssetDepositProtocolVersion) Enum() *AssetDepositProtocolVersion { + p := new(AssetDepositProtocolVersion) + *p = x + return p +} + +func (x AssetDepositProtocolVersion) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AssetDepositProtocolVersion) Descriptor() protoreflect.EnumDescriptor { + return file_asset_deposit_proto_enumTypes[0].Descriptor() +} + +func (AssetDepositProtocolVersion) Type() protoreflect.EnumType { + return &file_asset_deposit_proto_enumTypes[0] +} + +func (x AssetDepositProtocolVersion) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AssetDepositProtocolVersion.Descriptor instead. +func (AssetDepositProtocolVersion) EnumDescriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{0} +} + +// NewAssetDepositServerReq is the request to the Server to create a new asset +// deposit. +type NewAssetDepositServerReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // asset_id is the id of the asset to deposit. + AssetId []byte `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` + // amount is the amount of the asset to deposit. + Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` + // client_internal_key is the client's internal pubkey used for the asset + // deposit deposit MuSig2 key. + ClientInternalPubkey []byte `protobuf:"bytes,3,opt,name=client_internal_pubkey,json=clientInternalPubkey,proto3" json:"client_internal_pubkey,omitempty"` + // client_script_key is the client's script pubkey used for the asset + // deposit timeout script. + ClientScriptPubkey []byte `protobuf:"bytes,4,opt,name=client_script_pubkey,json=clientScriptPubkey,proto3" json:"client_script_pubkey,omitempty"` + // csv_expiry is the CSV expiry for the deposit transaction. + CsvExpiry int32 `protobuf:"varint,5,opt,name=csv_expiry,json=csvExpiry,proto3" json:"csv_expiry,omitempty"` +} + +func (x *NewAssetDepositServerReq) Reset() { + *x = NewAssetDepositServerReq{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NewAssetDepositServerReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NewAssetDepositServerReq) ProtoMessage() {} + +func (x *NewAssetDepositServerReq) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NewAssetDepositServerReq.ProtoReflect.Descriptor instead. +func (*NewAssetDepositServerReq) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{0} +} + +func (x *NewAssetDepositServerReq) GetAssetId() []byte { + if x != nil { + return x.AssetId + } + return nil +} + +func (x *NewAssetDepositServerReq) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *NewAssetDepositServerReq) GetClientInternalPubkey() []byte { + if x != nil { + return x.ClientInternalPubkey + } + return nil +} + +func (x *NewAssetDepositServerReq) GetClientScriptPubkey() []byte { + if x != nil { + return x.ClientScriptPubkey + } + return nil +} + +func (x *NewAssetDepositServerReq) GetCsvExpiry() int32 { + if x != nil { + return x.CsvExpiry + } + return 0 +} + +// NewAssetDepositServerRes is the Server's response to a NewAssetDeposit +// request. +type NewAssetDepositServerRes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // deposit_id is the unique id of the deposit. + DepositId string `protobuf:"bytes,1,opt,name=deposit_id,json=depositId,proto3" json:"deposit_id,omitempty"` + // server_script_pubkey is the script pubkey of the server used for the + // asset deposit spending HTLC script. + ServerScriptPubkey []byte `protobuf:"bytes,2,opt,name=server_script_pubkey,json=serverScriptPubkey,proto3" json:"server_script_pubkey,omitempty"` + // server_internal_pubkey is the public key of the server used for the asset + // deposit MuSig2 key. + ServerInternalPubkey []byte `protobuf:"bytes,3,opt,name=server_internal_pubkey,json=serverInternalPubkey,proto3" json:"server_internal_pubkey,omitempty"` + // deposit_addr is the TAP address to deposit the asset to. + DepositAddr string `protobuf:"bytes,4,opt,name=deposit_addr,json=depositAddr,proto3" json:"deposit_addr,omitempty"` +} + +func (x *NewAssetDepositServerRes) Reset() { + *x = NewAssetDepositServerRes{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NewAssetDepositServerRes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NewAssetDepositServerRes) ProtoMessage() {} + +func (x *NewAssetDepositServerRes) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NewAssetDepositServerRes.ProtoReflect.Descriptor instead. +func (*NewAssetDepositServerRes) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{1} +} + +func (x *NewAssetDepositServerRes) GetDepositId() string { + if x != nil { + return x.DepositId + } + return "" +} + +func (x *NewAssetDepositServerRes) GetServerScriptPubkey() []byte { + if x != nil { + return x.ServerScriptPubkey + } + return nil +} + +func (x *NewAssetDepositServerRes) GetServerInternalPubkey() []byte { + if x != nil { + return x.ServerInternalPubkey + } + return nil +} + +func (x *NewAssetDepositServerRes) GetDepositAddr() string { + if x != nil { + return x.DepositAddr + } + return "" +} + +type WithdrawAssetDepositsServerReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DepositIds []string `protobuf:"bytes,1,rep,name=deposit_ids,json=depositIds,proto3" json:"deposit_ids,omitempty"` +} + +func (x *WithdrawAssetDepositsServerReq) Reset() { + *x = WithdrawAssetDepositsServerReq{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WithdrawAssetDepositsServerReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WithdrawAssetDepositsServerReq) ProtoMessage() {} + +func (x *WithdrawAssetDepositsServerReq) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WithdrawAssetDepositsServerReq.ProtoReflect.Descriptor instead. +func (*WithdrawAssetDepositsServerReq) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{2} +} + +func (x *WithdrawAssetDepositsServerReq) GetDepositIds() []string { + if x != nil { + return x.DepositIds + } + return nil +} + +type WithdrawAssetDepositsServerRes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DepositKeys map[string][]byte `protobuf:"bytes,1,rep,name=deposit_keys,json=depositKeys,proto3" json:"deposit_keys,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *WithdrawAssetDepositsServerRes) Reset() { + *x = WithdrawAssetDepositsServerRes{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WithdrawAssetDepositsServerRes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WithdrawAssetDepositsServerRes) ProtoMessage() {} + +func (x *WithdrawAssetDepositsServerRes) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WithdrawAssetDepositsServerRes.ProtoReflect.Descriptor instead. +func (*WithdrawAssetDepositsServerRes) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{3} +} + +func (x *WithdrawAssetDepositsServerRes) GetDepositKeys() map[string][]byte { + if x != nil { + return x.DepositKeys + } + return nil +} + +// AssetDepositPartialSig holds a nonce and partial signature spending a +// deposit. +type AssetDepositPartialSig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // deposit_id is the deposit ID corresponding to this partial signature. + DepositId string `protobuf:"bytes,1,opt,name=deposit_id,json=depositId,proto3" json:"deposit_id,omitempty"` + // nonce is the nonce used for generating this signature. + Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + // partial_sig is the partial signature for spending the deposit. + PartialSig []byte `protobuf:"bytes,3,opt,name=partial_sig,json=partialSig,proto3" json:"partial_sig,omitempty"` +} + +func (x *AssetDepositPartialSig) Reset() { + *x = AssetDepositPartialSig{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AssetDepositPartialSig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssetDepositPartialSig) ProtoMessage() {} + +func (x *AssetDepositPartialSig) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssetDepositPartialSig.ProtoReflect.Descriptor instead. +func (*AssetDepositPartialSig) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{4} +} + +func (x *AssetDepositPartialSig) GetDepositId() string { + if x != nil { + return x.DepositId + } + return "" +} + +func (x *AssetDepositPartialSig) GetNonce() []byte { + if x != nil { + return x.Nonce + } + return nil +} + +func (x *AssetDepositPartialSig) GetPartialSig() []byte { + if x != nil { + return x.PartialSig + } + return nil +} + +// PushAssetDepositHtlcSigsReq holds partial signatures spending one or more +// deposits and the zero fee HTLC spending them. +type PushAssetDepositHtlcSigsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // partial_sigs holds the partial signatures for the deposits spent by the + // HTLC. The inputs of the HTLC will be in the same order defined here. + PartialSigs []*AssetDepositPartialSig `protobuf:"bytes,1,rep,name=partial_sigs,json=partialSigs,proto3" json:"partial_sigs,omitempty"` + // htlc_psbt is the HTLC psbt. + HtlcPsbt []byte `protobuf:"bytes,2,opt,name=htlc_psbt,json=htlcPsbt,proto3" json:"htlc_psbt,omitempty"` +} + +func (x *PushAssetDepositHtlcSigsReq) Reset() { + *x = PushAssetDepositHtlcSigsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushAssetDepositHtlcSigsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushAssetDepositHtlcSigsReq) ProtoMessage() {} + +func (x *PushAssetDepositHtlcSigsReq) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushAssetDepositHtlcSigsReq.ProtoReflect.Descriptor instead. +func (*PushAssetDepositHtlcSigsReq) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{5} +} + +func (x *PushAssetDepositHtlcSigsReq) GetPartialSigs() []*AssetDepositPartialSig { + if x != nil { + return x.PartialSigs + } + return nil +} + +func (x *PushAssetDepositHtlcSigsReq) GetHtlcPsbt() []byte { + if x != nil { + return x.HtlcPsbt + } + return nil +} + +type PushAssetDepositHtlcSigsRes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PushAssetDepositHtlcSigsRes) Reset() { + *x = PushAssetDepositHtlcSigsRes{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushAssetDepositHtlcSigsRes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushAssetDepositHtlcSigsRes) ProtoMessage() {} + +func (x *PushAssetDepositHtlcSigsRes) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushAssetDepositHtlcSigsRes.ProtoReflect.Descriptor instead. +func (*PushAssetDepositHtlcSigsRes) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{6} +} + +// PushAssetDepositKeysReq holds private keys of one or more deposits. +type PushAssetDepositKeysReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // deposit_keys is a map wich maps deposit_id to deposit internal private + // key. + DepositKeys map[string][]byte `protobuf:"bytes,1,rep,name=deposit_keys,json=depositKeys,proto3" json:"deposit_keys,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *PushAssetDepositKeysReq) Reset() { + *x = PushAssetDepositKeysReq{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushAssetDepositKeysReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushAssetDepositKeysReq) ProtoMessage() {} + +func (x *PushAssetDepositKeysReq) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushAssetDepositKeysReq.ProtoReflect.Descriptor instead. +func (*PushAssetDepositKeysReq) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{7} +} + +func (x *PushAssetDepositKeysReq) GetDepositKeys() map[string][]byte { + if x != nil { + return x.DepositKeys + } + return nil +} + +type PushAssetDepositKeysRes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PushAssetDepositKeysRes) Reset() { + *x = PushAssetDepositKeysRes{} + if protoimpl.UnsafeEnabled { + mi := &file_asset_deposit_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushAssetDepositKeysRes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushAssetDepositKeysRes) ProtoMessage() {} + +func (x *PushAssetDepositKeysRes) ProtoReflect() protoreflect.Message { + mi := &file_asset_deposit_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushAssetDepositKeysRes.ProtoReflect.Descriptor instead. +func (*PushAssetDepositKeysRes) Descriptor() ([]byte, []int) { + return file_asset_deposit_proto_rawDescGZIP(), []int{8} +} + +var File_asset_deposit_proto protoreflect.FileDescriptor + +var file_asset_deposit_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x22, 0xd4, + 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x77, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x19, 0x0a, 0x08, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x34, + 0x0a, 0x16, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x50, 0x75, + 0x62, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x73, 0x76, 0x5f, 0x65, 0x78, + 0x70, 0x69, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, 0x73, 0x76, 0x45, + 0x78, 0x70, 0x69, 0x72, 0x79, 0x22, 0xc4, 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x77, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x49, + 0x64, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x12, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x14, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, 0x64, 0x72, 0x22, 0x41, 0x0a, 0x1e, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x1f, + 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x49, 0x64, 0x73, 0x22, + 0xbd, 0x01, 0x0a, 0x1e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x12, 0x5b, 0x0a, 0x0c, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x6b, 0x65, + 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x1a, + 0x3e, 0x0a, 0x10, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x6e, 0x0a, 0x16, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x69, 0x67, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x22, + 0x7e, 0x0a, 0x1b, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x12, 0x42, + 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x69, 0x67, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x50, 0x61, 0x72, 0x74, 0x69, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x68, 0x74, 0x6c, 0x63, 0x50, 0x73, 0x62, 0x74, 0x22, + 0x1d, 0x0a, 0x1b, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x22, 0xaf, + 0x01, 0x0a, 0x17, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x12, 0x54, 0x0a, 0x0c, 0x64, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x31, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, + 0x65, 0x71, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, + 0x1a, 0x3e, 0x0a, 0x10, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x19, 0x0a, 0x17, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x2a, 0x33, 0x0a, 0x1b, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x53, + 0x53, 0x45, 0x54, 0x5f, 0x44, 0x45, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x5f, 0x56, 0x30, 0x10, 0x00, + 0x32, 0x9d, 0x03, 0x0a, 0x13, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x57, 0x0a, 0x0f, 0x4e, 0x65, 0x77, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x12, 0x21, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x21, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x12, 0x69, 0x0a, 0x15, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, + 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x12, 0x66, 0x0a, 0x18, + 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x48, 0x74, 0x6c, 0x63, 0x53, 0x69, 0x67, 0x73, 0x12, 0x24, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x24, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x69, 0x67, + 0x73, 0x52, 0x65, 0x73, 0x12, 0x5a, 0x0a, 0x14, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x20, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, + 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, + 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x6f, 0x6f, + 0x70, 0x2f, 0x73, 0x77, 0x61, 0x70, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_asset_deposit_proto_rawDescOnce sync.Once + file_asset_deposit_proto_rawDescData = file_asset_deposit_proto_rawDesc +) + +func file_asset_deposit_proto_rawDescGZIP() []byte { + file_asset_deposit_proto_rawDescOnce.Do(func() { + file_asset_deposit_proto_rawDescData = protoimpl.X.CompressGZIP(file_asset_deposit_proto_rawDescData) + }) + return file_asset_deposit_proto_rawDescData +} + +var file_asset_deposit_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_asset_deposit_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_asset_deposit_proto_goTypes = []any{ + (AssetDepositProtocolVersion)(0), // 0: looprpc.AssetDepositProtocolVersion + (*NewAssetDepositServerReq)(nil), // 1: looprpc.NewAssetDepositServerReq + (*NewAssetDepositServerRes)(nil), // 2: looprpc.NewAssetDepositServerRes + (*WithdrawAssetDepositsServerReq)(nil), // 3: looprpc.WithdrawAssetDepositsServerReq + (*WithdrawAssetDepositsServerRes)(nil), // 4: looprpc.WithdrawAssetDepositsServerRes + (*AssetDepositPartialSig)(nil), // 5: looprpc.AssetDepositPartialSig + (*PushAssetDepositHtlcSigsReq)(nil), // 6: looprpc.PushAssetDepositHtlcSigsReq + (*PushAssetDepositHtlcSigsRes)(nil), // 7: looprpc.PushAssetDepositHtlcSigsRes + (*PushAssetDepositKeysReq)(nil), // 8: looprpc.PushAssetDepositKeysReq + (*PushAssetDepositKeysRes)(nil), // 9: looprpc.PushAssetDepositKeysRes + nil, // 10: looprpc.WithdrawAssetDepositsServerRes.DepositKeysEntry + nil, // 11: looprpc.PushAssetDepositKeysReq.DepositKeysEntry +} +var file_asset_deposit_proto_depIdxs = []int32{ + 10, // 0: looprpc.WithdrawAssetDepositsServerRes.deposit_keys:type_name -> looprpc.WithdrawAssetDepositsServerRes.DepositKeysEntry + 5, // 1: looprpc.PushAssetDepositHtlcSigsReq.partial_sigs:type_name -> looprpc.AssetDepositPartialSig + 11, // 2: looprpc.PushAssetDepositKeysReq.deposit_keys:type_name -> looprpc.PushAssetDepositKeysReq.DepositKeysEntry + 1, // 3: looprpc.AssetDepositService.NewAssetDeposit:input_type -> looprpc.NewAssetDepositServerReq + 3, // 4: looprpc.AssetDepositService.WithdrawAssetDeposits:input_type -> looprpc.WithdrawAssetDepositsServerReq + 6, // 5: looprpc.AssetDepositService.PushAssetDepositHtlcSigs:input_type -> looprpc.PushAssetDepositHtlcSigsReq + 8, // 6: looprpc.AssetDepositService.PushAssetDepositKeys:input_type -> looprpc.PushAssetDepositKeysReq + 2, // 7: looprpc.AssetDepositService.NewAssetDeposit:output_type -> looprpc.NewAssetDepositServerRes + 4, // 8: looprpc.AssetDepositService.WithdrawAssetDeposits:output_type -> looprpc.WithdrawAssetDepositsServerRes + 7, // 9: looprpc.AssetDepositService.PushAssetDepositHtlcSigs:output_type -> looprpc.PushAssetDepositHtlcSigsRes + 9, // 10: looprpc.AssetDepositService.PushAssetDepositKeys:output_type -> looprpc.PushAssetDepositKeysRes + 7, // [7:11] is the sub-list for method output_type + 3, // [3:7] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_asset_deposit_proto_init() } +func file_asset_deposit_proto_init() { + if File_asset_deposit_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_asset_deposit_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*NewAssetDepositServerReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_asset_deposit_proto_msgTypes[1].Exporter = func(v any, i int) any { + switch v := v.(*NewAssetDepositServerRes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_asset_deposit_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*WithdrawAssetDepositsServerReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_asset_deposit_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*WithdrawAssetDepositsServerRes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_asset_deposit_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*AssetDepositPartialSig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_asset_deposit_proto_msgTypes[5].Exporter = func(v any, i int) any { + switch v := v.(*PushAssetDepositHtlcSigsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_asset_deposit_proto_msgTypes[6].Exporter = func(v any, i int) any { + switch v := v.(*PushAssetDepositHtlcSigsRes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_asset_deposit_proto_msgTypes[7].Exporter = func(v any, i int) any { + switch v := v.(*PushAssetDepositKeysReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_asset_deposit_proto_msgTypes[8].Exporter = func(v any, i int) any { + switch v := v.(*PushAssetDepositKeysRes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_asset_deposit_proto_rawDesc, + NumEnums: 1, + NumMessages: 11, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_asset_deposit_proto_goTypes, + DependencyIndexes: file_asset_deposit_proto_depIdxs, + EnumInfos: file_asset_deposit_proto_enumTypes, + MessageInfos: file_asset_deposit_proto_msgTypes, + }.Build() + File_asset_deposit_proto = out.File + file_asset_deposit_proto_rawDesc = nil + file_asset_deposit_proto_goTypes = nil + file_asset_deposit_proto_depIdxs = nil +} diff --git a/swapserverrpc/asset_deposit.proto b/swapserverrpc/asset_deposit.proto new file mode 100644 index 000000000..20c87fa4f --- /dev/null +++ b/swapserverrpc/asset_deposit.proto @@ -0,0 +1,121 @@ +syntax = "proto3"; + +// We can't change this to swapserverrpc, it would be a breaking change because +// the package name is also contained in the HTTP URIs and old clients would +// call the wrong endpoints. Luckily with the go_package option we can have +// different golang and RPC package names to fix protobuf namespace conflicts. +package looprpc; + +option go_package = "github.com/lightninglabs/loop/swapserverrpc"; + +// AssetDepositService is the service handling asset deposit creation and +// spending. Asset deposits are used in asset loop-in swaps. +service AssetDepositService { + // NewAssetDeposit creates a new asset deposit address. + rpc NewAssetDeposit (NewAssetDepositServerReq) + returns (NewAssetDepositServerRes); + + // WithdrawAssetDeposit withdraws asset deposits to the user's wallet. + rpc WithdrawAssetDeposits (WithdrawAssetDepositsServerReq) + returns (WithdrawAssetDepositsServerRes); + + // PushHtlcSigs pushes a MuSig2 partial signatures to the server spending + // one ore more deposits to a zero fee HTLC. + rpc PushAssetDepositHtlcSigs (PushAssetDepositHtlcSigsReq) + returns (PushAssetDepositHtlcSigsRes); + + // PushKeys pushes (ie reveals) the private keys of one ore more deposits to + // the server. + rpc PushAssetDepositKeys (PushAssetDepositKeysReq) + returns (PushAssetDepositKeysRes); +} + +// NewAssetDepositServerReq is the request to the Server to create a new asset +// deposit. +message NewAssetDepositServerReq { + // asset_id is the id of the asset to deposit. + bytes asset_id = 1; + + // amount is the amount of the asset to deposit. + uint64 amount = 2; + + // client_internal_key is the client's internal pubkey used for the asset + // deposit deposit MuSig2 key. + bytes client_internal_pubkey = 3; + + // client_script_key is the client's script pubkey used for the asset + // deposit timeout script. + bytes client_script_pubkey = 4; + + // csv_expiry is the CSV expiry for the deposit transaction. + int32 csv_expiry = 5; +} + +// NewAssetDepositServerRes is the Server's response to a NewAssetDeposit +// request. +message NewAssetDepositServerRes { + // deposit_id is the unique id of the deposit. + string deposit_id = 1; + + // server_script_pubkey is the script pubkey of the server used for the + // asset deposit spending HTLC script. + bytes server_script_pubkey = 2; + + // server_internal_pubkey is the public key of the server used for the asset + // deposit MuSig2 key. + bytes server_internal_pubkey = 3; + + // deposit_addr is the TAP address to deposit the asset to. + string deposit_addr = 4; +} + +message WithdrawAssetDepositsServerReq { + repeated string deposit_ids = 1; +} + +message WithdrawAssetDepositsServerRes { + map deposit_keys = 1; +} + +// AssetDepositPartialSig holds a nonce and partial signature spending a +// deposit. +message AssetDepositPartialSig { + // deposit_id is the deposit ID corresponding to this partial signature. + string deposit_id = 1; + + // nonce is the nonce used for generating this signature. + bytes nonce = 2; + + // partial_sig is the partial signature for spending the deposit. + bytes partial_sig = 3; +} + +// PushAssetDepositHtlcSigsReq holds partial signatures spending one or more +// deposits and the zero fee HTLC spending them. +message PushAssetDepositHtlcSigsReq { + // partial_sigs holds the partial signatures for the deposits spent by the + // HTLC. The inputs of the HTLC will be in the same order defined here. + repeated AssetDepositPartialSig partial_sigs = 1; + + // htlc_psbt is the HTLC psbt. + bytes htlc_psbt = 2; +} + +message PushAssetDepositHtlcSigsRes { +} + +// PushAssetDepositKeysReq holds private keys of one or more deposits. +message PushAssetDepositKeysReq { + // deposit_keys is a map wich maps deposit_id to deposit internal private + // key. + map deposit_keys = 1; +} + +message PushAssetDepositKeysRes { +} + +// AssetDepositProtocolVersion is the version of the asset deposit protocol. +enum AssetDepositProtocolVersion { + // V0 is the first version of the asset deposit protocol. + ASSET_DEPOSIT_V0 = 0; +}; diff --git a/swapserverrpc/asset_deposit_grpc.pb.go b/swapserverrpc/asset_deposit_grpc.pb.go new file mode 100644 index 000000000..03dcd3e57 --- /dev/null +++ b/swapserverrpc/asset_deposit_grpc.pb.go @@ -0,0 +1,221 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package swapserverrpc + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// AssetDepositServiceClient is the client API for AssetDepositService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type AssetDepositServiceClient interface { + // NewAssetDeposit creates a new asset deposit address. + NewAssetDeposit(ctx context.Context, in *NewAssetDepositServerReq, opts ...grpc.CallOption) (*NewAssetDepositServerRes, error) + // WithdrawAssetDeposit withdraws asset deposits to the user's wallet. + WithdrawAssetDeposits(ctx context.Context, in *WithdrawAssetDepositsServerReq, opts ...grpc.CallOption) (*WithdrawAssetDepositsServerRes, error) + // PushHtlcSigs pushes a MuSig2 partial signatures to the server spending + // one ore more deposits to a zero fee HTLC. + PushAssetDepositHtlcSigs(ctx context.Context, in *PushAssetDepositHtlcSigsReq, opts ...grpc.CallOption) (*PushAssetDepositHtlcSigsRes, error) + // PushKeys pushes (ie reveals) the private keys of one ore more deposits to + // the server. + PushAssetDepositKeys(ctx context.Context, in *PushAssetDepositKeysReq, opts ...grpc.CallOption) (*PushAssetDepositKeysRes, error) +} + +type assetDepositServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAssetDepositServiceClient(cc grpc.ClientConnInterface) AssetDepositServiceClient { + return &assetDepositServiceClient{cc} +} + +func (c *assetDepositServiceClient) NewAssetDeposit(ctx context.Context, in *NewAssetDepositServerReq, opts ...grpc.CallOption) (*NewAssetDepositServerRes, error) { + out := new(NewAssetDepositServerRes) + err := c.cc.Invoke(ctx, "/looprpc.AssetDepositService/NewAssetDeposit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *assetDepositServiceClient) WithdrawAssetDeposits(ctx context.Context, in *WithdrawAssetDepositsServerReq, opts ...grpc.CallOption) (*WithdrawAssetDepositsServerRes, error) { + out := new(WithdrawAssetDepositsServerRes) + err := c.cc.Invoke(ctx, "/looprpc.AssetDepositService/WithdrawAssetDeposits", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *assetDepositServiceClient) PushAssetDepositHtlcSigs(ctx context.Context, in *PushAssetDepositHtlcSigsReq, opts ...grpc.CallOption) (*PushAssetDepositHtlcSigsRes, error) { + out := new(PushAssetDepositHtlcSigsRes) + err := c.cc.Invoke(ctx, "/looprpc.AssetDepositService/PushAssetDepositHtlcSigs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *assetDepositServiceClient) PushAssetDepositKeys(ctx context.Context, in *PushAssetDepositKeysReq, opts ...grpc.CallOption) (*PushAssetDepositKeysRes, error) { + out := new(PushAssetDepositKeysRes) + err := c.cc.Invoke(ctx, "/looprpc.AssetDepositService/PushAssetDepositKeys", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AssetDepositServiceServer is the server API for AssetDepositService service. +// All implementations must embed UnimplementedAssetDepositServiceServer +// for forward compatibility +type AssetDepositServiceServer interface { + // NewAssetDeposit creates a new asset deposit address. + NewAssetDeposit(context.Context, *NewAssetDepositServerReq) (*NewAssetDepositServerRes, error) + // WithdrawAssetDeposit withdraws asset deposits to the user's wallet. + WithdrawAssetDeposits(context.Context, *WithdrawAssetDepositsServerReq) (*WithdrawAssetDepositsServerRes, error) + // PushHtlcSigs pushes a MuSig2 partial signatures to the server spending + // one ore more deposits to a zero fee HTLC. + PushAssetDepositHtlcSigs(context.Context, *PushAssetDepositHtlcSigsReq) (*PushAssetDepositHtlcSigsRes, error) + // PushKeys pushes (ie reveals) the private keys of one ore more deposits to + // the server. + PushAssetDepositKeys(context.Context, *PushAssetDepositKeysReq) (*PushAssetDepositKeysRes, error) + mustEmbedUnimplementedAssetDepositServiceServer() +} + +// UnimplementedAssetDepositServiceServer must be embedded to have forward compatible implementations. +type UnimplementedAssetDepositServiceServer struct { +} + +func (UnimplementedAssetDepositServiceServer) NewAssetDeposit(context.Context, *NewAssetDepositServerReq) (*NewAssetDepositServerRes, error) { + return nil, status.Errorf(codes.Unimplemented, "method NewAssetDeposit not implemented") +} +func (UnimplementedAssetDepositServiceServer) WithdrawAssetDeposits(context.Context, *WithdrawAssetDepositsServerReq) (*WithdrawAssetDepositsServerRes, error) { + return nil, status.Errorf(codes.Unimplemented, "method WithdrawAssetDeposits not implemented") +} +func (UnimplementedAssetDepositServiceServer) PushAssetDepositHtlcSigs(context.Context, *PushAssetDepositHtlcSigsReq) (*PushAssetDepositHtlcSigsRes, error) { + return nil, status.Errorf(codes.Unimplemented, "method PushAssetDepositHtlcSigs not implemented") +} +func (UnimplementedAssetDepositServiceServer) PushAssetDepositKeys(context.Context, *PushAssetDepositKeysReq) (*PushAssetDepositKeysRes, error) { + return nil, status.Errorf(codes.Unimplemented, "method PushAssetDepositKeys not implemented") +} +func (UnimplementedAssetDepositServiceServer) mustEmbedUnimplementedAssetDepositServiceServer() {} + +// UnsafeAssetDepositServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AssetDepositServiceServer will +// result in compilation errors. +type UnsafeAssetDepositServiceServer interface { + mustEmbedUnimplementedAssetDepositServiceServer() +} + +func RegisterAssetDepositServiceServer(s grpc.ServiceRegistrar, srv AssetDepositServiceServer) { + s.RegisterService(&AssetDepositService_ServiceDesc, srv) +} + +func _AssetDepositService_NewAssetDeposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NewAssetDepositServerReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AssetDepositServiceServer).NewAssetDeposit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.AssetDepositService/NewAssetDeposit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AssetDepositServiceServer).NewAssetDeposit(ctx, req.(*NewAssetDepositServerReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _AssetDepositService_WithdrawAssetDeposits_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(WithdrawAssetDepositsServerReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AssetDepositServiceServer).WithdrawAssetDeposits(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.AssetDepositService/WithdrawAssetDeposits", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AssetDepositServiceServer).WithdrawAssetDeposits(ctx, req.(*WithdrawAssetDepositsServerReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _AssetDepositService_PushAssetDepositHtlcSigs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PushAssetDepositHtlcSigsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AssetDepositServiceServer).PushAssetDepositHtlcSigs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.AssetDepositService/PushAssetDepositHtlcSigs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AssetDepositServiceServer).PushAssetDepositHtlcSigs(ctx, req.(*PushAssetDepositHtlcSigsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _AssetDepositService_PushAssetDepositKeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PushAssetDepositKeysReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AssetDepositServiceServer).PushAssetDepositKeys(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.AssetDepositService/PushAssetDepositKeys", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AssetDepositServiceServer).PushAssetDepositKeys(ctx, req.(*PushAssetDepositKeysReq)) + } + return interceptor(ctx, in, info, handler) +} + +// AssetDepositService_ServiceDesc is the grpc.ServiceDesc for AssetDepositService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AssetDepositService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "looprpc.AssetDepositService", + HandlerType: (*AssetDepositServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "NewAssetDeposit", + Handler: _AssetDepositService_NewAssetDeposit_Handler, + }, + { + MethodName: "WithdrawAssetDeposits", + Handler: _AssetDepositService_WithdrawAssetDeposits_Handler, + }, + { + MethodName: "PushAssetDepositHtlcSigs", + Handler: _AssetDepositService_PushAssetDepositHtlcSigs_Handler, + }, + { + MethodName: "PushAssetDepositKeys", + Handler: _AssetDepositService_PushAssetDepositKeys_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "asset_deposit.proto", +}