Skip to content

Commit 731271a

Browse files
committed
tapas_loopout
1 parent 0fe952a commit 731271a

36 files changed

+6619
-134
lines changed

assets/actions.go

Lines changed: 421 additions & 0 deletions
Large diffs are not rendered by default.

assets/interfaces.go

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

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"
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 means the
12+
// package will not perform any logging by default until the caller requests
13+
// 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. This
22+
// should be used in preference to SetLogWriter if the caller is also using
23+
// btclog.
24+
func UseLogger(logger btclog.Logger) {
25+
log = logger
26+
}

assets/manager.go

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package assets
2+
3+
import (
4+
"context"
5+
"sync"
6+
"time"
7+
8+
"github.com/btcsuite/btcd/btcutil"
9+
"github.com/lightninglabs/lndclient"
10+
"github.com/lightninglabs/loop/fsm"
11+
loop_rpc "github.com/lightninglabs/loop/swapserverrpc"
12+
"github.com/lightninglabs/loop/utils"
13+
"github.com/lightninglabs/taproot-assets/taprpc"
14+
"github.com/lightningnetwork/lnd/lntypes"
15+
)
16+
17+
const (
18+
ClientKeyFamily = 696969
19+
)
20+
21+
type Config struct {
22+
AssetClient *TapdClient
23+
Wallet lndclient.WalletKitClient
24+
// ExchangeRateProvider is the exchange rate provider.
25+
ExchangeRateProvider *FixedExchangeRateProvider
26+
Signer lndclient.SignerClient
27+
ChainNotifier lndclient.ChainNotifierClient
28+
Router lndclient.RouterClient
29+
LndClient lndclient.LightningClient
30+
Store *PostgresStore
31+
ServerClient loop_rpc.AssetsSwapServerClient
32+
}
33+
34+
type AssetsSwapManager struct {
35+
cfg *Config
36+
37+
expiryManager *utils.ExpiryManager
38+
txConfManager *utils.TxSubscribeConfirmationManager
39+
40+
blockHeight int32
41+
runCtx context.Context
42+
activeSwapOuts map[lntypes.Hash]*OutFSM
43+
44+
sync.Mutex
45+
}
46+
47+
func NewAssetSwapServer(config *Config) *AssetsSwapManager {
48+
return &AssetsSwapManager{
49+
cfg: config,
50+
51+
activeSwapOuts: make(map[lntypes.Hash]*OutFSM),
52+
}
53+
}
54+
55+
func (m *AssetsSwapManager) Run(ctx context.Context, blockHeight int32) error {
56+
m.runCtx = ctx
57+
m.blockHeight = blockHeight
58+
59+
// Get our tapd client info.
60+
tapdInfo, err := m.cfg.AssetClient.GetInfo(
61+
ctx, &taprpc.GetInfoRequest{},
62+
)
63+
if err != nil {
64+
return err
65+
}
66+
log.Infof("Tapd info: %v", tapdInfo)
67+
68+
// Create our subscriptionManagers.
69+
m.expiryManager = utils.NewExpiryManager(m.cfg.ChainNotifier)
70+
m.txConfManager = utils.NewTxSubscribeConfirmationManager(
71+
m.cfg.ChainNotifier,
72+
)
73+
74+
// Start the expiry manager.
75+
errChan := make(chan error, 1)
76+
wg := &sync.WaitGroup{}
77+
wg.Add(1)
78+
go func() {
79+
defer wg.Done()
80+
err := m.expiryManager.Start(ctx, blockHeight)
81+
if err != nil {
82+
log.Errorf("Expiry manager failed: %v", err)
83+
errChan <- err
84+
log.Errorf("Gude1")
85+
}
86+
}()
87+
88+
// Recover all the active asset swap outs from the database.
89+
err = m.recoverSwapOuts(ctx)
90+
if err != nil {
91+
return err
92+
}
93+
94+
for {
95+
select {
96+
case err := <-errChan:
97+
log.Errorf("Gude2")
98+
return err
99+
100+
case <-ctx.Done():
101+
log.Errorf("Gude3")
102+
// wg.Wait()
103+
log.Errorf("Gude4")
104+
return nil
105+
}
106+
}
107+
}
108+
109+
func (m *AssetsSwapManager) NewSwapOut(ctx context.Context,
110+
amt btcutil.Amount, asset []byte) (*OutFSM, error) {
111+
112+
// Create a new out fsm.
113+
outFSM := NewOutFSM(m.runCtx, m.getFSMOutConfig())
114+
115+
// Send the initial event to the fsm.
116+
err := outFSM.SendEvent(
117+
ctx, OnRequestAssetOut, &InitSwapOutContext{
118+
Amount: amt,
119+
AssetId: asset,
120+
},
121+
)
122+
if err != nil {
123+
return nil, err
124+
}
125+
// Check if the fsm has an error.
126+
if outFSM.LastActionError != nil {
127+
return nil, outFSM.LastActionError
128+
}
129+
130+
// Wait for the fsm to be in the state we expect.
131+
err = outFSM.DefaultObserver.WaitForState(
132+
ctx, time.Second*15, PayPrepay,
133+
fsm.WithAbortEarlyOnErrorOption(),
134+
)
135+
if err != nil {
136+
return nil, err
137+
}
138+
139+
// Add the swap to the active swap outs.
140+
m.Lock()
141+
m.activeSwapOuts[outFSM.SwapOut.SwapHash] = outFSM
142+
m.Unlock()
143+
144+
return outFSM, nil
145+
}
146+
147+
// recoverSwapOuts recovers all the active asset swap outs from the database.
148+
func (m *AssetsSwapManager) recoverSwapOuts(ctx context.Context) error {
149+
// Fetch all the active asset swap outs from the database.
150+
activeSwapOuts, err := m.cfg.Store.GetActiveAssetOuts(ctx)
151+
if err != nil {
152+
return err
153+
}
154+
155+
for _, swapOut := range activeSwapOuts {
156+
log.Debugf("Recovering asset out %v with state %v",
157+
swapOut.SwapHash, swapOut.State)
158+
159+
swapOutFSM := NewOutFSMFromSwap(
160+
ctx, m.getFSMOutConfig(), swapOut,
161+
)
162+
163+
m.Lock()
164+
m.activeSwapOuts[swapOut.SwapHash] = swapOutFSM
165+
m.Unlock()
166+
167+
// As SendEvent can block, we'll start a goroutine to process
168+
// the event.
169+
go func() {
170+
err := swapOutFSM.SendEvent(ctx, OnRecover, nil)
171+
if err != nil {
172+
log.Errorf("FSM %v Error sending recover "+
173+
"event %v, state: %v",
174+
swapOutFSM.SwapOut.SwapHash,
175+
err, swapOutFSM.SwapOut.State)
176+
}
177+
}()
178+
}
179+
180+
return nil
181+
}
182+
183+
// getFSMOutConfig returns a fsmconfig from the manager.
184+
func (m *AssetsSwapManager) getFSMOutConfig() *FSMConfig {
185+
return &FSMConfig{
186+
TapdClient: m.cfg.AssetClient,
187+
AssetClient: m.cfg.ServerClient,
188+
BlockHeightSubscriber: m.expiryManager,
189+
TxConfSubscriber: m.txConfManager,
190+
ExchangeRateProvider: m.cfg.ExchangeRateProvider,
191+
Wallet: m.cfg.Wallet,
192+
Router: m.cfg.Router,
193+
194+
Store: m.cfg.Store,
195+
Signer: m.cfg.Signer,
196+
}
197+
}
198+
199+
func (m *AssetsSwapManager) ListSwapOutoutputs(ctx context.Context) ([]*SwapOut,
200+
error) {
201+
202+
return m.cfg.Store.GetAllAssetOuts(ctx)
203+
}

0 commit comments

Comments
 (0)