Skip to content

Commit

Permalink
chore(solver/app): approve outbox spend in fulfill
Browse files Browse the repository at this point in the history
  • Loading branch information
corverroos committed Nov 26, 2024
1 parent f543d00 commit 422e34b
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 60 deletions.
6 changes: 6 additions & 0 deletions e2e/app/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/omni-network/omni/e2e/netman"
"github.com/omni-network/omni/e2e/netman/pingpong"
"github.com/omni-network/omni/e2e/solve"
"github.com/omni-network/omni/e2e/solve/devapp"
"github.com/omni-network/omni/e2e/types"
"github.com/omni-network/omni/halo/genutil/evm/predeploys"
"github.com/omni-network/omni/lib/contracts"
Expand Down Expand Up @@ -171,6 +172,11 @@ func E2ETest(ctx context.Context, def Definition, cfg E2ETestConfig) error {
return err
}

// TODO(corver): Remove this
if err := devapp.TestFlow(ctx, NetworkFromDef(def), ExternalEndpoints(def)); err != nil {
return err
}

var eg errgroup.Group
eg.Go(func() error { return testGasPumps(ctx, def) })
eg.Go(func() error { return testBridge(ctx, def) })
Expand Down
6 changes: 5 additions & 1 deletion e2e/solve/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ func DeployContracts(ctx context.Context, network netconf.Network, backends ethb
var eg errgroup.Group

eg.Go(func() error {
return deployBoxes(ctx, network, backends)
if err := deployBoxes(ctx, network, backends); err != nil {
return errors.Wrap(err, "deploy boxes")
}

return devapp.AllowOutboxCalls(ctx, network, backends)
})
eg.Go(func() error {
return devapp.Deploy(ctx, network, backends)
Expand Down
57 changes: 57 additions & 0 deletions e2e/solve/devapp/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/omni-network/omni/contracts/bindings"
"github.com/omni-network/omni/e2e/app/eoa"
"github.com/omni-network/omni/lib/cast"
"github.com/omni-network/omni/lib/contracts"
"github.com/omni-network/omni/lib/create3"
"github.com/omni-network/omni/lib/errors"
Expand All @@ -24,6 +25,7 @@ const (
var (
create3Factory = contracts.Create3Factory(netconf.Devnet)
deployer = eoa.MustAddress(netconf.Devnet, eoa.RoleDeployer)
manager = eoa.MustAddress(netconf.Devnet, eoa.RoleManager)
)

// Deploy deploys the mock tokens and vaults to devnet.
Expand Down Expand Up @@ -67,6 +69,61 @@ func Deploy(ctx context.Context, network netconf.Network, backends ethbackend.Ba
return nil
}

// AllowOutboxCalls allows the outbox to call the L1 vault deposit method.
func AllowOutboxCalls(ctx context.Context, network netconf.Network, backends ethbackend.Backends) error {
if network.ID != netconf.Devnet {
return errors.New("onl devnet")
}

addrs, err := contracts.GetAddresses(ctx, network.ID)
if err != nil {
return errors.Wrap(err, "get addresses")
}

mockl1, ok := network.Chain(evmchain.IDMockL1)
if !ok {
return errors.New("no mock l1")
}

mockl1Backend, err := backends.Backend(mockl1.ID)
if err != nil {
return errors.Wrap(err, "backend mock l1")
}

if err := allowCalls(ctx, mockl1Backend, addrs.SolveOutbox); err != nil {
return errors.Wrap(err, "allow calls")
}

return nil
}

// allowCalls allows the outbox to call the L1 vault deposit method.
func allowCalls(ctx context.Context, backend *ethbackend.Backend, outboxAddr common.Address) error {
outbox, err := bindings.NewSolveOutbox(outboxAddr, backend)
if err != nil {
return errors.Wrap(err, "new solve outbox")
}

txOpts, err := backend.BindOpts(ctx, manager)
if err != nil {
return errors.Wrap(err, "bind opts")
}

vaultDepositID, err := cast.Array4(vaultDeposit.ID[:4])
if err != nil {
return err
}

tx, err := outbox.SetAllowedCall(txOpts, static.L1Vault, vaultDepositID, true)
if err != nil {
return errors.Wrap(err, "set allowed call")
} else if _, err := backend.WaitMined(ctx, tx); err != nil {
return errors.Wrap(err, "wait mined")
}

return nil
}

func deployVault(ctx context.Context, backend *ethbackend.Backend, salt string, collaterlTkn common.Address) error {
txOpts, err := backend.BindOpts(ctx, deployer)
if err != nil {
Expand Down
120 changes: 116 additions & 4 deletions e2e/solve/devapp/deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package devapp
import (
"context"
"math/big"
"time"

"github.com/omni-network/omni/contracts/bindings"
"github.com/omni-network/omni/lib/anvil"
"github.com/omni-network/omni/lib/contracts"
"github.com/omni-network/omni/lib/errors"
"github.com/omni-network/omni/lib/ethclient/ethbackend"
"github.com/omni-network/omni/lib/log"
"github.com/omni-network/omni/lib/netconf"
"github.com/omni-network/omni/lib/xchain"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -78,7 +81,107 @@ func IsDeposited(ctx context.Context, backends ethbackend.Backends, req DepositR

// assumes balance(onBehalfOf) was zero before deposit request
// assumes one deposit per test case onBehalfOf addr
return balance.Cmp(req.Deposit.Amount) != 0, nil
return balance.Cmp(req.Deposit.Amount) == 0, nil
}

// TestFlow submits deposit requests to the solve inbox and waits for them to be processed.
func TestFlow(ctx context.Context, network netconf.Network, endpoints xchain.RPCEndpoints) error {
backends, err := ethbackend.BackendsFromNetwork(network, endpoints)
if err != nil {
return err
}

deposits, err := RequestDeposits(ctx, backends)
if err != nil {
return err
}

timeout, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()

// Wait for all deposits to be completed on dest chain by solver/outbox
toCheck := toSet(deposits)
for {
if timeout.Err() != nil {
return errors.New("timeout waiting for deposits")
}

for deposit := range toCheck {
ok, err := IsDeposited(ctx, backends, deposit)
if err != nil {
return err
} else if ok {
log.Debug(ctx, "Deposit complete", "remaining", len(toCheck)-1)
delete(toCheck, deposit)
}
}

if len(toCheck) == 0 {
break
}

time.Sleep(time.Second)
}

log.Debug(ctx, "All deposits fulfilled")

// Wait for requests to be claimed by solver
toCheck = toSet(deposits)
for {
if timeout.Err() != nil {
return errors.New("timeout waiting for claims")
}

const statusClaimed = 8

for deposit := range toCheck {
status, err := GetDepositStatus(ctx, backends, deposit)
if err != nil {
return err
} else if status == statusClaimed {
log.Debug(ctx, "Deposit claimed", "remaining", len(toCheck)-1)
delete(toCheck, deposit)
}
}

if len(toCheck) == 0 {
break
}

time.Sleep(time.Second)
}

log.Debug(ctx, "All deposits claimed")

return nil
}

func GetDepositStatus(ctx context.Context, backends ethbackend.Backends, deposit DepositReq) (uint8, error) {
app := GetApp()

backend, err := backends.Backend(app.L2.ChainID)
if err != nil {
return 0, errors.Wrap(err, "backend")
}

addrs, err := contracts.GetAddresses(ctx, netconf.Devnet)
if err != nil {
return 0, errors.Wrap(err, "get addresses")
}

inbox, err := bindings.NewSolveInbox(addrs.SolveInbox, backend)
if err != nil {
return 0, errors.Wrap(err, "new mock vault")
}

callOpts := &bind.CallOpts{Context: ctx}

req, err := inbox.GetRequest(callOpts, deposit.ID)
if err != nil {
return 0, errors.Wrap(err, "get balance")
}

return req.Status, nil
}

// addRandomDepositors adds n random depositors privkeys to the backend.
Expand Down Expand Up @@ -224,10 +327,19 @@ func parseReqID(inbox bindings.SolveInboxFilterer, logs []*types.Log) ([32]byte,
}

func packDeposit(args DepositArgs) ([]byte, error) {
data, err := vaultDeposit.Inputs.Pack(args.OnBehalfOf, args.Amount)
calldata, err := vaultABI.Pack("deposit", args.OnBehalfOf, args.Amount)
if err != nil {
return nil, errors.Wrap(err, "pack data")
return nil, errors.Wrap(err, "pack deposit call data")
}

return calldata, nil
}

func toSet[T comparable](slice []T) map[T]bool {
set := make(map[T]bool)
for _, v := range slice {
set[v] = true
}

return data, nil
return set
}
27 changes: 27 additions & 0 deletions e2e/solve/devapp/deposit_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package devapp

import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"

"github.com/stretchr/testify/require"
)

func TestPackUnpack(t *testing.T) {
t.Parallel()

dep := DepositArgs{
OnBehalfOf: common.Address{},
Amount: big.NewInt(1),
}

packed, err := packDeposit(dep)
require.NoError(t, err)

dep2, err := unpackDeposit(packed)
require.NoError(t, err)

require.Equal(t, dep, dep2)
}
8 changes: 7 additions & 1 deletion e2e/solve/devapp/target.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package devapp

import (
"bytes"
"math/big"

"github.com/omni-network/omni/contracts/bindings"
Expand Down Expand Up @@ -79,7 +80,12 @@ func (a App) Verify(srcChainID uint64, call bindings.SolveCall, deposits []bindi
}

func unpackDeposit(data []byte) (DepositArgs, error) {
unpacked, err := vaultDeposit.Inputs.Unpack(data)
trimmed := bytes.TrimPrefix(data, vaultDeposit.ID)
if bytes.Equal(trimmed, data) {
return DepositArgs{}, errors.New("data not prefixed with deposit method id")
}

unpacked, err := vaultDeposit.Inputs.Unpack(trimmed)
if err != nil {
return DepositArgs{}, errors.Wrap(err, "unpack data")
}
Expand Down
44 changes: 1 addition & 43 deletions e2e/test/solve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package e2e_test
import (
"context"
"testing"
"time"

"github.com/omni-network/omni/e2e/solve/devapp"
"github.com/omni-network/omni/e2e/types"
"github.com/omni-network/omni/lib/ethclient/ethbackend"
"github.com/omni-network/omni/lib/log"
"github.com/omni-network/omni/lib/netconf"
"github.com/omni-network/omni/lib/xchain"

Expand All @@ -23,46 +20,7 @@ func TestSolver(t *testing.T) {
}
maybeTestNetwork(t, skipFunc, func(t *testing.T, network netconf.Network, endpoints xchain.RPCEndpoints) {
t.Helper()
ctx := context.Background()

backends, err := ethbackend.BackendsFromNetwork(network, endpoints)
require.NoError(t, err)

deposits, err := devapp.RequestDeposits(ctx, backends)
err := devapp.TestFlow(context.Background(), network, endpoints)
require.NoError(t, err)

timeout, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()

toCheck := toSet(deposits)
for {
if timeout.Err() != nil {
require.Fail(t, "timeout waiting for deposits")
}

for deposit := range toCheck {
ok, err := devapp.IsDeposited(ctx, backends, deposit)
require.NoError(t, err)
if ok {
log.Info(ctx, "Deposit complete", "remaining", len(toCheck)-1)
delete(toCheck, deposit)
}
}

if len(toCheck) == 0 {
return
}

time.Sleep(time.Second)
}
})
}

func toSet[T comparable](slice []T) map[T]bool {
set := make(map[T]bool)
for _, v := range slice {
set[v] = true
}

return set
}
11 changes: 10 additions & 1 deletion lib/cast/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,20 @@ func Array20[A any](slice []A) ([20]A, error) {
return [20]A{}, errors.New("slice length not 20", "len", len(slice))
}

// Array8 casts a slice to an array of length 2.
// Array8 casts a slice to an array of length 8.
func Array8[A any](slice []A) ([8]A, error) {
if len(slice) == 8 {
return [8]A(slice), nil
}

return [8]A{}, errors.New("slice length not 8", "len", len(slice))
}

// Array4 casts a slice to an array of length 4.
func Array4[A any](slice []A) ([4]A, error) {
if len(slice) == 4 {
return [4]A(slice), nil
}

return [4]A{}, errors.New("slice length not 4", "len", len(slice))
}
Loading

0 comments on commit 422e34b

Please sign in to comment.