Skip to content

Commit

Permalink
feat(op-challenger): Delayed Weth Withdrawal Request Caller (ethereum…
Browse files Browse the repository at this point in the history
…-optimism#9938)

* feat(op-challenger): Delayed Weth Withdrawal Request Caller

* fix(op-challenger): withdrawal request field ordering

* fix(op-challenger): encapsulate delayed weth behind the fault dispute game contract binding
  • Loading branch information
refcell authored Mar 22, 2024
1 parent 3afb562 commit 9a96543
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
61 changes: 61 additions & 0 deletions op-challenger/game/fault/contracts/delayed_weth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package contracts

import (
"context"
"fmt"
"math/big"

"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/common"
)

var (
methodWithdrawals = "withdrawals"
)

type DelayedWETHContract struct {
metrics metrics.ContractMetricer
multiCaller *batching.MultiCaller
contract *batching.BoundContract
}

type WithdrawalRequest struct {
Amount *big.Int
Timestamp *big.Int
}

func NewDelayedWETHContract(metrics metrics.ContractMetricer, addr common.Address, caller *batching.MultiCaller) (*DelayedWETHContract, error) {
contractAbi, err := bindings.DelayedWETHMetaData.GetAbi()
if err != nil {
return nil, fmt.Errorf("failed to load delayed weth ABI: %w", err)
}
return &DelayedWETHContract{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(contractAbi, addr),
}, nil
}

// GetWithdrawals returns all withdrawals made from the contract since the given block.
func (d *DelayedWETHContract) GetWithdrawals(ctx context.Context, block rpcblock.Block, gameAddr common.Address, recipients ...common.Address) ([]*WithdrawalRequest, error) {
defer d.metrics.StartContractRequest("GetWithdrawals")()
calls := make([]batching.Call, 0, len(recipients))
for _, recipient := range recipients {
calls = append(calls, d.contract.Call(methodWithdrawals, gameAddr, recipient))
}
results, err := d.multiCaller.Call(ctx, block, calls...)
if err != nil {
return nil, fmt.Errorf("failed to fetch withdrawals: %w", err)
}
withdrawals := make([]*WithdrawalRequest, len(recipients))
for i, result := range results {
withdrawals[i] = &WithdrawalRequest{
Amount: result.GetBigInt(0),
Timestamp: result.GetBigInt(1),
}
}
return withdrawals, nil
}
52 changes: 52 additions & 0 deletions op-challenger/game/fault/contracts/delayed_weth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package contracts

import (
"context"
"math/big"
"testing"

"github.com/ethereum-optimism/optimism/op-bindings/bindings"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)

var (
delayedWeth = common.HexToAddress("0x24112842371dFC380576ebb09Ae16Cb6B6caD7CB")
)

func TestDelayedWeth_GetWithdrawals(t *testing.T) {
stubRpc, weth := setupDelayedWethTest(t)
block := rpcblock.ByNumber(482)

addrs := []common.Address{{0x01}, {0x02}}
expected := [][]*big.Int{
[]*big.Int{big.NewInt(123), big.NewInt(456)},
[]*big.Int{big.NewInt(123), big.NewInt(456)},
}

for i, addr := range addrs {
stubRpc.SetResponse(delayedWeth, methodWithdrawals, block, []interface{}{fdgAddr, addr}, []interface{}{expected[i][0], expected[i][1]})
}

actual, err := weth.GetWithdrawals(context.Background(), block, fdgAddr, addrs...)
require.NoError(t, err)
require.Equal(t, len(expected), len(actual))
for i := range expected {
require.Zerof(t, expected[i][0].Cmp(actual[i].Amount), "expected: %v actual: %v", expected[i][1], actual[i].Amount)
require.Zerof(t, expected[i][1].Cmp(actual[i].Timestamp), "expected: %v actual: %v", expected[i][0], actual[i].Timestamp)
}
}

func setupDelayedWethTest(t *testing.T) (*batchingTest.AbiBasedRpc, *DelayedWETHContract) {
delayedWethAbi, err := bindings.DelayedWETHMetaData.GetAbi()
require.NoError(t, err)
stubRpc := batchingTest.NewAbiBasedRpc(t, delayedWeth, delayedWethAbi)
caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize)
weth, err := NewDelayedWETHContract(contractMetrics.NoopContractMetrics, delayedWeth, caller)
require.NoError(t, err)
return stubRpc, weth
}
9 changes: 9 additions & 0 deletions op-challenger/game/fault/contracts/faultdisputegame.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,15 @@ func (f *FaultDisputeGameContract) addGlobalDataTx(ctx context.Context, data *ty
return oracle.AddGlobalDataTx(data)
}

func (f *FaultDisputeGameContract) GetDelayedWETH(ctx context.Context) (*DelayedWETHContract, error) {
defer f.metrics.StartContractRequest("GetDelayedWETH")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodWETH))
if err != nil {
return nil, fmt.Errorf("failed to fetch WETH addr: %w", err)
}
return NewDelayedWETHContract(f.metrics, result.GetAddress(0), f.multiCaller)
}

func (f *FaultDisputeGameContract) GetOracle(ctx context.Context) (*PreimageOracleContract, error) {
defer f.metrics.StartContractRequest("GetOracle")()
vm, err := f.vm(ctx)
Expand Down

0 comments on commit 9a96543

Please sign in to comment.