Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(e2e/solve): devnet target #2468

Merged
merged 1 commit into from
Nov 13, 2024
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
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
Loading