Skip to content

Commit

Permalink
feat(e2e/solve): devnet target (#2468)
Browse files Browse the repository at this point in the history
Add devnet solver target and initial target interface.

issue: #2355
  • Loading branch information
kevinhalliday authored Nov 13, 2024
1 parent c1121f3 commit 42565c9
Show file tree
Hide file tree
Showing 9 changed files with 1,429 additions and 13 deletions.
2 changes: 1 addition & 1 deletion contracts/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ CORE_CONTRACTS := OmniPortal FeeOracleV1 Create3 TransparentUpgradeableProxy \
PortalRegistry AllocPredeploys PingPong ProxyAdmin Admin \
OmniGasPump OmniGasStation

SOLVE_CONTRACTS := SolveInbox SolveOutbox
SOLVE_CONTRACTS := SolveInbox SolveOutbox MockToken MockVault

AVS_CONTRACTS := OmniAVS DelegationManager StrategyManager StrategyBase AVSDirectory \
test/common/MockERC20.sol:MockERC20
Expand Down
781 changes: 781 additions & 0 deletions contracts/bindings/mocktoken.go

Large diffs are not rendered by default.

307 changes: 307 additions & 0 deletions contracts/bindings/mockvault.go

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion e2e/solve/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package solve
import (
"context"

"github.com/omni-network/omni/e2e/solve/devapp"
"github.com/omni-network/omni/lib/contracts/solveinbox"
"github.com/omni-network/omni/lib/contracts/solveoutbox"
"github.com/omni-network/omni/lib/errors"
Expand All @@ -11,7 +12,7 @@ import (
"github.com/omni-network/omni/lib/netconf"
)

// DeployContracts deploys solve inbox / outbox contracts.
// DeployContracts deploys solve inbox / outbox contracts, and devnet app (if devnet).
func DeployContracts(ctx context.Context, network netconf.Network, backends ethbackend.Backends) error {
if network.ID != netconf.Devnet {
log.Warn(ctx, "Skipping solve deploy", nil)
Expand All @@ -20,6 +21,19 @@ func DeployContracts(ctx context.Context, network netconf.Network, backends ethb

log.Info(ctx, "Deploying solve contracts")

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

if err := devapp.Deploy(ctx, network, backends); err != nil {
return errors.Wrap(err, "deploy devapp")
}

return nil
}

// DeployContracts deploys solve inbox / outbox contracts.
func deployBoxes(ctx context.Context, network netconf.Network, backends ethbackend.Backends) error {
for _, chain := range network.EVMChains() {
backend, err := backends.Backend(chain.ID)
if err != nil {
Expand Down
126 changes: 126 additions & 0 deletions e2e/solve/devapp/deploy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package devapp

import (
"context"

"github.com/omni-network/omni/contracts/bindings"
"github.com/omni-network/omni/e2e/app/eoa"
"github.com/omni-network/omni/lib/contracts"
"github.com/omni-network/omni/lib/create3"
"github.com/omni-network/omni/lib/errors"
"github.com/omni-network/omni/lib/ethclient/ethbackend"
"github.com/omni-network/omni/lib/evmchain"
"github.com/omni-network/omni/lib/netconf"

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

const (
l1VaultSalt = "l1-vault"
l1TokenSalt = "l1-token"
l2TokenSalt = "l2-token"
)

var (
create3Factory = contracts.Create3Factory(netconf.Devnet)
deployer = eoa.MustAddress(netconf.Devnet, eoa.RoleDeployer)
)

// Deploy deploys the mock tokens and vaults to devnet.
func Deploy(ctx context.Context, network netconf.Network, backends ethbackend.Backends) error {
if network.ID != netconf.Devnet {
return errors.New("onl devnet")
}

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

mockl2, ok := network.Chain(evmchain.IDMockL2)
if !ok {
return errors.New("no mock l2")
}

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

mockl2Backend, err := backends.Backend(mockl2.ID)
if err != nil {
return errors.Wrap(err, "backend mock l2")
}

if err := deployToken(ctx, mockl1Backend, l1VaultSalt); err != nil {
return errors.Wrap(err, "deploy l1 token")
}

if err := deployVault(ctx, mockl1Backend, l1VaultSalt, static.L1Token); err != nil {
return errors.Wrap(err, "deploy vault")
}

if err := deployToken(ctx, mockl2Backend, l2TokenSalt); err != nil {
return errors.Wrap(err, "deploy l2 token")
}

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 {
return errors.Wrap(err, "bind opts")
}

factory, err := bindings.NewCreate3(create3Factory, backend)
if err != nil {
return errors.Wrap(err, "new create3")
}

initCode, err := contracts.PackInitCode(vaultABI, bindings.MockVaultBin, collaterlTkn)
if err != nil {
return errors.Wrap(err, "pack init code")
}

tx, err := factory.DeployWithRetry(txOpts, create3.HashSalt(salt), initCode) //nolint:contextcheck // Context is txOpts
if err != nil {
return errors.Wrap(err, "deploy proxy")
}

_, err = backend.WaitMined(ctx, tx)
if err != nil {
return errors.Wrap(err, "wait mined")
}

return nil
}

func deployToken(ctx context.Context, backend *ethbackend.Backend, salt string) error {
txOpts, err := backend.BindOpts(ctx, deployer)
if err != nil {
return errors.Wrap(err, "bind opts")
}

factory, err := bindings.NewCreate3(create3Factory, backend)
if err != nil {
return errors.Wrap(err, "new create3")
}

initCode, err := contracts.PackInitCode(tokenABI, bindings.MockTokenBin)
if err != nil {
return errors.Wrap(err, "pack init code")
}

tx, err := factory.DeployWithRetry(txOpts, create3.HashSalt(salt), initCode) //nolint:contextcheck // Context is txOpts
if err != nil {
return errors.Wrap(err, "deploy")
}

_, err = backend.WaitMined(ctx, tx)
if err != nil {
return errors.Wrap(err, "wait mined")
}

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

import (
"github.com/omni-network/omni/contracts/bindings"
"github.com/omni-network/omni/lib/create3"
"github.com/omni-network/omni/lib/errors"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)

type App struct {
L1Vault common.Address
L1Token common.Address
L2Token common.Address
}

var (
vaultABI = mustGetABI(bindings.MockVaultMetaData)
tokenABI = mustGetABI(bindings.MockTokenMetaData)
vaultDeposit = mustGetMethod(vaultABI, "deposit")

// static is the static devnt app instance.
static = App{
L1Vault: create3.Address(create3Factory, l1VaultSalt, deployer),
L1Token: create3.Address(create3Factory, l1TokenSalt, deployer),
L2Token: create3.Address(create3Factory, l2TokenSalt, deployer),
}
)

func GetApp() App {
return static
}

func mustGetABI(metadata *bind.MetaData) *abi.ABI {
abi, err := metadata.GetAbi()
if err != nil {
panic(err)
}

return abi
}

func mustGetMethod(abi *abi.ABI, name string) abi.Method {
method, ok := abi.Methods[name]
if !ok {
panic(errors.New("missing method", "name", name))
}

return method
}
111 changes: 111 additions & 0 deletions e2e/solve/devapp/target.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package devapp

import (
"math/big"

"github.com/omni-network/omni/contracts/bindings"
"github.com/omni-network/omni/lib/errors"
"github.com/omni-network/omni/lib/evmchain"
solver "github.com/omni-network/omni/solver/app"

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

var _ solver.Target = (*App)(nil)

type DepositArgs struct {
OnBehalfOf common.Address
Amount *big.Int
}

func (App) ChainID() uint64 {
return evmchain.IDMockL1
}

func (t App) Address() common.Address {
return t.L1Vault
}

func (t App) IsAllowedCall(call *bindings.SolveCall) bool {
if call.DestChainId != t.ChainID() {
return false
}

if call.Target != t.Address() {
return false
}

_, err := unpackDeposit(call.Data)

return err == nil
}

func (t App) TokenPrereqs(call *bindings.SolveCall) ([]*bindings.SolveTokenPrereq, error) {
if !t.IsAllowedCall(call) {
return nil, errors.New("call not allowed")
}

args, err := unpackDeposit(call.Data)
if err != nil {
return nil, errors.Wrap(err, "unpack deposit")
}

return []*bindings.SolveTokenPrereq{
{
Token: t.L1Token,
Amount: args.Amount,
},
}, nil
}

func (t App) Verify(srcChainID uint64, call *bindings.SolveCall, deposits []*bindings.SolveDeposit) error {
// we only accept deposits from mock L2
if srcChainID != evmchain.IDMockL2 {
return errors.New("source chain not supported", "src", srcChainID)
}

if !t.IsAllowedCall(call) {
return errors.New("call not allowed")
}

args, err := unpackDeposit(call.Data)
if err != nil {
return errors.Wrap(err, "invalid deposit")
}

var l2token *bindings.SolveDeposit

for _, deposit := range deposits {
if deposit.Token == t.L2Token {
l2token = deposit
}
}

// if no l2 deposit, we can't accept
if l2token == nil {
return errors.New("no L2 token deposit")
}

// if l2 deposit amount does not match call amount, we can't accept
if l2token.Amount.Cmp(args.Amount) != 0 {
return errors.New("insufficient L2 token deposit")
}

// TODO: require native deposit that covers gas / risk / overhead

return nil
}

func unpackDeposit(data []byte) (DepositArgs, error) {
unpacked, err := vaultDeposit.Inputs.Unpack(data)
if err != nil {
return DepositArgs{}, errors.Wrap(err, "unpack data")
}

var args DepositArgs
if err := vaultDeposit.Inputs.Copy(&args, unpacked); err != nil {
return DepositArgs{}, errors.Wrap(err, "copy args")
}

return args, nil
}
Loading

0 comments on commit 42565c9

Please sign in to comment.