-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(e2e/solve): devnet target (#2468)
Add devnet solver target and initial target interface. issue: #2355
- Loading branch information
1 parent
c1121f3
commit 42565c9
Showing
9 changed files
with
1,429 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.