Commit 35f2e3d5 authored by Hamdi Allam's avatar Hamdi Allam

standared_bridge code dedup with generics

parent d93a9a1a
...@@ -78,20 +78,19 @@ func DecodeFromProcessedEvents[ABI any](p *ProcessedContractEvents, name string, ...@@ -78,20 +78,19 @@ func DecodeFromProcessedEvents[ABI any](p *ProcessedContractEvents, name string,
return decodedEvents, nil return decodedEvents, nil
} }
func UnpackLog[EventType any](log *types.Log, name string, contractAbi *abi.ABI) (*EventType, error) { func UnpackLog(out interface{}, log *types.Log, name string, contractAbi *abi.ABI) error {
eventAbi, ok := contractAbi.Events[name] eventAbi, ok := contractAbi.Events[name]
if !ok { if !ok {
return nil, errors.New(fmt.Sprintf("event %s not present in supplied ABI", name)) return errors.New(fmt.Sprintf("event %s not present in supplied ABI", name))
} else if len(log.Topics) == 0 { } else if len(log.Topics) == 0 {
return nil, errors.New("anonymous events are not supported") return errors.New("anonymous events are not supported")
} else if log.Topics[0] != eventAbi.ID { } else if log.Topics[0] != eventAbi.ID {
return nil, errors.New("event signature mismatch not present in supplied ABI") return errors.New("event signature mismatch not present in supplied ABI")
} }
var event EventType err := contractAbi.UnpackIntoInterface(out, name, log.Data)
err := contractAbi.UnpackIntoInterface(&event, name, log.Data)
if err != nil { if err != nil {
return nil, err return err
} }
// handle topics if present // handle topics if present
...@@ -104,11 +103,11 @@ func UnpackLog[EventType any](log *types.Log, name string, contractAbi *abi.ABI) ...@@ -104,11 +103,11 @@ func UnpackLog[EventType any](log *types.Log, name string, contractAbi *abi.ABI)
} }
// The first topic (event signature) is ommitted // The first topic (event signature) is ommitted
err := abi.ParseTopics(&event, indexedArgs, log.Topics[1:]) err := abi.ParseTopics(out, indexedArgs, log.Topics[1:])
if err != nil { if err != nil {
return nil, err return err
} }
} }
return &event, nil return nil
} }
...@@ -207,7 +207,7 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -207,7 +207,7 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
numFinalizedDeposits := len(finalizationBridgeEvents) numFinalizedDeposits := len(finalizationBridgeEvents)
if numFinalizedDeposits > 0 { if numFinalizedDeposits > 0 {
processLog.Info("finalized deposits", "size", numFinalizedDeposits) processLog.Info("finalized L1StandardBridge deposits", "size", numFinalizedDeposits)
} }
// a-ok // a-ok
......
...@@ -18,6 +18,8 @@ var ( ...@@ -18,6 +18,8 @@ var (
) )
type StandardBridgeInitiatedEvent struct { type StandardBridgeInitiatedEvent struct {
// We hardcode to ERC20 since ETH can be psuedo-represented as an ERC20 utilizing
// the hardcoded ETH address
*bindings.L1StandardBridgeERC20BridgeInitiated *bindings.L1StandardBridgeERC20BridgeInitiated
CrossDomainMessengerNonce *big.Int CrossDomainMessengerNonce *big.Int
...@@ -25,6 +27,8 @@ type StandardBridgeInitiatedEvent struct { ...@@ -25,6 +27,8 @@ type StandardBridgeInitiatedEvent struct {
} }
type StandardBridgeFinalizedEvent struct { type StandardBridgeFinalizedEvent struct {
// We hardcode to ERC20 since ETH can be psuedo-represented as an ERC20 utilizing
// the hardcoded ETH address
*bindings.L1StandardBridgeERC20BridgeFinalized *bindings.L1StandardBridgeERC20BridgeFinalized
CrossDomainMessengerNonce *big.Int CrossDomainMessengerNonce *big.Int
...@@ -33,7 +37,37 @@ type StandardBridgeFinalizedEvent struct { ...@@ -33,7 +37,37 @@ type StandardBridgeFinalizedEvent struct {
// StandardBridgeInitiatedEvents extracts all initiated bridge events from the contracts that follow the StandardBridge ABI. The // StandardBridgeInitiatedEvents extracts all initiated bridge events from the contracts that follow the StandardBridge ABI. The
// correlated CrossDomainMessenger nonce is also parsed from the associated messenger events. // correlated CrossDomainMessenger nonce is also parsed from the associated messenger events.
func StandardBridgeInitiatedEvents(events *ProcessedContractEvents) ([]*StandardBridgeInitiatedEvent, error) { func StandardBridgeInitiatedEvents(events *ProcessedContractEvents) ([]StandardBridgeInitiatedEvent, error) {
ethBridgeInitiatedEvents, err := _standardBridgeInitiatedEvents[bindings.L1StandardBridgeETHBridgeInitiated](events)
if err != nil {
return nil, err
}
erc20BridgeInitiatedEvents, err := _standardBridgeInitiatedEvents[bindings.L1StandardBridgeERC20BridgeInitiated](events)
if err != nil {
return nil, err
}
return append(ethBridgeInitiatedEvents, erc20BridgeInitiatedEvents...), nil
}
// StandardBridgeFinalizedEvents extracts all finalization bridge events from the contracts that follow the StandardBridge ABI. The
// correlated CrossDomainMessenger nonce is also parsed by looking at the parameters of the corresponding relayMessage transaction data.
func StandardBridgeFinalizedEvents(rawEthClient *ethclient.Client, events *ProcessedContractEvents) ([]StandardBridgeFinalizedEvent, error) {
ethBridgeFinalizedEvents, err := _standardBridgeFinalizedEvents[bindings.L1StandardBridgeETHBridgeFinalized](rawEthClient, events)
if err != nil {
return nil, err
}
erc20BridgeFinalizedEvents, err := _standardBridgeFinalizedEvents[bindings.L1StandardBridgeERC20BridgeFinalized](rawEthClient, events)
if err != nil {
return nil, err
}
return append(ethBridgeFinalizedEvents, erc20BridgeFinalizedEvents...), nil
}
func _standardBridgeInitiatedEvents[BridgeEvent bindings.L1StandardBridgeETHBridgeInitiated | bindings.L1StandardBridgeERC20BridgeInitiated](events *ProcessedContractEvents) ([]StandardBridgeInitiatedEvent, error) {
l1StandardBridgeABI, err := bindings.L1StandardBridgeMetaData.GetAbi() l1StandardBridgeABI, err := bindings.L1StandardBridgeMetaData.GetAbi()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -44,82 +78,77 @@ func StandardBridgeInitiatedEvents(events *ProcessedContractEvents) ([]*Standard ...@@ -44,82 +78,77 @@ func StandardBridgeInitiatedEvents(events *ProcessedContractEvents) ([]*Standard
return nil, err return nil, err
} }
ethBridgeInitiatedEventAbi := l1StandardBridgeABI.Events["ETHBridgeInitiated"]
erc20BridgeInitiatedEventAbi := l1StandardBridgeABI.Events["ERC20BridgeInitiated"]
sentMessageEventAbi := l1CrossDomainMessengerABI.Events["SentMessage"] sentMessageEventAbi := l1CrossDomainMessengerABI.Events["SentMessage"]
ethBridgeInitiatedEvents := events.eventsBySignature[ethBridgeInitiatedEventAbi.ID] var bridgeData BridgeEvent
erc20BridgeInitiatedEvents := events.eventsBySignature[erc20BridgeInitiatedEventAbi.ID] var eventName string
initiatedBridgeEvents := []*StandardBridgeInitiatedEvent{} var finalizeMethodName string
switch any(bridgeData).(type) {
case bindings.L1StandardBridgeETHBridgeInitiated:
eventName = "ETHBridgeInitiated"
finalizeMethodName = "finalizeBridgeETH"
case bindings.L1StandardBridgeERC20BridgeInitiated:
eventName = "ERC20BridgeInitiated"
finalizeMethodName = "finalizeBridgeERC20"
default:
panic("should not be here")
}
// Handle ETH Bridge processedInitiatedBridgeEvents := events.eventsBySignature[l1StandardBridgeABI.Events[eventName].ID]
for _, bridgeInitiatedEvent := range ethBridgeInitiatedEvents { initiatedBridgeEvents := make([]StandardBridgeInitiatedEvent, len(processedInitiatedBridgeEvents))
for i, bridgeInitiatedEvent := range processedInitiatedBridgeEvents {
log := events.eventLog[bridgeInitiatedEvent.GUID] log := events.eventLog[bridgeInitiatedEvent.GUID]
bridgeData, err := UnpackLog[bindings.L1StandardBridgeETHBridgeInitiated](log, ethBridgeInitiatedEventAbi.Name, l1StandardBridgeABI) err := UnpackLog(&bridgeData, log, eventName, l1StandardBridgeABI)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Look for the sent message event to extract the associated messager nonce // Look for the sent message event to extract the associated messager nonce
// - The `SentMessage` event is the second after the bridge initiated event. BridgeInitiated -> Portal#DepositTransaction -> SentMesage ... // - The `SentMessage` event is the second after the bridge initiated event. BridgeInitiated -> Portal#DepositTransaction -> SentMesage ...
var sentMsgData bindings.L1CrossDomainMessengerSentMessage
sentMsgLog := events.eventLog[events.eventByLogIndex[log.Index+2].GUID] sentMsgLog := events.eventLog[events.eventByLogIndex[log.Index+2].GUID]
sentMsgData, err := UnpackLog[bindings.L1CrossDomainMessengerSentMessage](sentMsgLog, sentMessageEventAbi.Name, l1CrossDomainMessengerABI) err = UnpackLog(&sentMsgData, sentMsgLog, sentMessageEventAbi.Name, l1CrossDomainMessengerABI)
if err != nil {
return nil, err
}
expectedMsg, err := l1StandardBridgeABI.Pack("finalizeBridgeETH", bridgeData.From, bridgeData.To, bridgeData.Amount, bridgeData.ExtraData)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !bytes.Equal(sentMsgData.Message, expectedMsg) {
return nil, errors.New("bridge cross domain message mismatch")
} }
initiatedBridgeEvents = append(initiatedBridgeEvents, &StandardBridgeInitiatedEvent{ var erc20BridgeData *bindings.L1StandardBridgeERC20BridgeInitiated
&bindings.L1StandardBridgeERC20BridgeInitiated{ var expectedCrossDomainMessage []byte
// Default ETH switch any(bridgeData).(type) {
case bindings.L1StandardBridgeETHBridgeInitiated:
ethBridgeData := any(bridgeData).(bindings.L1StandardBridgeETHBridgeInitiated)
expectedCrossDomainMessage, err = l1StandardBridgeABI.Pack(finalizeMethodName, ethBridgeData.From, ethBridgeData.To, ethBridgeData.Amount, ethBridgeData.ExtraData)
if err != nil {
return nil, err
}
erc20BridgeData = &bindings.L1StandardBridgeERC20BridgeInitiated{
// Represent ETH using the hardcoded address
LocalToken: ethAddress, RemoteToken: ethAddress, LocalToken: ethAddress, RemoteToken: ethAddress,
// Bridge data
From: ethBridgeData.From, To: ethBridgeData.To, Amount: ethBridgeData.Amount, ExtraData: ethBridgeData.ExtraData,
}
// BridgeDAta case bindings.L1StandardBridgeERC20BridgeInitiated:
From: bridgeData.From, To: bridgeData.To, Amount: bridgeData.Amount, ExtraData: bridgeData.ExtraData, _temp := any(bridgeData).(bindings.L1StandardBridgeERC20BridgeInitiated)
}, // TODO: fix this as bridgeData is the same pointer
sentMsgData.MessageNonce, erc20BridgeData = &_temp
bridgeInitiatedEvent, expectedCrossDomainMessage, err = l1StandardBridgeABI.Pack(finalizeMethodName, erc20BridgeData.RemoteToken, erc20BridgeData.LocalToken, erc20BridgeData.From, erc20BridgeData.To, erc20BridgeData.Amount, erc20BridgeData.ExtraData)
}) if err != nil {
} return nil, err
}
// Handle ERC20 Bridge
for _, bridgeInitiatedEvent := range erc20BridgeInitiatedEvents {
log := events.eventLog[bridgeInitiatedEvent.GUID]
bridgeData, err := UnpackLog[bindings.L1StandardBridgeERC20BridgeInitiated](log, erc20BridgeInitiatedEventAbi.Name, l1StandardBridgeABI)
if err != nil {
return nil, err
}
// Look for the sent message event to extract the associated messager nonce
// - The `SentMessage` event is the second after the bridge initiated event. BridgeInitiated -> Portal#DepositTransaction -> SentMesage ...
sentMsgLog := events.eventLog[events.eventByLogIndex[log.Index+2].GUID]
sentMsgData, err := UnpackLog[bindings.L1CrossDomainMessengerSentMessage](sentMsgLog, sentMessageEventAbi.Name, l1CrossDomainMessengerABI)
if err != nil {
return nil, err
} }
expectedMsg, err := l1StandardBridgeABI.Pack("finalizeBridgeERC20", bridgeData.RemoteToken, bridgeData.LocalToken, bridgeData.From, bridgeData.To, bridgeData.Amount, bridgeData.ExtraData) if !bytes.Equal(sentMsgData.Message, expectedCrossDomainMessage) {
if err != nil {
return nil, err
} else if !bytes.Equal(sentMsgData.Message, expectedMsg) {
return nil, errors.New("bridge cross domain message mismatch") return nil, errors.New("bridge cross domain message mismatch")
} }
initiatedBridgeEvents = append(initiatedBridgeEvents, &StandardBridgeInitiatedEvent{bridgeData, sentMsgData.MessageNonce, bridgeInitiatedEvent}) initiatedBridgeEvents[i] = StandardBridgeInitiatedEvent{erc20BridgeData, sentMsgData.MessageNonce, bridgeInitiatedEvent}
} }
return initiatedBridgeEvents, nil return initiatedBridgeEvents, nil
} }
// StandardBridgeFinalizedEvents extracts all finalization bridge events from the contracts that follow the StandardBridge ABI. The func _standardBridgeFinalizedEvents[BridgeEvent bindings.L1StandardBridgeETHBridgeFinalized | bindings.L1StandardBridgeERC20BridgeFinalized](rawEthClient *ethclient.Client, events *ProcessedContractEvents) ([]StandardBridgeFinalizedEvent, error) {
// correlated CrossDomainMessenger nonce is also parsed by looking at the parameters of the corresponding relayMessage transaction data.
func StandardBridgeFinalizedEvents(rawEthClient *ethclient.Client, events *ProcessedContractEvents) ([]*StandardBridgeFinalizedEvent, error) {
l1StandardBridgeABI, err := bindings.L1StandardBridgeMetaData.GetAbi() l1StandardBridgeABI, err := bindings.L1StandardBridgeMetaData.GetAbi()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -130,19 +159,25 @@ func StandardBridgeFinalizedEvents(rawEthClient *ethclient.Client, events *Proce ...@@ -130,19 +159,25 @@ func StandardBridgeFinalizedEvents(rawEthClient *ethclient.Client, events *Proce
return nil, err return nil, err
} }
ethBridgeFinalizedEventAbi := l1StandardBridgeABI.Events["ETHBridgeFinalized"]
erc20BridgeFinalizedEventAbi := l1StandardBridgeABI.Events["ERC20BridgeFinalized"]
relayedMessageEventAbi := l1CrossDomainMessengerABI.Events["RelayedMessage"] relayedMessageEventAbi := l1CrossDomainMessengerABI.Events["RelayedMessage"]
relayMessageMethodAbi := l1CrossDomainMessengerABI.Methods["relayMessage"] relayMessageMethodAbi := l1CrossDomainMessengerABI.Methods["relayMessage"]
ethBridgeFinalizedEvents := events.eventsBySignature[ethBridgeFinalizedEventAbi.ID] var bridgeData BridgeEvent
erc20BridgeFinalizedEvents := events.eventsBySignature[erc20BridgeFinalizedEventAbi.ID] var eventName string
finalizedBridgeEvents := []*StandardBridgeFinalizedEvent{} switch any(bridgeData).(type) {
case bindings.L1StandardBridgeETHBridgeFinalized:
eventName = "ETHBridgeFinalized"
case bindings.L1StandardBridgeERC20BridgeFinalized:
eventName = "ERC20BridgeFinalized"
default:
panic("should not be here")
}
// Handle ETH Bridge processedFinalizedBridgeEvents := events.eventsBySignature[l1StandardBridgeABI.Events[eventName].ID]
for _, bridgeFinalizedEvent := range ethBridgeFinalizedEvents { finalizedBridgeEvents := make([]StandardBridgeFinalizedEvent, len(processedFinalizedBridgeEvents))
for i, bridgeFinalizedEvent := range processedFinalizedBridgeEvents {
log := events.eventLog[bridgeFinalizedEvent.GUID] log := events.eventLog[bridgeFinalizedEvent.GUID]
bridgeData, err := UnpackLog[bindings.L1StandardBridgeETHBridgeFinalized](log, ethBridgeFinalizedEventAbi.Name, l1StandardBridgeABI) err := UnpackLog(&bridgeData, log, eventName, l1StandardBridgeABI)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -176,57 +211,24 @@ func StandardBridgeFinalizedEvents(rawEthClient *ethclient.Client, events *Proce ...@@ -176,57 +211,24 @@ func StandardBridgeFinalizedEvents(rawEthClient *ethclient.Client, events *Proce
return nil, errors.New("unable to extract `_nonce` parameter from relayMessage transaction") return nil, errors.New("unable to extract `_nonce` parameter from relayMessage transaction")
} }
finalizedBridgeEvents = append(finalizedBridgeEvents, &StandardBridgeFinalizedEvent{ var erc20BridgeData *bindings.L1StandardBridgeERC20BridgeFinalized
&bindings.L1StandardBridgeERC20BridgeFinalized{ switch any(bridgeData).(type) {
// Default ETH case bindings.L1StandardBridgeETHBridgeInitiated:
ethBridgeData := any(bridgeData).(bindings.L1StandardBridgeETHBridgeFinalized)
erc20BridgeData = &bindings.L1StandardBridgeERC20BridgeFinalized{
// Represent ETH using the hardcoded address
LocalToken: ethAddress, RemoteToken: ethAddress, LocalToken: ethAddress, RemoteToken: ethAddress,
// Bridge data
From: ethBridgeData.From, To: ethBridgeData.To, Amount: ethBridgeData.Amount, ExtraData: ethBridgeData.ExtraData,
}
// BridgeDAta case bindings.L1StandardBridgeERC20BridgeInitiated:
From: bridgeData.From, To: bridgeData.To, Amount: bridgeData.Amount, ExtraData: bridgeData.ExtraData, _temp := any(bridgeData).(bindings.L1StandardBridgeERC20BridgeFinalized)
}, // TODO: fix this as bridgeData is the same pointer
nonce, erc20BridgeData = &_temp
bridgeFinalizedEvent,
})
}
// Handle ERC20 Bridge
for _, bridgeFinalizedEvent := range erc20BridgeFinalizedEvents {
log := events.eventLog[bridgeFinalizedEvent.GUID]
bridgeData, err := UnpackLog[bindings.L1StandardBridgeERC20BridgeFinalized](log, erc20BridgeFinalizedEventAbi.Name, l1StandardBridgeABI)
if err != nil {
return nil, err
}
// Look for the RelayedMessage event that follows right after the BridgeFinalized Event
relayedMsgLog := events.eventLog[events.eventByLogIndex[log.Index+1].GUID]
if relayedMsgLog.Topics[0] != relayedMessageEventAbi.ID {
return nil, errors.New("unexpected bridge event ordering")
}
// There's no way to extract the nonce on the relayed message event. we can extract
// the nonce by unpacking the transaction input for the `relayMessage` transaction
tx, isPending, err := rawEthClient.TransactionByHash(context.Background(), relayedMsgLog.TxHash)
if err != nil || isPending {
return nil, errors.New("unable to query relayMessage tx for bridge finalization event")
}
txData := tx.Data()
if !bytes.Equal(txData[:4], relayMessageMethodAbi.ID) {
return nil, errors.New("bridge finalization event does not match relayMessage tx invocation")
}
inputsMap := make(map[string]interface{})
err = relayMessageMethodAbi.Inputs.UnpackIntoMap(inputsMap, txData[4:])
if err != nil {
return nil, err
}
nonce, ok := inputsMap["_nonce"].(*big.Int)
if !ok {
return nil, errors.New("unable to extract `_nonce` parameter from relayMessage transaction")
} }
finalizedBridgeEvents = append(finalizedBridgeEvents, &StandardBridgeFinalizedEvent{bridgeData, nonce, bridgeFinalizedEvent}) finalizedBridgeEvents[i] = StandardBridgeFinalizedEvent{erc20BridgeData, nonce, bridgeFinalizedEvent}
} }
return finalizedBridgeEvents, nil return finalizedBridgeEvents, nil
......
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