Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
cc91c03c
Commit
cc91c03c
authored
Aug 03, 2023
by
Hamdi Allam
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bridge transaction/transfer schema & models
parent
42ac06a8
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
936 additions
and
253 deletions
+936
-253
bridge_transactions.go
indexer/database/bridge_transactions.go
+152
-0
bridge_transfers.go
indexer/database/bridge_transfers.go
+43
-84
db.go
indexer/database/db.go
+14
-11
bridge_transactions_e2e_test.go
indexer/e2e_tests/bridge_transactions_e2e_test.go
+166
-0
bridge_transfers_e2e_test.go
indexer/e2e_tests/bridge_transfers_e2e_test.go
+131
-19
20230523_create_schema.sql
indexer/migrations/20230523_create_schema.sql
+56
-27
encoding.go
indexer/processor/encoding.go
+24
-0
l1_processor.go
indexer/processor/l1_processor.go
+153
-65
l2_processor.go
indexer/processor/l2_processor.go
+92
-46
l2_to_l1_message_passer.go
indexer/processor/l2_to_l1_message_passer.go
+35
-0
optimism_portal.go
indexer/processor/optimism_portal.go
+70
-1
No files found.
indexer/database/bridge_transactions.go
0 → 100644
View file @
cc91c03c
package
database
import
(
"errors"
"fmt"
"github.com/google/uuid"
"gorm.io/gorm"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
/**
* Types
*/
type
Transaction
struct
{
FromAddress
common
.
Address
`gorm:"serializer:json"`
ToAddress
common
.
Address
`gorm:"serializer:json"`
Amount
U256
Data
hexutil
.
Bytes
`gorm:"serializer:json"`
Timestamp
uint64
}
type
L1TransactionDeposit
struct
{
SourceHash
common
.
Hash
`gorm:"serializer:json;primaryKey"`
L2TransactionHash
common
.
Hash
`gorm:"serializer:json"`
InitiatedL1EventGUID
uuid
.
UUID
Version
U256
OpaqueData
hexutil
.
Bytes
`gorm:"serializer:json"`
Tx
Transaction
`gorm:"embedded"`
GasLimit
U256
}
type
L2TransactionWithdrawal
struct
{
WithdrawalHash
common
.
Hash
`gorm:"serializer:json;primaryKey"`
InitiatedL2EventGUID
uuid
.
UUID
ProvenL1EventGUID
*
uuid
.
UUID
FinalizedL1EventGUID
*
uuid
.
UUID
Nonce
U256
Tx
Transaction
`gorm:"embedded"`
GasLimit
U256
}
type
BridgeTransactionsView
interface
{
L1TransactionDeposit
(
common
.
Hash
)
(
*
L1TransactionDeposit
,
error
)
L2TransactionWithdrawal
(
common
.
Hash
)
(
*
L2TransactionWithdrawal
,
error
)
}
type
BridgeTransactionsDB
interface
{
BridgeTransactionsView
StoreL1TransactionDeposits
([]
*
L1TransactionDeposit
)
error
StoreL2TransactionWithdrawals
([]
*
L2TransactionWithdrawal
)
error
MarkL2TransactionWithdrawalProvenEvent
(
common
.
Hash
,
uuid
.
UUID
)
error
MarkL2TransactionWithdrawalFinalizedEvent
(
common
.
Hash
,
uuid
.
UUID
)
error
}
/**
* Implementation
*/
type
bridgeTransactionsDB
struct
{
gorm
*
gorm
.
DB
}
func
newBridgeTransactionsDB
(
db
*
gorm
.
DB
)
BridgeTransactionsDB
{
return
&
bridgeTransactionsDB
{
gorm
:
db
}
}
/**
* Transactions deposited from L1
*/
func
(
db
*
bridgeTransactionsDB
)
StoreL1TransactionDeposits
(
deposits
[]
*
L1TransactionDeposit
)
error
{
result
:=
db
.
gorm
.
Create
(
&
deposits
)
return
result
.
Error
}
func
(
db
*
bridgeTransactionsDB
)
L1TransactionDeposit
(
sourceHash
common
.
Hash
)
(
*
L1TransactionDeposit
,
error
)
{
var
deposit
L1TransactionDeposit
result
:=
db
.
gorm
.
Where
(
&
L1TransactionDeposit
{
SourceHash
:
sourceHash
})
.
Take
(
&
deposit
)
if
result
.
Error
!=
nil
{
if
errors
.
Is
(
result
.
Error
,
gorm
.
ErrRecordNotFound
)
{
return
nil
,
nil
}
return
nil
,
result
.
Error
}
return
&
deposit
,
nil
}
/**
* Transactions withdrawn from L2
*/
func
(
db
*
bridgeTransactionsDB
)
StoreL2TransactionWithdrawals
(
withdrawals
[]
*
L2TransactionWithdrawal
)
error
{
result
:=
db
.
gorm
.
Create
(
&
withdrawals
)
return
result
.
Error
}
func
(
db
*
bridgeTransactionsDB
)
L2TransactionWithdrawal
(
withdrawalHash
common
.
Hash
)
(
*
L2TransactionWithdrawal
,
error
)
{
var
withdrawal
L2TransactionWithdrawal
result
:=
db
.
gorm
.
Where
(
&
L2TransactionWithdrawal
{
WithdrawalHash
:
withdrawalHash
})
.
Take
(
&
withdrawal
)
if
result
.
Error
!=
nil
{
if
errors
.
Is
(
result
.
Error
,
gorm
.
ErrRecordNotFound
)
{
return
nil
,
nil
}
return
nil
,
result
.
Error
}
return
&
withdrawal
,
nil
}
// MarkL2TransactionWithdrawalProvenEvent links a withdrawn transaction with associated Prove action on L1.
func
(
db
*
bridgeTransactionsDB
)
MarkL2TransactionWithdrawalProvenEvent
(
withdrawalHash
common
.
Hash
,
provenL1EventGuid
uuid
.
UUID
)
error
{
withdrawal
,
err
:=
db
.
L2TransactionWithdrawal
(
withdrawalHash
)
if
err
!=
nil
{
return
err
}
else
if
withdrawal
==
nil
{
return
fmt
.
Errorf
(
"transaction withdrawal hash %s not found"
,
withdrawalHash
)
}
withdrawal
.
ProvenL1EventGUID
=
&
provenL1EventGuid
result
:=
db
.
gorm
.
Save
(
&
withdrawal
)
return
result
.
Error
}
// MarkL2TransactionWithdrawalProvenEvent links a withdrawn transaction in its finalized state
func
(
db
*
bridgeTransactionsDB
)
MarkL2TransactionWithdrawalFinalizedEvent
(
withdrawalHash
common
.
Hash
,
finalizedL1EventGuid
uuid
.
UUID
)
error
{
withdrawal
,
err
:=
db
.
L2TransactionWithdrawal
(
withdrawalHash
)
if
err
!=
nil
{
return
err
}
else
if
withdrawal
==
nil
{
return
fmt
.
Errorf
(
"transaction withdrawal hash %s not found"
,
withdrawalHash
)
}
else
if
withdrawal
.
ProvenL1EventGUID
==
nil
{
return
fmt
.
Errorf
(
"cannot mark unproven withdrawal hash %s as finalized"
,
withdrawal
.
WithdrawalHash
)
}
withdrawal
.
FinalizedL1EventGUID
=
&
finalizedL1EventGuid
result
:=
db
.
gorm
.
Save
(
&
withdrawal
)
return
result
.
Error
}
indexer/database/bridge_transfers.go
View file @
cc91c03c
This diff is collapsed.
Click to expand it.
indexer/database/db.go
View file @
cc91c03c
...
...
@@ -10,9 +10,10 @@ import (
type
DB
struct
{
gorm
*
gorm
.
DB
Blocks
BlocksDB
ContractEvents
ContractEventsDB
BridgeTransfers
BridgeTransfersDB
Blocks
BlocksDB
ContractEvents
ContractEventsDB
BridgeTransfers
BridgeTransfersDB
BridgeTransactions
BridgeTransactionsDB
}
func
NewDB
(
dsn
string
)
(
*
DB
,
error
)
{
...
...
@@ -31,10 +32,11 @@ func NewDB(dsn string) (*DB, error) {
}
db
:=
&
DB
{
gorm
:
gorm
,
Blocks
:
newBlocksDB
(
gorm
),
ContractEvents
:
newContractEventsDB
(
gorm
),
BridgeTransfers
:
newBridgeTransfersDB
(
gorm
),
gorm
:
gorm
,
Blocks
:
newBlocksDB
(
gorm
),
ContractEvents
:
newContractEventsDB
(
gorm
),
BridgeTransactions
:
newBridgeTransactionsDB
(
gorm
),
BridgeTransfers
:
newBridgeTransfersDB
(
gorm
),
}
return
db
,
nil
...
...
@@ -59,9 +61,10 @@ func (db *DB) Close() error {
func
dbFromGormTx
(
tx
*
gorm
.
DB
)
*
DB
{
return
&
DB
{
gorm
:
tx
,
Blocks
:
newBlocksDB
(
tx
),
ContractEvents
:
newContractEventsDB
(
tx
),
BridgeTransfers
:
newBridgeTransfersDB
(
tx
),
gorm
:
tx
,
Blocks
:
newBlocksDB
(
tx
),
ContractEvents
:
newContractEventsDB
(
tx
),
BridgeTransactions
:
newBridgeTransactionsDB
(
tx
),
BridgeTransfers
:
newBridgeTransfersDB
(
tx
),
}
}
indexer/e2e_tests/bridge_transactions_e2e_test.go
0 → 100644
View file @
cc91c03c
package
e2e_tests
import
(
"context"
"math/big"
"testing"
"time"
e2etest_utils
"github.com/ethereum-optimism/optimism/indexer/e2e_tests/utils"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
op_e2e
"github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
func
TestE2EBridgeTransactionsOptimismPortalDeposits
(
t
*
testing
.
T
)
{
testSuite
:=
createE2ETestSuite
(
t
)
optimismPortal
,
err
:=
bindings
.
NewOptimismPortal
(
testSuite
.
OpCfg
.
L1Deployments
.
OptimismPortalProxy
,
testSuite
.
L1Client
)
require
.
NoError
(
t
,
err
)
aliceAddr
:=
testSuite
.
OpCfg
.
Secrets
.
Addresses
()
.
Alice
// attach 1 ETH to the deposit and random calldata
calldata
:=
[]
byte
{
byte
(
1
),
byte
(
2
),
byte
(
3
)}
l1Opts
,
err
:=
bind
.
NewKeyedTransactorWithChainID
(
testSuite
.
OpCfg
.
Secrets
.
Alice
,
testSuite
.
OpCfg
.
L1ChainIDBig
())
require
.
NoError
(
t
,
err
)
l1Opts
.
Value
=
big
.
NewInt
(
params
.
Ether
)
depositTx
,
err
:=
optimismPortal
.
DepositTransaction
(
l1Opts
,
aliceAddr
,
l1Opts
.
Value
,
100
_000
,
false
,
calldata
)
require
.
NoError
(
t
,
err
)
depositReceipt
,
err
:=
utils
.
WaitReceiptOK
(
context
.
Background
(),
testSuite
.
L1Client
,
depositTx
.
Hash
())
require
.
NoError
(
t
,
err
)
depositInfo
,
err
:=
e2etest_utils
.
ParseDepositInfo
(
depositReceipt
)
require
.
NoError
(
t
,
err
)
depositL2TxHash
:=
types
.
NewTx
(
depositInfo
.
DepositTx
)
.
Hash
()
// wait for processor catchup
require
.
NoError
(
t
,
utils
.
WaitFor
(
context
.
Background
(),
500
*
time
.
Millisecond
,
func
()
(
bool
,
error
)
{
l1Header
:=
testSuite
.
Indexer
.
L1Processor
.
LatestProcessedHeader
()
return
l1Header
!=
nil
&&
l1Header
.
Number
.
Uint64
()
>=
depositReceipt
.
BlockNumber
.
Uint64
(),
nil
}))
deposit
,
err
:=
testSuite
.
DB
.
BridgeTransactions
.
L1TransactionDeposit
(
depositInfo
.
DepositTx
.
SourceHash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
depositL2TxHash
,
deposit
.
L2TransactionHash
)
require
.
Equal
(
t
,
big
.
NewInt
(
100
_000
),
deposit
.
GasLimit
.
Int
)
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
deposit
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
aliceAddr
,
deposit
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
deposit
.
Tx
.
ToAddress
)
require
.
ElementsMatch
(
t
,
calldata
,
deposit
.
Tx
.
Data
)
require
.
Equal
(
t
,
depositInfo
.
Version
.
Uint64
(),
deposit
.
Version
.
Int
.
Uint64
())
require
.
ElementsMatch
(
t
,
depositInfo
.
OpaqueData
,
deposit
.
OpaqueData
)
event
,
err
:=
testSuite
.
DB
.
ContractEvents
.
L1ContractEvent
(
deposit
.
InitiatedL1EventGUID
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
event
)
require
.
Equal
(
t
,
event
.
TransactionHash
,
depositTx
.
Hash
())
// NOTE: The indexer does not track deposit inclusion as it's apart of the block derivation process.
// If this changes, we'd like to test for this here.
}
func
TestE2EBridgeTransactionsL2ToL1MessagePasserWithdrawal
(
t
*
testing
.
T
)
{
testSuite
:=
createE2ETestSuite
(
t
)
optimismPortal
,
err
:=
bindings
.
NewOptimismPortal
(
testSuite
.
OpCfg
.
L1Deployments
.
OptimismPortalProxy
,
testSuite
.
L1Client
)
require
.
NoError
(
t
,
err
)
l2ToL1MessagePasser
,
err
:=
bindings
.
NewL2ToL1MessagePasser
(
predeploys
.
L2ToL1MessagePasserAddr
,
testSuite
.
L2Client
)
require
.
NoError
(
t
,
err
)
aliceAddr
:=
testSuite
.
OpCfg
.
Secrets
.
Addresses
()
.
Alice
// attach 1 ETH to the withdrawal and random calldata
calldata
:=
[]
byte
{
byte
(
1
),
byte
(
2
),
byte
(
3
)}
l2Opts
,
err
:=
bind
.
NewKeyedTransactorWithChainID
(
testSuite
.
OpCfg
.
Secrets
.
Alice
,
testSuite
.
OpCfg
.
L2ChainIDBig
())
require
.
NoError
(
t
,
err
)
l2Opts
.
Value
=
big
.
NewInt
(
params
.
Ether
)
// Ensure L1 has enough funds for the withdrawal by depositing an equal amount into the OptimismPortal
l1Opts
,
err
:=
bind
.
NewKeyedTransactorWithChainID
(
testSuite
.
OpCfg
.
Secrets
.
Alice
,
testSuite
.
OpCfg
.
L1ChainIDBig
())
require
.
NoError
(
t
,
err
)
l1Opts
.
Value
=
l2Opts
.
Value
depositTx
,
err
:=
optimismPortal
.
Receive
(
l1Opts
)
require
.
NoError
(
t
,
err
)
_
,
err
=
utils
.
WaitReceiptOK
(
context
.
Background
(),
testSuite
.
L1Client
,
depositTx
.
Hash
())
require
.
NoError
(
t
,
err
)
withdrawTx
,
err
:=
l2ToL1MessagePasser
.
InitiateWithdrawal
(
l2Opts
,
aliceAddr
,
big
.
NewInt
(
100
_000
),
calldata
)
require
.
NoError
(
t
,
err
)
withdrawReceipt
,
err
:=
utils
.
WaitReceiptOK
(
context
.
Background
(),
testSuite
.
L2Client
,
withdrawTx
.
Hash
())
require
.
NoError
(
t
,
err
)
// wait for processor catchup
require
.
NoError
(
t
,
utils
.
WaitFor
(
context
.
Background
(),
500
*
time
.
Millisecond
,
func
()
(
bool
,
error
)
{
l2Header
:=
testSuite
.
Indexer
.
L2Processor
.
LatestProcessedHeader
()
return
l2Header
!=
nil
&&
l2Header
.
Number
.
Uint64
()
>=
withdrawReceipt
.
BlockNumber
.
Uint64
(),
nil
}))
msgPassed
,
err
:=
withdrawals
.
ParseMessagePassed
(
withdrawReceipt
)
require
.
NoError
(
t
,
err
)
withdrawalHash
,
err
:=
withdrawals
.
WithdrawalHash
(
msgPassed
)
require
.
NoError
(
t
,
err
)
withdraw
,
err
:=
testSuite
.
DB
.
BridgeTransactions
.
L2TransactionWithdrawal
(
withdrawalHash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
msgPassed
.
Nonce
.
Uint64
(),
withdraw
.
Nonce
.
Int
.
Uint64
())
require
.
Equal
(
t
,
big
.
NewInt
(
100
_000
),
withdraw
.
GasLimit
.
Int
)
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
withdraw
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
aliceAddr
,
withdraw
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
withdraw
.
Tx
.
ToAddress
)
require
.
ElementsMatch
(
t
,
calldata
,
withdraw
.
Tx
.
Data
)
event
,
err
:=
testSuite
.
DB
.
ContractEvents
.
L2ContractEvent
(
withdraw
.
InitiatedL2EventGUID
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
event
)
require
.
Equal
(
t
,
event
.
TransactionHash
,
withdrawTx
.
Hash
())
// Test Withdrawal Proven
require
.
Nil
(
t
,
withdraw
.
ProvenL1EventGUID
)
require
.
Nil
(
t
,
withdraw
.
FinalizedL1EventGUID
)
withdrawParams
,
proveReceipt
:=
op_e2e
.
ProveWithdrawal
(
t
,
*
testSuite
.
OpCfg
,
testSuite
.
L1Client
,
testSuite
.
OpSys
.
Nodes
[
"sequencer"
],
testSuite
.
OpCfg
.
Secrets
.
Alice
,
withdrawReceipt
)
require
.
NoError
(
t
,
utils
.
WaitFor
(
context
.
Background
(),
500
*
time
.
Millisecond
,
func
()
(
bool
,
error
)
{
l1Header
:=
testSuite
.
Indexer
.
L1Processor
.
LatestProcessedHeader
()
return
l1Header
!=
nil
&&
l1Header
.
Number
.
Uint64
()
>=
proveReceipt
.
BlockNumber
.
Uint64
(),
nil
}))
withdraw
,
err
=
testSuite
.
DB
.
BridgeTransactions
.
L2TransactionWithdrawal
(
withdrawalHash
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
withdraw
.
ProvenL1EventGUID
)
proveEvent
,
err
:=
testSuite
.
DB
.
ContractEvents
.
L1ContractEvent
(
*
withdraw
.
ProvenL1EventGUID
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
event
)
require
.
Equal
(
t
,
proveEvent
.
TransactionHash
,
proveReceipt
.
TxHash
)
// Test Withdrawal Finalized
require
.
Nil
(
t
,
withdraw
.
FinalizedL1EventGUID
)
finalizeReceipt
:=
op_e2e
.
FinalizeWithdrawal
(
t
,
*
testSuite
.
OpCfg
,
testSuite
.
L1Client
,
testSuite
.
OpCfg
.
Secrets
.
Alice
,
proveReceipt
,
withdrawParams
)
require
.
NoError
(
t
,
utils
.
WaitFor
(
context
.
Background
(),
500
*
time
.
Millisecond
,
func
()
(
bool
,
error
)
{
l1Header
:=
testSuite
.
Indexer
.
L1Processor
.
LatestProcessedHeader
()
return
l1Header
!=
nil
&&
l1Header
.
Number
.
Uint64
()
>=
finalizeReceipt
.
BlockNumber
.
Uint64
(),
nil
}))
withdraw
,
err
=
testSuite
.
DB
.
BridgeTransactions
.
L2TransactionWithdrawal
(
withdrawalHash
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
withdraw
.
FinalizedL1EventGUID
)
finalizedEvent
,
err
:=
testSuite
.
DB
.
ContractEvents
.
L1ContractEvent
(
*
withdraw
.
FinalizedL1EventGUID
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
event
)
require
.
Equal
(
t
,
finalizedEvent
.
TransactionHash
,
finalizeReceipt
.
TxHash
)
}
indexer/e2e_tests/bridge_transfers_e2e_test.go
View file @
cc91c03c
This diff is collapsed.
Click to expand it.
indexer/migrations/20230523_create_schema.sql
View file @
cc91c03c
CREATE
DOMAIN
UINT256
AS
NUMERIC
NOT
NULL
CREATE
DOMAIN
UINT256
AS
NUMERIC
CHECK
(
VALUE
>=
0
AND
VALUE
<
2
^
256
and
SCALE
(
VALUE
)
=
0
);
/**
...
...
@@ -9,7 +9,7 @@ CREATE DOMAIN UINT256 AS NUMERIC NOT NULL
CREATE
TABLE
IF
NOT
EXISTS
l1_block_headers
(
hash
VARCHAR
NOT
NULL
PRIMARY
KEY
,
parent_hash
VARCHAR
NOT
NULL
,
number
UINT256
,
number
UINT256
NOT
NULL
,
timestamp
INTEGER
NOT
NULL
CHECK
(
timestamp
>
0
)
);
...
...
@@ -17,7 +17,7 @@ CREATE TABLE IF NOT EXISTS l2_block_headers (
-- Block header
hash
VARCHAR
NOT
NULL
PRIMARY
KEY
,
parent_hash
VARCHAR
NOT
NULL
,
number
UINT256
,
number
UINT256
NOT
NULL
,
timestamp
INTEGER
NOT
NULL
CHECK
(
timestamp
>
0
)
);
...
...
@@ -57,8 +57,8 @@ CREATE TABLE IF NOT EXISTS legacy_state_batches (
CREATE
TABLE
IF
NOT
EXISTS
output_proposals
(
output_root
VARCHAR
NOT
NULL
PRIMARY
KEY
,
l2_output_index
UINT256
,
l2_block_number
UINT256
,
l2_output_index
UINT256
NOT
NULL
,
l2_block_number
UINT256
NOT
NULL
,
l1_contract_event_guid
VARCHAR
REFERENCES
l1_contract_events
(
guid
)
);
...
...
@@ -67,47 +67,76 @@ CREATE TABLE IF NOT EXISTS output_proposals (
* BRIDGING DATA
*/
-- OptimismPortal/L2ToL1MessagePasser
CREATE
TABLE
IF
NOT
EXISTS
l1_transaction_deposits
(
source_hash
VARCHAR
NOT
NULL
PRIMARY
KEY
,
l2_transaction_hash
VARCHAR
NOT
NULL
,
initiated_l1_event_guid
VARCHAR
NOT
NULL
REFERENCES
l1_contract_events
(
guid
),
-- OptimismPortal specific
version
UINT256
NOT
NULL
,
opaque_data
VARCHAR
NOT
NULL
,
-- transaction data
from_address
VARCHAR
NOT
NULL
,
to_address
VARCHAR
NOT
NULL
,
amount
UINT256
NOT
NULL
,
gas_limit
UINT256
NOT
NULL
,
data
VARCHAR
NOT
NULL
,
timestamp
INTEGER
NOT
NULL
CHECK
(
timestamp
>
0
)
);
CREATE
TABLE
IF
NOT
EXISTS
l2_transaction_withdrawals
(
withdrawal_hash
VARCHAR
NOT
NULL
PRIMARY
KEY
,
initiated_l2_event_guid
VARCHAR
NOT
NULL
REFERENCES
l2_contract_events
(
guid
),
-- Multistep (bedrock) process of a withdrawal
proven_l1_event_guid
VARCHAR
REFERENCES
l1_contract_events
(
guid
),
finalized_l1_event_guid
VARCHAR
REFERENCES
l1_contract_events
(
guid
),
-- L2ToL1MessagePasser specific
nonce
UINT256
UNIQUE
,
-- transaction data
from_address
VARCHAR
NOT
NULL
,
to_address
VARCHAR
NOT
NULL
,
amount
UINT256
NOT
NULL
,
gas_limit
UINT256
NOT
NULL
,
data
VARCHAR
NOT
NULL
,
timestamp
INTEGER
NOT
NULL
CHECK
(
timestamp
>
0
)
);
-- StandardBridge
CREATE
TABLE
IF
NOT
EXISTS
l1_bridge_deposits
(
guid
VARCHAR
PRIMARY
KEY
NOT
NULL
,
transaction_source_hash
VARCHAR
PRIMARY
KEY
REFERENCES
l1_transaction_deposits
(
source_hash
)
,
--
Event causing the deposi
t
initiated_l1_event_guid
VARCHAR
NOT
NULL
REFERENCES
l1_contract_events
(
guid
),
--
We allow the cross_domain_messenger_nonce to be NULL-able to accoun
t
-- for scenarios where ETH is simply sent to the OptimismPortal contract
cross_domain_messenger_nonce
UINT256
UNIQUE
,
-- Finalization marker for the deposit
finalized_l2_event_guid
VARCHAR
REFERENCES
l2_contract_events
(
guid
),
-- Deposit information (do we need indexes on from/to?)
-- Deposit information
from_address
VARCHAR
NOT
NULL
,
to_address
VARCHAR
NOT
NULL
,
l1_token_address
VARCHAR
NOT
NULL
,
l2_token_address
VARCHAR
NOT
NULL
,
amount
UINT256
,
amount
UINT256
NOT
NULL
,
data
VARCHAR
NOT
NULL
,
timestamp
INTEGER
NOT
NULL
CHECK
(
timestamp
>
0
)
);
CREATE
TABLE
IF
NOT
EXISTS
l2_bridge_withdrawals
(
guid
VARCHAR
PRIMARY
KEY
NOT
NULL
,
transaction_withdrawal_hash
VARCHAR
PRIMARY
KEY
REFERENCES
l2_transaction_withdrawals
(
withdrawal_hash
)
,
--
Event causing this withdrawal
initiated_l2_event_guid
VARCHAR
NOT
NULL
REFERENCES
l2_contract_events
(
guid
),
--
We allow the cross_domain_messenger_nonce to be NULL-able to account for
-- scenarios where ETH is simply sent to the L2ToL1MessagePasser contract
cross_domain_messenger_nonce
UINT256
UNIQUE
,
-- Multistep (bedrock) process of a withdrawal
withdrawal_hash
VARCHAR
NOT
NULL
,
proven_l1_event_guid
VARCHAR
REFERENCES
l1_contract_events
(
guid
),
-- Finalization marker (legacy & bedrock)
finalized_l1_event_guid
VARCHAR
REFERENCES
l1_contract_events
(
guid
),
-- Withdrawal information (do we need indexes on from/to?)
-- Withdrawal information
from_address
VARCHAR
NOT
NULL
,
to_address
VARCHAR
NOT
NULL
,
l1_token_address
VARCHAR
NOT
NULL
,
l2_token_address
VARCHAR
NOT
NULL
,
amount
UINT256
,
amount
UINT256
NOT
NULL
,
data
VARCHAR
NOT
NULL
,
timestamp
INTEGER
NOT
NULL
CHECK
(
timestamp
>
0
)
);
indexer/processor/encoding.go
0 → 100644
View file @
cc91c03c
package
processor
import
(
"encoding/binary"
"math/big"
)
// DecodeVersionNonce is an re-implementation of Encoding.sol#decodeVersionedNonce.
// If the nonce is greater than 32 bytes (solidity uint256), bytes [32:] are ignored
func
DecodeVersionedNonce
(
nonce
*
big
.
Int
)
(
uint16
,
*
big
.
Int
)
{
nonceBytes
:=
nonce
.
Bytes
()
nonceByteLen
:=
len
(
nonceBytes
)
if
nonceByteLen
<
30
{
// version is 0x0000
return
0
,
nonce
}
else
if
nonceByteLen
==
31
{
// version is 0x00[01..ff]
return
uint16
(
nonceBytes
[
0
]),
new
(
big
.
Int
)
.
SetBytes
(
nonceBytes
[
1
:
])
}
else
{
// fully specified
version
:=
binary
.
BigEndian
.
Uint16
(
nonceBytes
[
:
2
])
return
version
,
new
(
big
.
Int
)
.
SetBytes
(
nonceBytes
[
2
:
])
}
}
indexer/processor/l1_processor.go
View file @
cc91c03c
This diff is collapsed.
Click to expand it.
indexer/processor/l2_processor.go
View file @
cc91c03c
package
processor
import
(
"bytes"
"context"
"errors"
"reflect"
...
...
@@ -8,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/
google/uuid
"
"github.com/
ethereum-optimism/optimism/op-bindings/predeploys
"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -155,8 +156,14 @@ func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2
return
err
}
// forward along contract events to the bridge processor
err
=
l2BridgeProcessContractEvents
(
processLog
,
db
,
ethClient
,
processedContractEvents
)
// forward along contract events to bridge txs processor
err
=
l2ProcessContractEventsBridgeTransactions
(
processLog
,
db
,
processedContractEvents
)
if
err
!=
nil
{
return
err
}
// forward along contract events to standard bridge processor
err
=
l2ProcessContractEventsStandardBridge
(
processLog
,
db
,
ethClient
,
processedContractEvents
)
if
err
!=
nil
{
return
err
}
...
...
@@ -167,17 +174,73 @@ func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2
}
}
func
l2BridgeProcessContractEvents
(
processLog
log
.
Logger
,
db
*
database
.
DB
,
ethClient
node
.
EthClient
,
events
*
ProcessedContractEvents
)
error
{
func
l2ProcessContractEventsBridgeTransactions
(
processLog
log
.
Logger
,
db
*
database
.
DB
,
events
*
ProcessedContractEvents
)
error
{
// (1) Process New Withdrawals
messagesPassed
,
err
:=
L2ToL1MessagePasserMessagesPassed
(
events
)
if
err
!=
nil
{
return
err
}
ethWithdrawals
:=
[]
*
database
.
L2BridgeWithdrawal
{}
transactionWithdrawals
:=
make
([]
*
database
.
L2TransactionWithdrawal
,
len
(
messagesPassed
))
for
i
,
withdrawalEvent
:=
range
messagesPassed
{
transactionWithdrawals
[
i
]
=
&
database
.
L2TransactionWithdrawal
{
WithdrawalHash
:
withdrawalEvent
.
WithdrawalHash
,
InitiatedL2EventGUID
:
withdrawalEvent
.
RawEvent
.
GUID
,
Nonce
:
database
.
U256
{
Int
:
withdrawalEvent
.
Nonce
},
GasLimit
:
database
.
U256
{
Int
:
withdrawalEvent
.
GasLimit
},
Tx
:
database
.
Transaction
{
FromAddress
:
withdrawalEvent
.
Sender
,
ToAddress
:
withdrawalEvent
.
Target
,
Amount
:
database
.
U256
{
Int
:
withdrawalEvent
.
Value
},
Data
:
withdrawalEvent
.
Data
,
Timestamp
:
withdrawalEvent
.
RawEvent
.
Timestamp
,
},
}
if
len
(
withdrawalEvent
.
Data
)
==
0
&&
withdrawalEvent
.
Value
.
BitLen
()
>
0
{
ethWithdrawals
=
append
(
ethWithdrawals
,
&
database
.
L2BridgeWithdrawal
{
TransactionWithdrawalHash
:
withdrawalEvent
.
WithdrawalHash
,
Tx
:
transactionWithdrawals
[
i
]
.
Tx
,
TokenPair
:
database
.
TokenPair
{
L1TokenAddress
:
predeploys
.
LegacyERC20ETHAddr
,
L2TokenAddress
:
predeploys
.
LegacyERC20ETHAddr
,
},
})
}
}
if
len
(
transactionWithdrawals
)
>
0
{
processLog
.
Info
(
"detected transaction withdrawals"
,
"size"
,
len
(
transactionWithdrawals
))
db
.
BridgeTransactions
.
StoreL2TransactionWithdrawals
(
transactionWithdrawals
)
if
len
(
ethWithdrawals
)
>
0
{
processLog
.
Info
(
"detected L2ToL1MessagePasser ETH transfers"
,
"size"
,
len
(
ethWithdrawals
))
err
:=
db
.
BridgeTransfers
.
StoreL2BridgeWithdrawals
(
ethWithdrawals
)
if
err
!=
nil
{
return
err
}
}
}
// (2) Process Deposit Finalization
// - Since L2 deposits are apart of the block derivation processes, we dont track finalization as it's too tricky
// to do so purely from the L2-side since there is not a way to easily identify deposit transations on L2 without walking
// the transaction list of every L2 epoch.
// a-ok!
return
nil
}
func
l2ProcessContractEventsStandardBridge
(
processLog
log
.
Logger
,
db
*
database
.
DB
,
ethClient
node
.
EthClient
,
events
*
ProcessedContractEvents
)
error
{
rawEthClient
:=
ethclient
.
NewClient
(
ethClient
.
RawRpcClient
())
l2ToL1MessagePasserABI
,
err
:=
bindings
.
L2ToL1MessagePasserMetaData
.
GetAbi
(
)
l2ToL1MessagePasserABI
,
err
:=
bindings
.
NewL2ToL1MessagePasser
(
common
.
Address
{},
nil
)
if
err
!=
nil
{
return
err
}
messagePassedEventAbi
:=
l2ToL1MessagePasserABI
.
Events
[
"MessagePassed"
]
// Process New Withdrawals
// (1) Process New Withdrawals
initiatedWithdrawalEvents
,
err
:=
StandardBridgeInitiatedEvents
(
events
)
if
err
!=
nil
{
return
err
...
...
@@ -187,19 +250,16 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
for
i
,
initiatedBridgeEvent
:=
range
initiatedWithdrawalEvents
{
log
:=
events
.
eventLog
[
initiatedBridgeEvent
.
RawEvent
.
GUID
]
// extract the withdrawal hash from the MessagePassed event
var
msgPassedData
bindings
.
L2ToL1MessagePasserMessagePassed
// extract the withdrawal hash from the following MessagePassed event
msgPassedLog
:=
events
.
eventLog
[
events
.
eventByLogIndex
[
ProcessedContractEventLogIndexKey
{
log
.
BlockHash
,
log
.
Index
+
1
}]
.
GUID
]
err
:=
UnpackLog
(
&
msgPassedData
,
msgPassedLog
,
messagePassedEventAbi
.
Name
,
l2ToL1MessagePasserABI
)
msgPassedEvent
,
err
:=
l2ToL1MessagePasserABI
.
ParseMessagePassed
(
*
msgPassedLog
)
if
err
!=
nil
{
return
err
}
withdrawals
[
i
]
=
&
database
.
L2BridgeWithdrawal
{
GUID
:
uuid
.
New
(),
InitiatedL2EventGUID
:
initiatedBridgeEvent
.
RawEvent
.
GUID
,
CrossDomainMessengerNonce
:
database
.
U256
{
Int
:
initiatedBridgeEvent
.
CrossDomainMessengerNonce
},
WithdrawalHash
:
msgPassedData
.
WithdrawalHash
,
TransactionWithdrawalHash
:
msgPassedEvent
.
WithdrawalHash
,
CrossDomainMessengerNonce
:
&
database
.
U256
{
Int
:
initiatedBridgeEvent
.
CrossDomainMessengerNonce
},
TokenPair
:
database
.
TokenPair
{
L1TokenAddress
:
initiatedBridgeEvent
.
LocalToken
,
L2TokenAddress
:
initiatedBridgeEvent
.
RemoteToken
},
Tx
:
database
.
Transaction
{
FromAddress
:
initiatedBridgeEvent
.
From
,
...
...
@@ -219,49 +279,35 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
}
}
// Finalize Deposits
finalizationBridgeEvents
,
err
:=
StandardBridgeFinalizedEvents
(
rawEthClient
,
events
)
if
err
!=
nil
{
return
err
}
// (2) Process Finalized Deposits
// - We dont need do anything actionable on the database here as this is layered on top of the
// bridge transaction & messages that have a tracked lifecyle. We simply walk through and ensure
// that the corresponding initiated deposits exist as an integrity check
latestL1Header
,
err
:=
db
.
Blocks
.
LatestL1BlockHeader
(
)
finalizedDepositEvents
,
err
:=
StandardBridgeFinalizedEvents
(
rawEthClient
,
events
)
if
err
!=
nil
{
return
err
}
else
if
len
(
finalizationBridgeEvents
)
>
0
&&
latestL1Header
==
nil
{
return
errors
.
New
(
"no indexed L1 state to process any L2 bridge finalizations"
)
}
for
_
,
finalizedBridgeEvent
:=
range
finalizationBridgeEvents
{
nonce
:=
finalizedBridgeEvent
.
CrossDomainMessengerNonce
deposit
,
err
:=
db
.
BridgeTransfers
.
L1BridgeDepositByCrossDomainMessengerNonce
(
nonce
)
for
_
,
finalizedDepositEvent
:=
range
finalizedDepositEvents
{
deposit
,
err
:=
db
.
BridgeTransfers
.
L1BridgeDepositByCrossDomainMessengerNonce
(
finalizedDepositEvent
.
CrossDomainMessengerNonce
)
if
err
!=
nil
{
processLog
.
Error
(
"error querying associated deposit messsage using nonce"
,
"cross_domain_messenger_nonce"
,
nonce
)
return
err
}
else
if
deposit
==
nil
{
// Check if the L1Processor is behind or really has missed an event. Since L2 timestamps
// are derived from L1, we can simply compare timestamps
if
finalizedBridgeEvent
.
RawEvent
.
Timestamp
>
latestL1Header
.
Timestamp
{
processLog
.
Warn
(
"behind on indexed L1StandardBridge deposits"
)
return
errors
.
New
(
"waiting for L1Processor to catch up"
)
}
else
{
processLog
.
Crit
(
"missing indexed L1StandardBridge deposit for this finalization event"
)
return
errors
.
New
(
"missing deposit message"
)
}
// NOTE: We'll be indexing CrossDomainMessenger messages that'll ensure we're in a caught up state here
processLog
.
Error
(
"missing indexed L1StandardBridge deposit on finalization"
,
"cross_domain_messenger_nonce"
,
finalizedDepositEvent
.
CrossDomainMessengerNonce
)
return
errors
.
New
(
"missing indexed L1StandardBridge deposit on finalization"
)
}
err
=
db
.
BridgeTransfers
.
MarkFinalizedL1BridgeDepositEvent
(
deposit
.
GUID
,
finalizedBridgeEvent
.
RawEvent
.
GUID
)
if
err
!=
nil
{
processLog
.
Error
(
"error finalizing deposit"
,
"err"
,
err
)
return
err
// sanity check on the bridge fields
if
finalizedDepositEvent
.
From
!=
deposit
.
Tx
.
FromAddress
||
finalizedDepositEvent
.
To
!=
deposit
.
Tx
.
ToAddress
||
finalizedDepositEvent
.
Amount
.
Cmp
(
deposit
.
Tx
.
Amount
.
Int
)
!=
0
||
!
bytes
.
Equal
(
finalizedDepositEvent
.
ExtraData
,
deposit
.
Tx
.
Data
)
||
finalizedDepositEvent
.
LocalToken
!=
deposit
.
TokenPair
.
L1TokenAddress
||
finalizedDepositEvent
.
RemoteToken
!=
deposit
.
TokenPair
.
L2TokenAddress
{
processLog
.
Error
(
"bridge finalization fields mismatch with initiated fields!"
,
"tx_source_hash"
,
deposit
.
TransactionSourceHash
,
"cross_domain_messenger_nonce"
,
deposit
.
CrossDomainMessengerNonce
.
Int
)
return
errors
.
New
(
"bridge tx mismatch"
)
}
}
if
len
(
finalizationBridgeEvents
)
>
0
{
processLog
.
Info
(
"finalized L1StandardBridge deposits"
,
"size"
,
len
(
finalizationBridgeEvents
))
}
// a-ok
// a-ok!
return
nil
}
indexer/processor/l2_to_l1_message_passer.go
0 → 100644
View file @
cc91c03c
package
processor
import
(
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
)
type
L2ToL1MessagePasserMessagePassed
struct
{
*
bindings
.
L2ToL1MessagePasserMessagePassed
RawEvent
*
database
.
ContractEvent
}
func
L2ToL1MessagePasserMessagesPassed
(
events
*
ProcessedContractEvents
)
([]
L2ToL1MessagePasserMessagePassed
,
error
)
{
l2ToL1MessagePasserAbi
,
err
:=
bindings
.
L2ToL1MessagePasserMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
eventName
:=
"MessagePassed"
processedMessagePassedEvents
:=
events
.
eventsBySignature
[
l2ToL1MessagePasserAbi
.
Events
[
eventName
]
.
ID
]
messagesPassed
:=
make
([]
L2ToL1MessagePasserMessagePassed
,
len
(
processedMessagePassedEvents
))
for
i
,
messagePassedEvent
:=
range
processedMessagePassedEvents
{
log
:=
events
.
eventLog
[
messagePassedEvent
.
GUID
]
var
messagePassed
bindings
.
L2ToL1MessagePasserMessagePassed
err
:=
UnpackLog
(
&
messagePassed
,
log
,
eventName
,
l2ToL1MessagePasserAbi
)
if
err
!=
nil
{
return
nil
,
err
}
messagesPassed
[
i
]
=
L2ToL1MessagePasserMessagePassed
{
&
messagePassed
,
messagePassedEvent
}
}
return
messagesPassed
,
nil
}
indexer/processor/optimism_portal.go
View file @
cc91c03c
...
...
@@ -2,19 +2,32 @@ package processor
import
(
"context"
"errors"
"math/big"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)
type
OptimismPortalTransactionDepositEvent
struct
{
*
bindings
.
OptimismPortalTransactionDeposited
DepositTx
*
types
.
DepositTx
RawEvent
*
database
.
ContractEvent
}
type
OptimismPortalWithdrawalProvenEvent
struct
{
*
bindings
.
OptimismPortalWithdrawalProven
RawEvent
*
database
.
ContractEvent
}
type
OptimismPortalWithdrawalFinalizedEvent
struct
{
*
bindings
.
OptimismPortalWithdrawalFinalized
RawEvent
*
database
.
ContractEvent
}
...
...
@@ -24,6 +37,39 @@ type OptimismPortalProvenWithdrawal struct {
L2OutputIndex
*
big
.
Int
}
func
OptimismPortalTransactionDepositEvents
(
events
*
ProcessedContractEvents
)
([]
OptimismPortalTransactionDepositEvent
,
error
)
{
optimismPortalAbi
,
err
:=
bindings
.
OptimismPortalMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
eventName
:=
"TransactionDeposited"
if
optimismPortalAbi
.
Events
[
eventName
]
.
ID
!=
derive
.
DepositEventABIHash
{
return
nil
,
errors
.
New
(
"op-node deposit event abi hash & optimism portal tx deposit mismatch"
)
}
processedTxDepositedEvents
:=
events
.
eventsBySignature
[
derive
.
DepositEventABIHash
]
txDeposits
:=
make
([]
OptimismPortalTransactionDepositEvent
,
len
(
processedTxDepositedEvents
))
for
i
,
txDepositEvent
:=
range
processedTxDepositedEvents
{
log
:=
events
.
eventLog
[
txDepositEvent
.
GUID
]
depositTx
,
err
:=
derive
.
UnmarshalDepositLogEvent
(
log
)
if
err
!=
nil
{
return
nil
,
err
}
var
txDeposit
bindings
.
OptimismPortalTransactionDeposited
err
=
UnpackLog
(
&
txDeposit
,
log
,
eventName
,
optimismPortalAbi
)
if
err
!=
nil
{
return
nil
,
err
}
txDeposits
[
i
]
=
OptimismPortalTransactionDepositEvent
{
&
txDeposit
,
depositTx
,
txDepositEvent
}
}
return
txDeposits
,
nil
}
func
OptimismPortalWithdrawalProvenEvents
(
events
*
ProcessedContractEvents
)
([]
OptimismPortalWithdrawalProvenEvent
,
error
)
{
optimismPortalAbi
,
err
:=
bindings
.
OptimismPortalMetaData
.
GetAbi
()
if
err
!=
nil
{
...
...
@@ -31,7 +77,6 @@ func OptimismPortalWithdrawalProvenEvents(events *ProcessedContractEvents) ([]Op
}
eventName
:=
"WithdrawalProven"
processedWithdrawalProvenEvents
:=
events
.
eventsBySignature
[
optimismPortalAbi
.
Events
[
eventName
]
.
ID
]
provenEvents
:=
make
([]
OptimismPortalWithdrawalProvenEvent
,
len
(
processedWithdrawalProvenEvents
))
for
i
,
provenEvent
:=
range
processedWithdrawalProvenEvents
{
...
...
@@ -49,6 +94,30 @@ func OptimismPortalWithdrawalProvenEvents(events *ProcessedContractEvents) ([]Op
return
provenEvents
,
nil
}
func
OptimismPortalWithdrawalFinalizedEvents
(
events
*
ProcessedContractEvents
)
([]
OptimismPortalWithdrawalFinalizedEvent
,
error
)
{
optimismPortalAbi
,
err
:=
bindings
.
OptimismPortalMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
eventName
:=
"WithdrawalFinalized"
processedWithdrawalFinalizedEvents
:=
events
.
eventsBySignature
[
optimismPortalAbi
.
Events
[
eventName
]
.
ID
]
finalizedEvents
:=
make
([]
OptimismPortalWithdrawalFinalizedEvent
,
len
(
processedWithdrawalFinalizedEvents
))
for
i
,
finalizedEvent
:=
range
processedWithdrawalFinalizedEvents
{
log
:=
events
.
eventLog
[
finalizedEvent
.
GUID
]
var
withdrawalFinalized
bindings
.
OptimismPortalWithdrawalFinalized
err
:=
UnpackLog
(
&
withdrawalFinalized
,
log
,
eventName
,
optimismPortalAbi
)
if
err
!=
nil
{
return
nil
,
err
}
finalizedEvents
[
i
]
=
OptimismPortalWithdrawalFinalizedEvent
{
&
withdrawalFinalized
,
finalizedEvent
}
}
return
finalizedEvents
,
nil
}
func
OptimismPortalQueryProvenWithdrawal
(
ethClient
*
ethclient
.
Client
,
portalAddress
common
.
Address
,
withdrawalHash
common
.
Hash
)
(
OptimismPortalProvenWithdrawal
,
error
)
{
var
provenWithdrawal
OptimismPortalProvenWithdrawal
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment