Commit 97ae6b1b authored by Hamdi Allam's avatar Hamdi Allam

coalesce eth sends and bridge transfers

parent b4243cc6
...@@ -106,8 +106,7 @@ func (db *bridgeTransfersDB) L1BridgeDeposit(txSourceHash common.Hash) (*L1Bridg ...@@ -106,8 +106,7 @@ func (db *bridgeTransfersDB) L1BridgeDeposit(txSourceHash common.Hash) (*L1Bridg
return &deposit, nil return &deposit, nil
} }
// L1BridgeDepositByCrossDomainMessengerNonce retrieves tokens deposited, specified by the associated `L1CrossDomainMessenger` nonce. // L1BridgeDepositWithFilter queries for a bridge deposit with set fields in the `BridgeTransfer` filter
// All tokens bridged via the StandardBridge flows through the L1CrossDomainMessenger
func (db *bridgeTransfersDB) L1BridgeDepositWithFilter(filter BridgeTransfer) (*L1BridgeDeposit, error) { func (db *bridgeTransfersDB) L1BridgeDepositWithFilter(filter BridgeTransfer) (*L1BridgeDeposit, error) {
var deposit L1BridgeDeposit var deposit L1BridgeDeposit
result := db.gorm.Where(&filter).Take(&deposit) result := db.gorm.Where(&filter).Take(&deposit)
...@@ -127,31 +126,43 @@ type L1BridgeDepositsResponse struct { ...@@ -127,31 +126,43 @@ type L1BridgeDepositsResponse struct {
HasNextPage bool HasNextPage bool
} }
// L1BridgeDepositsByAddress retrieves a list of deposits intiated by the specified address, coupled with the L1/L2 transaction // L1BridgeDepositsByAddress retrieves a list of deposits intiated by the specified address,
// hashes that complete the bridge transaction. // coupled with the L1/L2 transaction hashes that complete the bridge transaction.
func (db *bridgeTransfersDB) L1BridgeDepositsByAddress(address common.Address, cursor string, limit int) (*L1BridgeDepositsResponse, error) { func (db *bridgeTransfersDB) L1BridgeDepositsByAddress(address common.Address, cursor string, limit int) (*L1BridgeDepositsResponse, error) {
defaultLimit := 100 defaultLimit := 100
if limit <= 0 { if limit <= 0 {
limit = defaultLimit limit = defaultLimit
} }
depositsQuery := db.gorm.Table("l1_bridge_deposits").Select(`
l1_bridge_deposits.*,
l1_contract_events.transaction_hash AS l1_transaction_hash,
l1_transaction_deposits.l2_transaction_hash`)
// TODO join with l1_tokens and l2_tokens // TODO join with l1_tokens and l2_tokens
depositsQuery = depositsQuery.Joins("INNER JOIN l1_transaction_deposits ON l1_bridge_deposits.transaction_source_hash = l1_transaction_deposits.source_hash") ethAddressString := predeploys.LegacyERC20ETHAddr.String()
depositsQuery = depositsQuery.Joins("INNER JOIN l1_contract_events ON l1_transaction_deposits.initiated_l1_event_guid = l1_contract_events.guid")
// Coalesce l1 transaction deposits that are ETH receives into bridge deposits.
if cursor != "" { ethTransactionDeposits := db.gorm.Model(&L1TransactionDeposit{})
depositsQuery = depositsQuery.Where("l1_bridge_deposits.transaction_source_hash < ?", cursor) ethTransactionDeposits = ethTransactionDeposits.Where(`from_address = ? AND data = '0x' AND amount > 0`, address.String())
} ethTransactionDeposits = ethTransactionDeposits.Joins("INNER JOIN l1_contract_events ON l1_contract_events.guid = initiated_l1_event_guid")
ethTransactionDeposits = ethTransactionDeposits.Select(`
filteredQuery := depositsQuery.Where(&Transaction{FromAddress: address}).Order("l1_bridge_deposits.transaction_source_hash DESC").Limit(limit + 1) from_address, to_address, amount, data, source_hash AS transaction_source_hash,
l2_transaction_hash, l1_contract_events.transaction_hash AS l1_transaction_hash,
l1_transaction_deposits.timestamp, NULL AS cross_domain_message_hash, ? AS local_token_address, ? AS remote_token_address`, ethAddressString, ethAddressString)
depositsQuery := db.gorm.Model(&L1BridgeDeposit{})
depositsQuery = depositsQuery.Joins("INNER JOIN l1_transaction_deposits ON l1_transaction_deposits.source_hash = transaction_source_hash")
depositsQuery = depositsQuery.Joins("INNER JOIN l1_contract_events ON l1_contract_events.guid = l1_transaction_deposits.initiated_l1_event_guid")
depositsQuery = depositsQuery.Select(`
l1_bridge_deposits.from_address, l1_bridge_deposits.to_address, l1_bridge_deposits.amount, l1_bridge_deposits.data, transaction_source_hash,
l2_transaction_hash, l1_contract_events.transaction_hash as l1_transaction_hash,
l1_bridge_deposits.timestamp, cross_domain_message_hash, local_token_address, remote_token_address`)
// Since all bridge deposits share have the same primary key corresponding to the transaction
// deposit, we can simply order by the timestamp in the transaction deposits table which will
// order all deposits (bridge & transactions) uniformly
query := db.gorm.Table("(?) AS deposits", depositsQuery)
query = query.Joins("UNION (?)", ethTransactionDeposits)
query = query.Select("*").Order("timestamp DESC").Limit(limit)
deposits := []L1BridgeDepositWithTransactionHashes{} deposits := []L1BridgeDepositWithTransactionHashes{}
result := filteredQuery.Scan(&deposits) result := query.Debug().Find(&deposits)
if result.Error != nil { if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) { if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil return nil, nil
...@@ -201,8 +212,7 @@ func (db *bridgeTransfersDB) L2BridgeWithdrawal(txWithdrawalHash common.Hash) (* ...@@ -201,8 +212,7 @@ func (db *bridgeTransfersDB) L2BridgeWithdrawal(txWithdrawalHash common.Hash) (*
return &withdrawal, nil return &withdrawal, nil
} }
// L2BridgeWithdrawalByCrossDomainMessengerNonce retrieves tokens withdrawn, specified by the associated `L2CrossDomainMessenger` nonce. // L2BridgeWithdrawalWithFilter queries for a bridge withdrawal with set fields in the `BridgeTransfer` filter
// All tokens bridged via the StandardBridge flows through the L2CrossDomainMessenger
func (db *bridgeTransfersDB) L2BridgeWithdrawalWithFilter(filter BridgeTransfer) (*L2BridgeWithdrawal, error) { func (db *bridgeTransfersDB) L2BridgeWithdrawalWithFilter(filter BridgeTransfer) (*L2BridgeWithdrawal, error) {
var withdrawal L2BridgeWithdrawal var withdrawal L2BridgeWithdrawal
result := db.gorm.Where(filter).Take(&withdrawal) result := db.gorm.Where(filter).Take(&withdrawal)
......
...@@ -227,6 +227,8 @@ func TestE2EBridgeTransfersOptimismPortalETHReceive(t *testing.T) { ...@@ -227,6 +227,8 @@ func TestE2EBridgeTransfersOptimismPortalETHReceive(t *testing.T) {
aliceDeposits, err := testSuite.DB.BridgeTransfers.L1BridgeDepositsByAddress(aliceAddr, "", 0) aliceDeposits, err := testSuite.DB.BridgeTransfers.L1BridgeDepositsByAddress(aliceAddr, "", 0)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, aliceDeposits)
require.Len(t, aliceDeposits.Deposits, 1)
require.Equal(t, portalDepositTx.Hash(), aliceDeposits.Deposits[0].L1TransactionHash) require.Equal(t, portalDepositTx.Hash(), aliceDeposits.Deposits[0].L1TransactionHash)
deposit := aliceDeposits.Deposits[0].L1BridgeDeposit deposit := aliceDeposits.Deposits[0].L1BridgeDeposit
......
...@@ -184,10 +184,7 @@ CREATE TABLE IF NOT EXISTS l2_bridge_messages( ...@@ -184,10 +184,7 @@ CREATE TABLE IF NOT EXISTS l2_bridge_messages(
-- StandardBridge -- StandardBridge
CREATE TABLE IF NOT EXISTS l1_bridge_deposits ( CREATE TABLE IF NOT EXISTS l1_bridge_deposits (
transaction_source_hash VARCHAR PRIMARY KEY REFERENCES l1_transaction_deposits(source_hash), transaction_source_hash VARCHAR PRIMARY KEY REFERENCES l1_transaction_deposits(source_hash),
-- We allow the cross_domain_message_hash to be NULL-able to account
-- for scenarios where ETH is simply sent to the OptimismPortal contract
cross_domain_message_hash VARCHAR UNIQUE REFERENCES l1_bridge_messages(message_hash), cross_domain_message_hash VARCHAR UNIQUE REFERENCES l1_bridge_messages(message_hash),
-- Deposit information -- Deposit information
...@@ -201,10 +198,7 @@ CREATE TABLE IF NOT EXISTS l1_bridge_deposits ( ...@@ -201,10 +198,7 @@ CREATE TABLE IF NOT EXISTS l1_bridge_deposits (
); );
CREATE TABLE IF NOT EXISTS l2_bridge_withdrawals ( CREATE TABLE IF NOT EXISTS l2_bridge_withdrawals (
transaction_withdrawal_hash VARCHAR PRIMARY KEY REFERENCES l2_transaction_withdrawals(withdrawal_hash), transaction_withdrawal_hash VARCHAR PRIMARY KEY REFERENCES l2_transaction_withdrawals(withdrawal_hash),
cross_domain_message_hash VARCHAR NOT NULL UNIQUE REFERENCES l2_bridge_messages(message_hash),
-- We allow the cross_domain_message_hash to be NULL-able to account for
-- scenarios where ETH is simply sent to the L2ToL1MessagePasser contract
cross_domain_message_hash VARCHAR UNIQUE REFERENCES l2_bridge_messages(message_hash),
-- Withdrawal information -- Withdrawal information
from_address VARCHAR NOT NULL, from_address VARCHAR NOT NULL,
......
...@@ -26,7 +26,6 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, chainConfig ...@@ -26,7 +26,6 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, chainConfig
return err return err
} }
ethDeposits := []database.L1BridgeDeposit{}
portalDeposits := make(map[logKey]*contracts.OptimismPortalTransactionDepositEvent, len(optimismPortalTxDeposits)) portalDeposits := make(map[logKey]*contracts.OptimismPortalTransactionDepositEvent, len(optimismPortalTxDeposits))
transactionDeposits := make([]database.L1TransactionDeposit, len(optimismPortalTxDeposits)) transactionDeposits := make([]database.L1TransactionDeposit, len(optimismPortalTxDeposits))
for i := range optimismPortalTxDeposits { for i := range optimismPortalTxDeposits {
...@@ -39,14 +38,6 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, chainConfig ...@@ -39,14 +38,6 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, chainConfig
GasLimit: depositTx.GasLimit, GasLimit: depositTx.GasLimit,
Tx: depositTx.Tx, Tx: depositTx.Tx,
} }
// catch ETH transfers to the portal contract.
if len(depositTx.DepositTx.Data) == 0 && depositTx.DepositTx.Value.BitLen() > 0 {
ethDeposits = append(ethDeposits, database.L1BridgeDeposit{
TransactionSourceHash: depositTx.DepositTx.SourceHash,
BridgeTransfer: database.BridgeTransfer{Tx: transactionDeposits[i].Tx, TokenPair: database.ETHTokenPair},
})
}
} }
if len(transactionDeposits) > 0 { if len(transactionDeposits) > 0 {
...@@ -54,12 +45,6 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, chainConfig ...@@ -54,12 +45,6 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, chainConfig
if err := db.BridgeTransactions.StoreL1TransactionDeposits(transactionDeposits); err != nil { if err := db.BridgeTransactions.StoreL1TransactionDeposits(transactionDeposits); err != nil {
return err return err
} }
if len(ethDeposits) > 0 {
log.Info("detected portal ETH transfers", "size", len(ethDeposits))
if err := db.BridgeTransfers.StoreL1BridgeDeposits(ethDeposits); err != nil {
return err
}
}
} }
// (2) L1CrossDomainMessenger // (2) L1CrossDomainMessenger
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment