Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hip-shrimps-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/contracts-bedrock': patch
---

Emit an extra event when withdrawals are initiated to make chainops easier
148 changes: 146 additions & 2 deletions op-bindings/bindings/l2tol1messagepasser.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion op-bindings/bindings/l2tol1messagepasser_deployed.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 51 additions & 5 deletions op-node/withdrawals/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package withdrawals

import (
"bytes"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -172,8 +173,15 @@ func FinalizeWithdrawalParameters(ctx context.Context, l2client ProofClient, txH
if err != nil {
return FinalizedWithdrawalParameters{}, err
}
ev1, err := ParseWithdrawalInitiatedExtension1(receipt)
if err != nil {
return FinalizedWithdrawalParameters{}, err
}
// Generate then verify the withdrawal proof
withdrawalHash, err := WithdrawalHash(ev)
if !bytes.Equal(withdrawalHash[:], ev1.Hash[:]) {
return FinalizedWithdrawalParameters{}, errors.New("Computed withdrawal hash incorrectly")
}
if err != nil {
return FinalizedWithdrawalParameters{}, err
}
Expand Down Expand Up @@ -255,14 +263,52 @@ func ParseWithdrawalInitiated(receipt *types.Receipt) (*bindings.L2ToL1MessagePa
if err != nil {
return nil, err
}
if len(receipt.Logs) != 1 {
return nil, errors.New("invalid length of logs")
abi, err := bindings.L2ToL1MessagePasserMetaData.GetAbi()
if err != nil {
return nil, err
}
ev, err := contract.ParseWithdrawalInitiated(*receipt.Logs[0])

for _, log := range receipt.Logs {
event, err := abi.EventByID(log.Topics[0])
if err != nil {
return nil, err
}
if event.Name == "WithdrawalInitiated" {
ev, err := contract.ParseWithdrawalInitiated(*log)
if err != nil {
return nil, fmt.Errorf("failed to parse log: %w", err)
}
return ev, nil
}
}
return nil, errors.New("Unable to find WithdrawalInitiated event")
}

// ParseWithdrawalInitiatedExtension1 parses
func ParseWithdrawalInitiatedExtension1(receipt *types.Receipt) (*bindings.L2ToL1MessagePasserWithdrawalInitiatedExtension1, error) {
contract, err := bindings.NewL2ToL1MessagePasser(common.Address{}, nil)
if err != nil {
return nil, err
}
abi, err := bindings.L2ToL1MessagePasserMetaData.GetAbi()
if err != nil {
return nil, fmt.Errorf("failed to parse log: %w", err)
return nil, err
}

for _, log := range receipt.Logs {
event, err := abi.EventByID(log.Topics[0])
if err != nil {
return nil, err
}
if event.Name == "WithdrawalInitiatedExtension1" {
ev, err := contract.ParseWithdrawalInitiatedExtension1(*log)
if err != nil {
return nil, fmt.Errorf("failed to parse log: %w", err)
}
return ev, nil
}
}
return ev, nil
return nil, errors.New("Unable to find WithdrawalInitiatedExtension1 event")
}

// StorageSlotOfWithdrawalHash determines the storage slot of the Withdrawer contract to look at
Expand Down
24 changes: 12 additions & 12 deletions packages/contracts-bedrock/.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageFirstStuckSecondSucceeds
L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageSucceeds() (gas: 57396)
L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageToSystemContract() (gas: 36217)
L2CrossDomainMessenger_Test:test_L2MessengerRelayShouldRevertIfPaused() (gas: 41682)
L2CrossDomainMessenger_Test:test_L2MessengerSendMessage() (gas: 121684)
L2CrossDomainMessenger_Test:test_L2MessengerTwiceSendMessage() (gas: 136258)
L2CrossDomainMessenger_Test:test_L2MessengerSendMessage() (gas: 122833)
L2CrossDomainMessenger_Test:test_L2MessengerTwiceSendMessage() (gas: 138556)
L2CrossDomainMessenger_Test:test_L2MessengerXDomainSenderReverts() (gas: 10598)
L2CrossDomainMessenger_Test:test_L2MessengerxDomainMessageSenderResets() (gas: 54889)
L2OutputOracleTest:testCannot_ProposeWithUnmatchedBlockhash() (gas: 26829)
Expand All @@ -96,19 +96,19 @@ L2OutputOracleUpgradeable_Test:test_cannotInitImpl() (gas: 19555)
L2OutputOracleUpgradeable_Test:test_cannotInitProxy() (gas: 24554)
L2OutputOracleUpgradeable_Test:test_initValuesOnProxy() (gas: 39086)
L2OutputOracleUpgradeable_Test:test_upgrading() (gas: 180632)
L2StandardBridge_Test:test_ERC20BridgeFailed_whenLocalTokenIsBridge() (gas: 134358)
L2StandardBridge_Test:test_ERC20BridgeFailed_whenLocalTokenIsBridge() (gas: 135507)
L2StandardBridge_Test:test_cannotWithdrawEthWithoutSendingIt() (gas: 21619)
L2StandardBridge_Test:test_finalizeBridgeERC20FailSendBack() (gas: 499449)
L2StandardBridge_Test:test_finalizeBridgeERC20FailSendBack() (gas: 500368)
L2StandardBridge_Test:test_finalizeDeposit() (gas: 93125)
L2StandardBridge_Test:test_finalizeDeposit_failsToCompleteOutboundTransfer() (gas: 141373)
L2StandardBridge_Test:test_finalizeDeposit_failsToCompleteOutboundTransfer() (gas: 142522)
L2StandardBridge_Test:test_initialize() (gas: 14823)
L2StandardBridge_Test:test_receive() (gas: 137921)
L2StandardBridge_Test:test_withdraw() (gas: 353438)
L2StandardBridge_Test:test_withdrawTo() (gas: 354193)
L2StandardBridge_Test:test_receive() (gas: 139070)
L2StandardBridge_Test:test_withdraw() (gas: 354357)
L2StandardBridge_Test:test_withdrawTo() (gas: 355112)
L2StandardBridge_Test:test_withdraw_onlyEOA() (gas: 251674)
L2ToL1MessagePasserTest:test_burn() (gas: 112246)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract() (gas: 68198)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromEOA() (gas: 75284)
L2ToL1MessagePasserTest:test_burn() (gas: 113395)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract() (gas: 72486)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromEOA() (gas: 76433)
LegacyERC20ETH_Test:test_approve() (gas: 10796)
LegacyERC20ETH_Test:test_burn() (gas: 10681)
LegacyERC20ETH_Test:test_crossDomain() (gas: 10577)
Expand Down Expand Up @@ -279,4 +279,4 @@ SequencerFeeVault_Test:test_constructor() (gas: 7678)
SequencerFeeVault_Test:test_minWithdrawalAmount() (gas: 5440)
SequencerFeeVault_Test:test_receive() (gas: 17338)
SequencerFeeVault_Test:test_revertWithdraw() (gas: 9342)
SequencerFeeVault_Test:test_withdraw() (gas: 148784)
SequencerFeeVault_Test:test_withdraw() (gas: 149933)
10 changes: 10 additions & 0 deletions packages/contracts-bedrock/contracts/L2/L2ToL1MessagePasser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ contract L2ToL1MessagePasser is Semver {
bytes data
);

/**
* @notice Emitted any time a withdrawal is initiated. An extension to
* WithdrawalInitiated so that the interface is maintained.
*
* @param hash The hash of the withdrawal
*/
event WithdrawalInitiatedExtension1(bytes32 indexed hash);

/**
* @notice Emitted when the balance of this contract is burned.
*
Expand Down Expand Up @@ -106,6 +114,8 @@ contract L2ToL1MessagePasser is Semver {
sentMessages[withdrawalHash] = true;

emit WithdrawalInitiated(nonce, msg.sender, _target, msg.value, _gasLimit, _data);
emit WithdrawalInitiatedExtension1(withdrawalHash);

unchecked {
++nonce;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ contract L2ToL1MessagePasserTest is CommonTest {
bytes data
);

event WithdrawalInitiatedExtension1(bytes32 indexed hash);

event WithdrawerBalanceBurnt(uint256 indexed amount);

function setUp() virtual public {
Expand All @@ -36,6 +38,20 @@ contract L2ToL1MessagePasserTest is CommonTest {
hex""
);

bytes32 withdrawalHash = Hashing.hashWithdrawal(
Types.WithdrawalTransaction(
messagePasser.nonce(),
address(this),
address(4),
100,
64000,
hex""
)
);

vm.expectEmit(true, true, true, true);
emit WithdrawalInitiatedExtension1(withdrawalHash);

vm.deal(address(this), 2**64);
messagePasser.initiateWithdrawal{ value: 100 }(
address(4),
Expand Down
10 changes: 10 additions & 0 deletions specs/withdrawals.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ interface L2ToL1MessagePasser {
bytes data
);

event WithdrawalInitiatedExtension1(bytes32 indexed hash);

event WithdrawerBalanceBurnt(uint256 indexed amount);

function burn() external;
Expand All @@ -100,6 +102,14 @@ interface L2ToL1MessagePasser {

```

The `WithdrawalInitiated` event includes all of the data that is hashed and
stored in the `sentMessages` mapping. The `WithdrawalInitiatedExtension1` emits
the hash that was computed and used as part of the storage proof used to
finalize the withdrawal on L1.

The events are separate as to preserve backwards compatibility. The hashing
scheme could be upgraded in the future through a contract upgrade.

### Addresses are not Aliased on Withdrawals

[address-aliasing]: #no-address-aliasing
Expand Down