Skip to content

Commit

Permalink
coalesce eth sends from l2
Browse files Browse the repository at this point in the history
  • Loading branch information
hamdiallam committed Aug 22, 2023
1 parent 97ae6b1 commit 25aa02b
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 33 deletions.
54 changes: 36 additions & 18 deletions indexer/database/bridge_transfers.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ func (db *bridgeTransfersDB) L1BridgeDepositsByAddress(address common.Address, c

// Coalesce l1 transaction deposits that are ETH receives into bridge deposits.
ethTransactionDeposits := db.gorm.Model(&L1TransactionDeposit{})
ethTransactionDeposits = ethTransactionDeposits.Where(`from_address = ? AND data = '0x' AND amount > 0`, address.String())
ethTransactionDeposits = ethTransactionDeposits.Where(Transaction{FromAddress: address}).Where(`data = '0x' AND amount > 0`)
ethTransactionDeposits = ethTransactionDeposits.Joins("INNER JOIN l1_contract_events ON l1_contract_events.guid = initiated_l1_event_guid")
ethTransactionDeposits = ethTransactionDeposits.Select(`
from_address, to_address, amount, data, source_hash AS transaction_source_hash,
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)

Expand All @@ -151,13 +151,15 @@ l1_transaction_deposits.timestamp, NULL AS cross_domain_message_hash, ? AS local
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,
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

// TODO: cursoring options

query := db.gorm.Table("(?) AS deposits", depositsQuery)
query = query.Joins("UNION (?)", ethTransactionDeposits)
query = query.Select("*").Order("timestamp DESC").Limit(limit)
Expand Down Expand Up @@ -240,25 +242,41 @@ func (db *bridgeTransfersDB) L2BridgeWithdrawalsByAddress(address common.Address
limit = defaultLimit
}

withdrawalsQuery := db.gorm.Table("l2_bridge_withdrawals").Select(`
l2_bridge_withdrawals.*,
l2_contract_events.transaction_hash AS l2_transaction_hash,
proven_l1_contract_events.transaction_hash AS proven_l1_transaction_hash,
finalized_l1_contract_events.transaction_hash AS finalized_l1_transaction_hash`)

withdrawalsQuery = withdrawalsQuery.Joins("INNER JOIN l2_transaction_withdrawals ON l2_bridge_withdrawals.transaction_withdrawal_hash = l2_transaction_withdrawals.withdrawal_hash")
withdrawalsQuery = withdrawalsQuery.Joins("INNER JOIN l2_contract_events ON l2_transaction_withdrawals.initiated_l2_event_guid = l2_contract_events.guid")
withdrawalsQuery = withdrawalsQuery.Joins("LEFT JOIN l1_contract_events AS proven_l1_contract_events ON l2_transaction_withdrawals.proven_l1_event_guid = proven_l1_contract_events.guid")
withdrawalsQuery = withdrawalsQuery.Joins("LEFT JOIN l1_contract_events AS finalized_l1_contract_events ON l2_transaction_withdrawals.finalized_l1_event_guid = finalized_l1_contract_events.guid")
// TODO join with l1_tokens and l2_tokens
ethAddressString := predeploys.LegacyERC20ETHAddr.String()

if cursor != "" {
withdrawalsQuery = withdrawalsQuery.Where("l2_bridge_withdrawals.id < ?", cursor)
}
// Coalesce l2 transaction withdrawals that are ETH receives
ethTransactionWithdrawals := db.gorm.Model(&L2TransactionWithdrawal{})
ethTransactionWithdrawals = ethTransactionWithdrawals.Where(Transaction{FromAddress: address}).Where(`data = '0x' AND amount > 0`)
ethTransactionWithdrawals = ethTransactionWithdrawals.Joins("INNER JOIN l2_contract_events ON l2_contract_events.guid = l2_transaction_withdrawals.initiated_l2_event_guid")
ethTransactionWithdrawals = ethTransactionWithdrawals.Joins("LEFT JOIN l1_contract_events AS proven_l1_events ON proven_l1_events.guid = l2_transaction_withdrawals.proven_l1_event_guid")
ethTransactionWithdrawals = ethTransactionWithdrawals.Joins("LEFT JOIN l1_contract_events AS finalized_l1_events ON finalized_l1_events.guid = l2_transaction_withdrawals.finalized_l1_event_guid")
ethTransactionWithdrawals = ethTransactionWithdrawals.Select(`
from_address, to_address, amount, data, withdrawal_hash AS transaction_withdrawal_hash,
l2_contract_events.transaction_hash AS l2_transaction_hash, proven_l1_events.transaction_hash AS proven_l1_transaction_hash, finalized_l1_events.transaction_hash AS finalized_l1_transaction_hash,
l2_transaction_withdrawals.timestamp, NULL AS cross_domain_message_hash, ? AS local_token_address, ? AS remote_token_address`, ethAddressString, ethAddressString)

withdrawalsQuery := db.gorm.Model(&L2BridgeWithdrawal{})
withdrawalsQuery = withdrawalsQuery.Joins("INNER JOIN l2_transaction_withdrawals ON withdrawal_hash = l2_bridge_withdrawals.transaction_withdrawal_hash")
withdrawalsQuery = withdrawalsQuery.Joins("INNER JOIN l2_contract_events ON l2_contract_events.guid = l2_transaction_withdrawals.initiated_l2_event_guid")
withdrawalsQuery = withdrawalsQuery.Joins("LEFT JOIN l1_contract_events AS proven_l1_events ON proven_l1_events.guid = l2_transaction_withdrawals.proven_l1_event_guid")
withdrawalsQuery = withdrawalsQuery.Joins("LEFT JOIN l1_contract_events AS finalized_l1_events ON finalized_l1_events.guid = l2_transaction_withdrawals.finalized_l1_event_guid")
withdrawalsQuery = withdrawalsQuery.Select(`
l2_bridge_withdrawals.from_address, l2_bridge_withdrawals.to_address, l2_bridge_withdrawals.amount, l2_bridge_withdrawals.data, transaction_withdrawal_hash,
l2_contract_events.transaction_hash AS l2_transaction_hash, proven_l1_events.transaction_hash AS proven_l1_transaction_hash, finalized_l1_events.transaction_hash AS finalized_l1_transaction_hash,
l2_bridge_withdrawals.timestamp, cross_domain_message_hash, local_token_address, remote_token_address`)

// Since all bridge withdrawals share have the same primary key corresponding to the transaction
// withdrawal, we can simply order by the timestamp in the transaction withdrawal table which will
// order all deposits (bridge & transactions) uniformly

filteredQuery := withdrawalsQuery.Where(&Transaction{FromAddress: address}).Order("l2_bridge_withdrawals.timestamp DESC").Limit(limit + 1)
// TODO: cursoring options

query := db.gorm.Table("(?) AS withdrawals", withdrawalsQuery)
query = query.Joins("UNION (?)", ethTransactionWithdrawals)
query = query.Select("*").Order("timestamp DESC").Limit(limit)
withdrawals := []L2BridgeWithdrawalWithTransactionHashes{}
result := filteredQuery.Scan(&withdrawals)
result := query.Scan(&withdrawals)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
Expand Down
3 changes: 2 additions & 1 deletion indexer/e2e_tests/bridge_transfers_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
require.NotNil(t, crossDomainBridgeMessage.RelayedMessageEventGUID)
}

func TestE2EBridgeTransfersL2ToL1MessagePasserReceive(t *testing.T) {
func TestE2EBridgeTransfersL2ToL1MessagePasserETHReceive(t *testing.T) {
testSuite := createE2ETestSuite(t)

optimismPortal, err := bindings.NewOptimismPortal(testSuite.OpCfg.L1Deployments.OptimismPortalProxy, testSuite.L1Client)
Expand Down Expand Up @@ -378,6 +378,7 @@ func TestE2EBridgeTransfersL2ToL1MessagePasserReceive(t *testing.T) {

aliceWithdrawals, err := testSuite.DB.BridgeTransfers.L2BridgeWithdrawalsByAddress(aliceAddr, "", 0)
require.NoError(t, err)
require.Len(t, aliceWithdrawals.Withdrawals, 1)
require.Equal(t, l2ToL1MessagePasserWithdrawTx.Hash().String(), aliceWithdrawals.Withdrawals[0].L2TransactionHash.String())

msgPassed, err := withdrawals.ParseMessagePassed(l2ToL1WithdrawReceipt)
Expand Down
14 changes: 0 additions & 14 deletions indexer/processors/bridge/l2_bridge_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, fromHeight
return err
}

ethWithdrawals := []database.L2BridgeWithdrawal{}
messagesPassed := make(map[logKey]*contracts.L2ToL1MessagePasserMessagePassed, len(l2ToL1MPMessagesPassed))
transactionWithdrawals := make([]database.L2TransactionWithdrawal, len(l2ToL1MPMessagesPassed))
for i := range l2ToL1MPMessagesPassed {
Expand All @@ -39,26 +38,13 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, fromHeight
GasLimit: messagePassed.GasLimit,
Tx: messagePassed.Tx,
}

if len(messagePassed.Tx.Data) == 0 && messagePassed.Tx.Amount.Int.BitLen() > 0 {
ethWithdrawals = append(ethWithdrawals, database.L2BridgeWithdrawal{
TransactionWithdrawalHash: messagePassed.WithdrawalHash,
BridgeTransfer: database.BridgeTransfer{Tx: transactionWithdrawals[i].Tx, TokenPair: database.ETHTokenPair},
})
}
}

if len(messagesPassed) > 0 {
log.Info("detected transaction withdrawals", "size", len(transactionWithdrawals))
if err := db.BridgeTransactions.StoreL2TransactionWithdrawals(transactionWithdrawals); err != nil {
return err
}
if len(ethWithdrawals) > 0 {
log.Info("detected L2ToL1MessagePasser ETH transfers", "size", len(ethWithdrawals))
if err := db.BridgeTransfers.StoreL2BridgeWithdrawals(ethWithdrawals); err != nil {
return err
}
}
}

// (2) L2CrossDomainMessenger
Expand Down

0 comments on commit 25aa02b

Please sign in to comment.