diff --git a/loopdb/interface.go b/loopdb/interface.go index c3c049ca..9684035b 100644 --- a/loopdb/interface.go +++ b/loopdb/interface.go @@ -30,6 +30,11 @@ type SwapStore interface { UpdateLoopOut(ctx context.Context, hash lntypes.Hash, time time.Time, state SwapStateData) error + // UpdateLoopOutAssetInfo updates the asset information for a loop out + // swap. + UpdateLoopOutAssetInfo(ctx context.Context, hash lntypes.Hash, + asset *LoopOutAssetSwap) error + // FetchLoopInSwaps returns all swaps currently in the store. FetchLoopInSwaps(ctx context.Context) ([]*LoopIn, error) diff --git a/loopdb/sql_store.go b/loopdb/sql_store.go index c6de31f6..4a41fea8 100644 --- a/loopdb/sql_store.go +++ b/loopdb/sql_store.go @@ -126,10 +126,40 @@ func (db *BaseDB) CreateLoopOut(ctx context.Context, hash lntypes.Hash, return err } + // If the loop is an asset loop out, we'll also insert the + // asset details. + if swap.AssetSwapInfo != nil { + assetInfo := swap.AssetSwapInfo + err = tx.InsertLoopOutAsset( + ctx, sqlc.InsertLoopOutAssetParams{ + SwapHash: hash[:], + AssetID: assetInfo.AssetId, + SwapRfqID: assetInfo.SwapRfqId, + PrepayRfqID: assetInfo.PrepayRfqId, + }, + ) + if err != nil { + return err + } + } + return nil }) } +// UpdateLoopOutAssetInfo updates the offchain send amounts of the prepay and +// swap payment for an asset loop out swap. +func (db *BaseDB) UpdateLoopOutAssetInfo(ctx context.Context, hash lntypes.Hash, + asset *LoopOutAssetSwap) error { + + return db.UpdateLoopOutAssetOffchainPayments( + ctx, sqlc.UpdateLoopOutAssetOffchainPaymentsParams{ + SwapHash: hash[:], + AssetAmtPaidSwap: int64(asset.SwapPaidAmt), + AssetAmtPaidPrepay: int64(asset.PrepayPaidAmt), + }) +} + // BatchCreateLoopOut adds multiple initiated swaps to the store. func (db *BaseDB) BatchCreateLoopOut(ctx context.Context, swaps map[lntypes.Hash]*LoopOutContract) error { @@ -543,7 +573,8 @@ func swapToHtlcKeysInsertArgs(hash lntypes.Hash, // ConvertLoopOutRow converts a database row containing a loop out swap to a // LoopOut struct. func ConvertLoopOutRow(network *chaincfg.Params, row sqlc.GetLoopOutSwapRow, - updates []sqlc.SwapUpdate) (*LoopOut, error) { + updates []sqlc.SwapUpdate) (*LoopOut, + error) { htlcKeys, err := fetchHtlcKeys( row.SenderScriptPubkey, row.ReceiverScriptPubkey, @@ -601,6 +632,20 @@ func ConvertLoopOutRow(network *chaincfg.Params, row sqlc.GetLoopOutSwapRow, }, } + if row.AssetID != nil { + loopOut.Contract.AssetSwapInfo = &LoopOutAssetSwap{ + AssetId: row.AssetID, + SwapRfqId: row.SwapRfqID, + PrepayRfqId: row.PrepayRfqID, + SwapPaidAmt: uint64( + unmarshalSqlInt64(row.AssetAmtPaidSwap), + ), + PrepayPaidAmt: uint64( + unmarshalSqlInt64(row.AssetAmtPaidPrepay), + ), + } + } + if row.OutgoingChanSet != "" { chanSet, err := ConvertOutgoingChanSet(row.OutgoingChanSet) if err != nil { @@ -803,3 +848,11 @@ func blobTo33ByteSlice(blob []byte) ([33]byte, error) { return key, nil } + +func unmarshalSqlInt64(data sql.NullInt64) int64 { + if !data.Valid { + return 0 + } + + return data.Int64 +} diff --git a/loopdb/sql_test.go b/loopdb/sql_test.go index a8426199..225dc175 100644 --- a/loopdb/sql_test.go +++ b/loopdb/sql_test.go @@ -22,6 +22,15 @@ const ( testLabel = "test label" ) +var ( + testAssetId = []byte{ + 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, + 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, + } +) + // TestSqliteLoopOutStore tests all the basic functionality of the current // sqlite swap store. func TestSqliteLoopOutStore(t *testing.T) { @@ -80,6 +89,17 @@ func TestSqliteLoopOutStore(t *testing.T) { t.Run("labelled swap", func(t *testing.T) { testSqliteLoopOutStore(t, &labelledSwap) }) + + assetSwap := unrestrictedSwap + assetSwap.AssetSwapInfo = &LoopOutAssetSwap{ + AssetId: testAssetId, + PrepayRfqId: testAssetId, + SwapRfqId: testAssetId, + } + + t.Run("asset swap", func(t *testing.T) { + testSqliteLoopOutStore(t, &assetSwap) + }) } // testSqliteLoopOutStore tests the basic functionality of the current sqlite diff --git a/loopdb/sqlc/migrations/000012_loop_out_asset_params.down.sql b/loopdb/sqlc/migrations/000012_loop_out_asset_params.down.sql new file mode 100644 index 00000000..c47cee84 --- /dev/null +++ b/loopdb/sqlc/migrations/000012_loop_out_asset_params.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS loopout_swaps_assets; \ No newline at end of file diff --git a/loopdb/sqlc/migrations/000012_loop_out_asset_params.up.sql b/loopdb/sqlc/migrations/000012_loop_out_asset_params.up.sql new file mode 100644 index 00000000..cafd9aa0 --- /dev/null +++ b/loopdb/sqlc/migrations/000012_loop_out_asset_params.up.sql @@ -0,0 +1,22 @@ +CREATE TABLE IF NOT EXISTS loopout_swaps_asset_info ( + -- swap_hash points to the parent loop out swap hash. + swap_hash BLOB PRIMARY KEY REFERENCES loopout_swaps(swap_hash), + + -- asset_id is the asset that is used to pay the swap invoice. + asset_id BYTEA NOT NULL, + + -- swap_rfq_id is the RFQ id that will be used to pay the swap invoice. + swap_rfq_id BYTEA NOT NULL, + + -- prepay_rfq_id is the RFQ id that will be used to pay the prepay + -- invoice. + prepay_rfq_id BYTEA NOT NULL, + + -- asset_amt_paid_swap is the actual asset amt that has been paid for + -- the swap invoice. + asset_amt_paid_swap BIGINT NOT NULL DEFAULT 0, + + -- asset_amt_paid_prepay is the actual asset amt that has been paid for + -- the prepay invoice. + asset_amt_paid_prepay BIGINT NOT NULL DEFAULT 0 +) \ No newline at end of file diff --git a/loopdb/sqlc/models.go b/loopdb/sqlc/models.go index c79ae9b5..88aca93f 100644 --- a/loopdb/sqlc/models.go +++ b/loopdb/sqlc/models.go @@ -86,6 +86,15 @@ type LoopoutSwap struct { PaymentTimeout int32 } +type LoopoutSwapsAssetInfo struct { + SwapHash []byte + AssetID []byte + SwapRfqID []byte + PrepayRfqID []byte + AssetAmtPaidSwap int64 + AssetAmtPaidPrepay int64 +} + type MigrationTracker struct { MigrationID string MigrationTs sql.NullTime diff --git a/loopdb/sqlc/querier.go b/loopdb/sqlc/querier.go index 648eb3b5..a805196c 100644 --- a/loopdb/sqlc/querier.go +++ b/loopdb/sqlc/querier.go @@ -49,6 +49,7 @@ type Querier interface { InsertInstantOutUpdate(ctx context.Context, arg InsertInstantOutUpdateParams) error InsertLoopIn(ctx context.Context, arg InsertLoopInParams) error InsertLoopOut(ctx context.Context, arg InsertLoopOutParams) error + InsertLoopOutAsset(ctx context.Context, arg InsertLoopOutAssetParams) error InsertMigration(ctx context.Context, arg InsertMigrationParams) error InsertReservationUpdate(ctx context.Context, arg InsertReservationUpdateParams) error InsertStaticAddressLoopIn(ctx context.Context, arg InsertStaticAddressLoopInParams) error @@ -60,6 +61,7 @@ type Querier interface { UpdateBatch(ctx context.Context, arg UpdateBatchParams) error UpdateDeposit(ctx context.Context, arg UpdateDepositParams) error UpdateInstantOut(ctx context.Context, arg UpdateInstantOutParams) error + UpdateLoopOutAssetOffchainPayments(ctx context.Context, arg UpdateLoopOutAssetOffchainPaymentsParams) error UpdateReservation(ctx context.Context, arg UpdateReservationParams) error UpdateStaticAddressLoopIn(ctx context.Context, arg UpdateStaticAddressLoopInParams) error UpsertLiquidityParams(ctx context.Context, params []byte) error diff --git a/loopdb/sqlc/queries/swaps.sql b/loopdb/sqlc/queries/swaps.sql index 1cb256b3..6c369f4f 100644 --- a/loopdb/sqlc/queries/swaps.sql +++ b/loopdb/sqlc/queries/swaps.sql @@ -2,13 +2,16 @@ SELECT swaps.*, loopout_swaps.*, - htlc_keys.* + htlc_keys.*, + loopout_swaps_asset_info.* FROM swaps JOIN loopout_swaps ON swaps.swap_hash = loopout_swaps.swap_hash JOIN htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +LEFT JOIN + loopout_swaps_asset_info ON swaps.swap_hash = loopout_swaps_asset_info.swap_hash ORDER BY swaps.id; @@ -16,13 +19,16 @@ ORDER BY SELECT swaps.*, loopout_swaps.*, - htlc_keys.* + htlc_keys.*, + loopout_swaps_asset_info.* FROM swaps JOIN loopout_swaps ON swaps.swap_hash = loopout_swaps.swap_hash JOIN htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +LEFT JOIN + loopout_swaps_asset_info ON swaps.swap_hash = loopout_swaps_asset_info.swap_hash WHERE swaps.swap_hash = $1; @@ -111,6 +117,23 @@ INSERT INTO loopout_swaps ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 ); +-- name: InsertLoopOutAsset :exec +INSERT INTO loopout_swaps_asset_info ( + swap_hash, + asset_id, + swap_rfq_id, + prepay_rfq_id +) VALUES ( + $1, $2, $3, $4 +); + +-- name: UpdateLoopOutAssetOffchainPayments :exec +UPDATE loopout_swaps_asset_info +SET + asset_amt_paid_swap = $2, + asset_amt_paid_prepay = $3 +WHERE swap_hash = $1; + -- name: InsertLoopIn :exec INSERT INTO loopin_swaps ( swap_hash, diff --git a/loopdb/sqlc/swaps.sql.go b/loopdb/sqlc/swaps.sql.go index 17b53864..aca516ca 100644 --- a/loopdb/sqlc/swaps.sql.go +++ b/loopdb/sqlc/swaps.sql.go @@ -7,6 +7,7 @@ package sqlc import ( "context" + "database/sql" "time" ) @@ -185,13 +186,16 @@ const getLoopOutSwap = `-- name: GetLoopOutSwap :one SELECT swaps.id, swaps.swap_hash, swaps.preimage, swaps.initiation_time, swaps.amount_requested, swaps.cltv_expiry, swaps.max_miner_fee, swaps.max_swap_fee, swaps.initiation_height, swaps.protocol_version, swaps.label, loopout_swaps.swap_hash, loopout_swaps.dest_address, loopout_swaps.swap_invoice, loopout_swaps.max_swap_routing_fee, loopout_swaps.sweep_conf_target, loopout_swaps.htlc_confirmations, loopout_swaps.outgoing_chan_set, loopout_swaps.prepay_invoice, loopout_swaps.max_prepay_routing_fee, loopout_swaps.publication_deadline, loopout_swaps.single_sweep, loopout_swaps.payment_timeout, - htlc_keys.swap_hash, htlc_keys.sender_script_pubkey, htlc_keys.receiver_script_pubkey, htlc_keys.sender_internal_pubkey, htlc_keys.receiver_internal_pubkey, htlc_keys.client_key_family, htlc_keys.client_key_index + htlc_keys.swap_hash, htlc_keys.sender_script_pubkey, htlc_keys.receiver_script_pubkey, htlc_keys.sender_internal_pubkey, htlc_keys.receiver_internal_pubkey, htlc_keys.client_key_family, htlc_keys.client_key_index, + loopout_swaps_asset_info.swap_hash, loopout_swaps_asset_info.asset_id, loopout_swaps_asset_info.swap_rfq_id, loopout_swaps_asset_info.prepay_rfq_id, loopout_swaps_asset_info.asset_amt_paid_swap, loopout_swaps_asset_info.asset_amt_paid_prepay FROM swaps JOIN loopout_swaps ON swaps.swap_hash = loopout_swaps.swap_hash JOIN htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +LEFT JOIN + loopout_swaps_asset_info ON swaps.swap_hash = loopout_swaps_asset_info.swap_hash WHERE swaps.swap_hash = $1 ` @@ -227,6 +231,12 @@ type GetLoopOutSwapRow struct { ReceiverInternalPubkey []byte ClientKeyFamily int32 ClientKeyIndex int32 + SwapHash_4 []byte + AssetID []byte + SwapRfqID []byte + PrepayRfqID []byte + AssetAmtPaidSwap sql.NullInt64 + AssetAmtPaidPrepay sql.NullInt64 } func (q *Queries) GetLoopOutSwap(ctx context.Context, swapHash []byte) (GetLoopOutSwapRow, error) { @@ -263,6 +273,12 @@ func (q *Queries) GetLoopOutSwap(ctx context.Context, swapHash []byte) (GetLoopO &i.ReceiverInternalPubkey, &i.ClientKeyFamily, &i.ClientKeyIndex, + &i.SwapHash_4, + &i.AssetID, + &i.SwapRfqID, + &i.PrepayRfqID, + &i.AssetAmtPaidSwap, + &i.AssetAmtPaidPrepay, ) return i, err } @@ -271,13 +287,16 @@ const getLoopOutSwaps = `-- name: GetLoopOutSwaps :many SELECT swaps.id, swaps.swap_hash, swaps.preimage, swaps.initiation_time, swaps.amount_requested, swaps.cltv_expiry, swaps.max_miner_fee, swaps.max_swap_fee, swaps.initiation_height, swaps.protocol_version, swaps.label, loopout_swaps.swap_hash, loopout_swaps.dest_address, loopout_swaps.swap_invoice, loopout_swaps.max_swap_routing_fee, loopout_swaps.sweep_conf_target, loopout_swaps.htlc_confirmations, loopout_swaps.outgoing_chan_set, loopout_swaps.prepay_invoice, loopout_swaps.max_prepay_routing_fee, loopout_swaps.publication_deadline, loopout_swaps.single_sweep, loopout_swaps.payment_timeout, - htlc_keys.swap_hash, htlc_keys.sender_script_pubkey, htlc_keys.receiver_script_pubkey, htlc_keys.sender_internal_pubkey, htlc_keys.receiver_internal_pubkey, htlc_keys.client_key_family, htlc_keys.client_key_index + htlc_keys.swap_hash, htlc_keys.sender_script_pubkey, htlc_keys.receiver_script_pubkey, htlc_keys.sender_internal_pubkey, htlc_keys.receiver_internal_pubkey, htlc_keys.client_key_family, htlc_keys.client_key_index, + loopout_swaps_asset_info.swap_hash, loopout_swaps_asset_info.asset_id, loopout_swaps_asset_info.swap_rfq_id, loopout_swaps_asset_info.prepay_rfq_id, loopout_swaps_asset_info.asset_amt_paid_swap, loopout_swaps_asset_info.asset_amt_paid_prepay FROM swaps JOIN loopout_swaps ON swaps.swap_hash = loopout_swaps.swap_hash JOIN htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +LEFT JOIN + loopout_swaps_asset_info ON swaps.swap_hash = loopout_swaps_asset_info.swap_hash ORDER BY swaps.id ` @@ -313,6 +332,12 @@ type GetLoopOutSwapsRow struct { ReceiverInternalPubkey []byte ClientKeyFamily int32 ClientKeyIndex int32 + SwapHash_4 []byte + AssetID []byte + SwapRfqID []byte + PrepayRfqID []byte + AssetAmtPaidSwap sql.NullInt64 + AssetAmtPaidPrepay sql.NullInt64 } func (q *Queries) GetLoopOutSwaps(ctx context.Context) ([]GetLoopOutSwapsRow, error) { @@ -355,6 +380,12 @@ func (q *Queries) GetLoopOutSwaps(ctx context.Context) ([]GetLoopOutSwapsRow, er &i.ReceiverInternalPubkey, &i.ClientKeyFamily, &i.ClientKeyIndex, + &i.SwapHash_4, + &i.AssetID, + &i.SwapRfqID, + &i.PrepayRfqID, + &i.AssetAmtPaidSwap, + &i.AssetAmtPaidPrepay, ); err != nil { return nil, err } @@ -529,6 +560,34 @@ func (q *Queries) InsertLoopOut(ctx context.Context, arg InsertLoopOutParams) er return err } +const insertLoopOutAsset = `-- name: InsertLoopOutAsset :exec +INSERT INTO loopout_swaps_asset_info ( + swap_hash, + asset_id, + swap_rfq_id, + prepay_rfq_id +) VALUES ( + $1, $2, $3, $4 +) +` + +type InsertLoopOutAssetParams struct { + SwapHash []byte + AssetID []byte + SwapRfqID []byte + PrepayRfqID []byte +} + +func (q *Queries) InsertLoopOutAsset(ctx context.Context, arg InsertLoopOutAssetParams) error { + _, err := q.db.ExecContext(ctx, insertLoopOutAsset, + arg.SwapHash, + arg.AssetID, + arg.SwapRfqID, + arg.PrepayRfqID, + ) + return err +} + const insertSwap = `-- name: InsertSwap :exec INSERT INTO swaps ( swap_hash, @@ -637,3 +696,22 @@ func (q *Queries) OverrideSwapCosts(ctx context.Context, arg OverrideSwapCostsPa ) return err } + +const updateLoopOutAssetOffchainPayments = `-- name: UpdateLoopOutAssetOffchainPayments :exec +UPDATE loopout_swaps_asset_info +SET + asset_amt_paid_swap = $2, + asset_amt_paid_prepay = $3 +WHERE swap_hash = $1 +` + +type UpdateLoopOutAssetOffchainPaymentsParams struct { + SwapHash []byte + AssetAmtPaidSwap int64 + AssetAmtPaidPrepay int64 +} + +func (q *Queries) UpdateLoopOutAssetOffchainPayments(ctx context.Context, arg UpdateLoopOutAssetOffchainPaymentsParams) error { + _, err := q.db.ExecContext(ctx, updateLoopOutAssetOffchainPayments, arg.SwapHash, arg.AssetAmtPaidSwap, arg.AssetAmtPaidPrepay) + return err +} diff --git a/loopdb/store.go b/loopdb/store.go index a43db544..60cce0fb 100644 --- a/loopdb/store.go +++ b/loopdb/store.go @@ -568,6 +568,13 @@ func (s *boltSwapStore) CreateLoopOut(ctx context.Context, hash lntypes.Hash, }) } +// UpdateLoopOutAssetInfo is unused for the bolt swap store. +func (db *boltSwapStore) UpdateLoopOutAssetInfo(ctx context.Context, hash lntypes.Hash, + asset *LoopOutAssetSwap) error { + + return errors.New("unimplemented") +} + // CreateLoopIn adds an initiated swap to the store. // // NOTE: Part of the loopdb.SwapStore interface. diff --git a/loopdb/store_mock.go b/loopdb/store_mock.go index efaf8c4b..0f3dcc66 100644 --- a/loopdb/store_mock.go +++ b/loopdb/store_mock.go @@ -165,6 +165,12 @@ func (s *StoreMock) FetchLoopInSwaps(ctx context.Context) ([]*LoopIn, return result, nil } +func (s *StoreMock) UpdateLoopOutAssetInfo(ctx context.Context, + hash lntypes.Hash, asset *LoopOutAssetSwap) error { + + return errors.New("not implemented") +} + // CreateLoopIn adds an initiated loop in swap to the store. // // NOTE: Part of the SwapStore interface.