Skip to content

Commit 7d30034

Browse files
committed
assets: add basic swap out struct
1 parent 26a7fca commit 7d30034

File tree

3 files changed

+285
-0
lines changed

3 files changed

+285
-0
lines changed

assets/interfaces.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package assets
2+
3+
import (
4+
"context"
5+
6+
"github.com/btcsuite/btcd/btcutil"
7+
"github.com/btcsuite/btcd/btcutil/psbt"
8+
"github.com/btcsuite/btcd/chaincfg"
9+
"github.com/btcsuite/btcd/chaincfg/chainhash"
10+
"github.com/btcsuite/btcd/wire"
11+
"github.com/lightninglabs/lndclient"
12+
"github.com/lightninglabs/loop/fsm"
13+
"github.com/lightninglabs/taproot-assets/asset"
14+
"github.com/lightninglabs/taproot-assets/proof"
15+
"github.com/lightninglabs/taproot-assets/tappsbt"
16+
"github.com/lightninglabs/taproot-assets/taprpc"
17+
"github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc"
18+
wrpc "github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc"
19+
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
20+
"github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
21+
"github.com/lightninglabs/taproot-assets/taprpc/tapdevrpc"
22+
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
23+
"github.com/lightningnetwork/lnd/chainntnfs"
24+
"github.com/lightningnetwork/lnd/keychain"
25+
"github.com/lightningnetwork/lnd/lntypes"
26+
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
27+
)
28+
29+
const (
30+
// DefaultSwapCSVExpiry is the default expiry for a swap in blocks.
31+
DefaultSwapCSVExpiry = int32(24)
32+
33+
defaultHtlcFeeConfTarget = 3
34+
defaultHtlcConfRequirement = 2
35+
36+
AssetKeyFamily = 696969
37+
)
38+
39+
// TapdClient is an interface that groups the methods required to interact with
40+
// the taproot-assets server and the wallet.
41+
type AssetClient interface {
42+
taprpc.TaprootAssetsClient
43+
wrpc.AssetWalletClient
44+
mintrpc.MintClient
45+
universerpc.UniverseClient
46+
tapdevrpc.TapDevClient
47+
48+
// FundAndSignVpacket funds ands signs a vpacket.
49+
FundAndSignVpacket(ctx context.Context,
50+
vpkt *tappsbt.VPacket) (*tappsbt.VPacket, error)
51+
52+
// PrepareAndCommitVirtualPsbts prepares and commits virtual psbts.
53+
PrepareAndCommitVirtualPsbts(ctx context.Context,
54+
vpkt *tappsbt.VPacket, feeRateSatPerKVByte chainfee.SatPerVByte,
55+
changeKeyDesc *keychain.KeyDescriptor, params *chaincfg.Params) (
56+
*psbt.Packet, []*tappsbt.VPacket, []*tappsbt.VPacket,
57+
*assetwalletrpc.CommitVirtualPsbtsResponse, error)
58+
59+
// LogAndPublish logs and publishes the virtual psbts.
60+
LogAndPublish(ctx context.Context, btcPkt *psbt.Packet,
61+
activeAssets []*tappsbt.VPacket, passiveAssets []*tappsbt.VPacket,
62+
commitResp *wrpc.CommitVirtualPsbtsResponse) (*taprpc.SendAssetResponse,
63+
error)
64+
65+
// GetAssetBalance returns the balance of the given asset.
66+
GetAssetBalance(ctx context.Context, assetId []byte) (
67+
uint64, error)
68+
69+
// DeriveNewKeys derives a new internal and script key.
70+
DeriveNewKeys(ctx context.Context) (asset.ScriptKey,
71+
keychain.KeyDescriptor, error)
72+
73+
// AddHoldInvoice adds a new hold invoice.
74+
AddHoldInvoice(ctx context.Context, pHash lntypes.Hash,
75+
assetId []byte, assetAmt uint64, memo string) (
76+
*tapchannelrpc.AddInvoiceResponse, error)
77+
78+
// ImportProofFile imports the proof file and returns the last proof.
79+
ImportProofFile(ctx context.Context, rawProofFile []byte) (
80+
*proof.Proof, error)
81+
82+
// SendPayment pays a payment request.
83+
SendPayment(ctx context.Context,
84+
invoice string, assetId []byte) (chan *tapchannelrpc.SendPaymentResponse,
85+
chan error, error)
86+
}
87+
88+
// SwapStore is an interface that groups the methods required to store swap
89+
// information.
90+
type SwapStore interface {
91+
// CreateAssetSwapOut creates a new swap out in the store.
92+
CreateAssetSwapOut(ctx context.Context, swap *SwapOut) error
93+
94+
// UpdateAssetSwapHtlcOutpoint updates the htlc outpoint of a swap out.
95+
UpdateAssetSwapHtlcOutpoint(ctx context.Context, swapHash lntypes.Hash,
96+
outpoint *wire.OutPoint, confirmationHeight int32) error
97+
98+
// UpdateAssetSwapOutProof updates the proof of a swap out.
99+
UpdateAssetSwapOutProof(ctx context.Context, swapHash lntypes.Hash,
100+
rawProof []byte) error
101+
102+
// UpdateAssetSwapOutSweepTx updates the sweep tx of a swap out.
103+
UpdateAssetSwapOutSweepTx(ctx context.Context,
104+
swapHash lntypes.Hash, sweepTxid chainhash.Hash,
105+
confHeight int32, sweepPkscript []byte) error
106+
107+
// InsertAssetSwapUpdate inserts a new swap update in the store.
108+
InsertAssetSwapUpdate(ctx context.Context,
109+
swapHash lntypes.Hash, state fsm.StateType) error
110+
111+
UpdateAssetSwapOutPreimage(ctx context.Context,
112+
swapHash lntypes.Hash, preimage lntypes.Preimage) error
113+
}
114+
115+
// BlockHeightSubscriber is responsible for subscribing to the expiry height
116+
// of a swap, as well as getting the current block height.
117+
type BlockHeightSubscriber interface {
118+
// SubscribeExpiry subscribes to the expiry of a swap. It returns true
119+
// if the expiry is already past. Otherwise, it returns false and calls
120+
// the expiryFunc when the expiry height is reached.
121+
SubscribeExpiry(swapHash [32]byte,
122+
expiryHeight int32, expiryFunc func()) bool
123+
// GetBlockHeight returns the current block height.
124+
GetBlockHeight() int32
125+
}
126+
127+
// InvoiceSubscriber is responsible for subscribing to an invoice.
128+
type InvoiceSubscriber interface {
129+
// SubscribeInvoice subscribes to an invoice. The update callback is
130+
// called when the invoice is updated and the error callback is called
131+
// when an error occurs.
132+
SubscribeInvoice(ctx context.Context, invoiceHash lntypes.Hash,
133+
updateCallback func(lndclient.InvoiceUpdate, error)) error
134+
}
135+
136+
// TxConfirmationSubscriber is responsible for subscribing to the confirmation
137+
// of a transaction.
138+
type TxConfirmationSubscriber interface {
139+
140+
// SubscribeTxConfirmation subscribes to the confirmation of a
141+
// pkscript on the chain. The callback is called when the pkscript is
142+
// confirmed or when an error occurs.
143+
SubscribeTxConfirmation(ctx context.Context, swapHash lntypes.Hash,
144+
txid *chainhash.Hash, pkscript []byte, numConfs int32,
145+
eightHint int32, cb func(*chainntnfs.TxConfirmation, error)) error
146+
}
147+
148+
// ExchangeRateProvider is responsible for providing the exchange rate between
149+
// assets.
150+
type ExchangeRateProvider interface {
151+
// GetSatsPerAssetUnit returns the amount of satoshis per asset unit.
152+
GetSatsPerAssetUnit(assetId []byte) (btcutil.Amount, error)
153+
}

assets/log.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package assets
2+
3+
import (
4+
"github.com/btcsuite/btclog/v2"
5+
"github.com/lightningnetwork/lnd/build"
6+
)
7+
8+
// Subsystem defines the sub system name of this package.
9+
const Subsystem = "ASSETS"
10+
11+
// log is a logger that is initialized with no output filters. This
12+
// means the package will not perform any logging by default until the caller
13+
// requests it.
14+
var log btclog.Logger
15+
16+
// The default amount of logging is none.
17+
func init() {
18+
UseLogger(build.NewSubLogger(Subsystem, nil))
19+
}
20+
21+
// UseLogger uses a specified Logger to output package logging info.
22+
// This should be used in preference to SetLogWriter if the caller is also
23+
// using btclog.
24+
func UseLogger(logger btclog.Logger) {
25+
log = logger
26+
}

assets/swap_out.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package assets
2+
3+
import (
4+
"github.com/btcsuite/btcd/btcec/v2"
5+
"github.com/btcsuite/btcd/txscript"
6+
"github.com/btcsuite/btcd/wire"
7+
"github.com/lightninglabs/loop/assets/htlc"
8+
"github.com/lightninglabs/loop/fsm"
9+
"github.com/lightninglabs/taproot-assets/commitment"
10+
"github.com/lightninglabs/taproot-assets/proof"
11+
12+
"github.com/lightningnetwork/lnd/keychain"
13+
"github.com/lightningnetwork/lnd/lntypes"
14+
)
15+
16+
// SwapOut is a struct that represents a swap out. It contains all the
17+
// information needed to perform a swap out.
18+
type SwapOut struct {
19+
// We embed swapkit for all script related helpers.
20+
htlc.SwapKit
21+
22+
// SwapPreimage is the preimage of the swap, that enables spending
23+
// the success path, it's hash is the main identifier of the swap.
24+
SwapPreimage lntypes.Preimage
25+
26+
// State is the current state of the swap.
27+
State fsm.StateType
28+
29+
// InitiationHeight is the height at which the swap was initiated.
30+
InitiationHeight uint32
31+
32+
// ClientKeyLocator is the key locator of the clients key.
33+
ClientKeyLocator keychain.KeyLocator
34+
35+
// HtlcOutPoint is the outpoint of the htlc that was created to
36+
// perform the swap.
37+
HtlcOutPoint *wire.OutPoint
38+
39+
// HtlcConfirmationHeight is the height at which the htlc was
40+
// confirmed.
41+
HtlcConfirmationHeight uint32
42+
43+
// SweepOutpoint is the outpoint of the htlc that was swept.
44+
SweepOutpoint *wire.OutPoint
45+
46+
// SweepConfirmationHeight is the height at which the sweep was
47+
// confirmed.
48+
SweepConfirmationHeight uint32
49+
50+
// SweepPkscript is the pkscript of the sweep transaction.
51+
SweepPkscript []byte
52+
53+
// RawHtlcProof is the raw htlc proof that we need to send to the
54+
// receiver. We only keep this in the OutFSM struct as we don't want
55+
// to save it in the store.
56+
RawHtlcProof []byte
57+
}
58+
59+
// NewSwapOut creates a new swap out.
60+
func NewSwapOut(swapHash lntypes.Hash, amt uint64,
61+
assetId []byte, clientKeyDesc *keychain.KeyDescriptor,
62+
senderPubkey *btcec.PublicKey, csvExpiry, initiationHeight uint32,
63+
) *SwapOut {
64+
65+
return &SwapOut{
66+
SwapKit: htlc.SwapKit{
67+
SwapHash: swapHash,
68+
Amount: amt,
69+
SenderPubKey: senderPubkey,
70+
ReceiverPubKey: clientKeyDesc.PubKey,
71+
CsvExpiry: csvExpiry,
72+
AssetID: assetId,
73+
},
74+
State: Init,
75+
InitiationHeight: initiationHeight,
76+
ClientKeyLocator: clientKeyDesc.KeyLocator,
77+
}
78+
}
79+
80+
// genTaprootAssetRootFromProof generates the taproot asset root from the proof
81+
// of the swap.
82+
func (s *SwapOut) genTaprootAssetRootFromProof(proof *proof.Proof) ([]byte,
83+
error) {
84+
85+
assetCpy := proof.Asset.Copy()
86+
assetCpy.PrevWitnesses[0].SplitCommitment = nil
87+
sendCommitment, err := commitment.NewAssetCommitment(
88+
assetCpy,
89+
)
90+
if err != nil {
91+
return nil, err
92+
}
93+
94+
version := commitment.TapCommitmentV2
95+
assetCommitment, err := commitment.NewTapCommitment(
96+
&version, sendCommitment,
97+
)
98+
if err != nil {
99+
return nil, err
100+
}
101+
taprootAssetRoot := txscript.AssembleTaprootScriptTree(
102+
assetCommitment.TapLeaf(),
103+
).RootNode.TapHash()
104+
105+
return taprootAssetRoot[:], nil
106+
}

0 commit comments

Comments
 (0)