Skip to content

Commit

Permalink
feat(evm): Add precompile to the EVM that enables transfers of ERC20 …
Browse files Browse the repository at this point in the history
…tokens to "nibi" accounts as Ethereum transactions (#1959)

* refactor(e2e-evm): unused vars and better type hint

Squashed commit of the following:

commit 51071dad60c12e02093d92d1311d33b70b81304f
Author: Unique-Divine <[email protected]>
Date:   Mon Jun 10 12:32:00 2024 -0500

    refactor(e2e-evm): unused vars and better type hint

commit 6729b97
Author: Unique-Divine <[email protected]>
Date:   Fri Jun 7 22:46:14 2024 -0500

    test(e2e-evm): more type safety

commit 25c1557
Author: Unique-Divine <[email protected]>
Date:   Fri Jun 7 22:01:21 2024 -0500

    Squashed commit of the following:

    commit 021d161d176112cf24e28780ad64f61155f70ea2
    Author: Unique-Divine <[email protected]>
    Date:   Fri Jun 7 22:00:10 2024 -0500

        test(e2e): (1) Generated smart contract types for ethers. (2) TypeScript support. (3) Formatter

    commit af7e7b3
    Author: Unique-Divine <[email protected]>
    Date:   Fri Jun 7 16:11:45 2024 -0500

        chore: another issue ticket

    commit 36745fd
    Author: Unique-Divine <[email protected]>
    Date:   Fri Jun 7 16:07:20 2024 -0500

        chore: add issue number for TODO comment

    commit 8a76c0e
    Author: Unique-Divine <[email protected]>
    Date:   Fri Jun 7 15:54:07 2024 -0500

        refactor(evm): Remove dead code and document non-EVM ante handler

    commit e4e11df
    Author: Unique-Divine <[email protected]>
    Date:   Fri Jun 7 15:52:38 2024 -0500

        refactor: remove dead code

    commit cad00c0
    Merge: dc5f4dd 359e310
    Author: Unique-Divine <[email protected]>
    Date:   Fri Jun 7 15:41:53 2024 -0500

        Merge branch 'main' into ud/ante-test

    commit dc5f4dd
    Author: Unique-Divine <[email protected]>
    Date:   Fri Jun 7 15:28:53 2024 -0500

        refactor: ante handler and evm cleanup

    commit f73cdc3
    Merge: d3a6ea9 290c372
    Author: Unique-Divine <[email protected]>
    Date:   Wed Jun 5 20:59:39 2024 -0500

        Merge branch 'test/evm-grpc-query' of https://github.com/NibiruChain/nibiru into test/evm-grpc-query

    commit d3a6ea9
    Merge: 376596d 70ee1bf
    Author: Unique-Divine <[email protected]>
    Date:   Wed Jun 5 20:59:30 2024 -0500

        Merge branch 'main' into test/evm-grpc-query

    commit 376596d
    Author: Unique-Divine <[email protected]>
    Date:   Wed Jun 5 20:58:40 2024 -0500

        Squashed commit of the following:

        commit b5687130ff5f3d020a3b14d219fec3a816579c30
        Author: Unique-Divine <[email protected]>
        Date:   Wed Jun 5 20:57:44 2024 -0500

            chore: run tidy

        commit 1f1f938
        Merge: 3e3cc83 bbcc6f8
        Author: Unique-Divine <[email protected]>
        Date:   Wed Jun 5 19:16:30 2024 -0500

            Merge branch 'main' into ud/fix-race-condition

        commit 3e3cc83
        Author: Unique-Divine <[email protected]>
        Date:   Wed Jun 5 19:15:40 2024 -0500

            chore: changelog

        commit 3876ccb
        Author: Unique-Divine <[email protected]>
        Date:   Wed Jun 5 19:04:00 2024 -0500

            refactor: more consistent test names

        commit aaa0a19
        Author: Unique-Divine <[email protected]>
        Date:   Wed Jun 5 18:53:09 2024 -0500

            test(oracle): Fix missing tear down step for oracle integration test

        commit 8c3c35e
        Author: Unique-Divine <[email protected]>
        Date:   Wed Jun 5 17:55:56 2024 -0500

            chore: add test comands to justfile

        commit 4916282
        Merge: 64ed0a2 e7e708d
        Author: Unique-Divine <[email protected]>
        Date:   Fri May 31 09:35:33 2024 -0500

            Merge branch 'main' into ud/fix-race-condition

        commit 64ed0a2
        Author: Unique-Divine <[email protected]>
        Date:   Fri May 31 01:44:55 2024 -0500

            fix(gosdk): tests parallel race condition

    commit 290c372
    Merge: 0d1c894 70ee1bf
    Author: Unique Divine <[email protected]>
    Date:   Wed Jun 5 20:05:19 2024 -0500

        Merge branch 'main' into test/evm-grpc-query

    commit 0d1c894
    Merge: 9170835 ad173e9
    Author: Unique Divine <[email protected]>
    Date:   Wed Jun 5 19:34:38 2024 -0500

        Merge branch 'main' into test/evm-grpc-query

    commit 9170835
    Author: Oleg Nikonychev <[email protected]>
    Date:   Wed Jun 5 13:55:14 2024 +0400

        fix: removed hardcoded gas value in grpc_query test

    commit 4337858
    Author: Oleg Nikonychev <[email protected]>
    Date:   Wed Jun 5 13:14:34 2024 +0400

        chore: refactored eth util methods

    commit 7df84e2
    Merge: 8918498 bbcc6f8
    Author: Oleg Nikonychev <[email protected]>
    Date:   Wed Jun 5 12:23:51 2024 +0400

        chore: resolve conflicts

    commit 8918498
    Merge: 3fd45ce e7e708d
    Author: Oleg Nikonychev <[email protected]>
    Date:   Mon Jun 3 21:56:39 2024 +0400

        Merge branch 'main' into test/evm-grpc-query

    commit 3fd45ce
    Author: Oleg Nikonychev <[email protected]>
    Date:   Mon Jun 3 21:56:23 2024 +0400

        chore: changelog update

    commit 3348876
    Author: Oleg Nikonychev <[email protected]>
    Date:   Mon Jun 3 21:53:54 2024 +0400

        test(evm): grpc_query full coverage

* wip!: save progress

* chore: changelog

* chore: linter

* feat(eth): finish todos for hex.go

* feat(eth): finalize protobuf impl for eth.HexAddr

* chore: small typos in comments

* feat(evm): contract embeds, create fun token from ERC20

* chore: merge conflict

* chore: clean TODOs

* fix: TestModuleAccountEVM

* feat(evm): impl CreateFunTokenFromCoin

* test: fix cleanup by increasing timeout for race condition prevention

* chore: rn

* wip!: precompile calls working w/ tests

* rm package-lock.json

* refactor: cleanup

* refactor: linter

* fix: cache during gas estimation in Eth tx
  • Loading branch information
Unique-Divine authored Jul 8, 2024
1 parent 5bc18fe commit a5ff022
Show file tree
Hide file tree
Showing 35 changed files with 1,170 additions and 199 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1949](https://github.com/NibiruChain/nibiru/pull/1949) - feat(evm): add fungible token mapping queries
- [#1950](https://github.com/NibiruChain/nibiru/pull/1950) - feat(evm): Tx to create FunToken mapping from ERC20, contract embeds, and ERC20 queries.
- [#1958](https://github.com/NibiruChain/nibiru/pull/1958) - chore(evm): wiped deprecated evm apis: miner, personal
- [#1959](https://github.com/NibiruChain/nibiru/pull/1959) - feat(evm): Add precompile to the EVM that enables trasnfers of ERC20 tokens to "nibi" accounts as regular Ethereum transactions

#### Dapp modules: perp, spot, oracle, etc

Expand Down
4 changes: 4 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/NibiruChain/nibiru/app/ante"
"github.com/NibiruChain/nibiru/app/wasmext"
"github.com/NibiruChain/nibiru/x/evm/precompile"

dbm "github.com/cometbft/cometbft-db"
abci "github.com/cometbft/cometbft/abci/types"
Expand Down Expand Up @@ -185,6 +186,9 @@ func NewNibiruApp(
skipGenesisInvariants := cast.ToBool(
appOpts.Get(crisis.FlagSkipGenesisInvariants))

precompilesToAdd := precompile.InitPrecompiles(app.AppKeepers.PublicKeepers)
app.EvmKeeper.AddPrecompiles(precompilesToAdd)

app.initModuleManager(encodingConfig, skipGenesisInvariants)

app.setupUpgrades()
Expand Down
49 changes: 10 additions & 39 deletions app/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ import (
// ---------------------------------------------------------------
// Nibiru Custom Modules

"github.com/NibiruChain/nibiru/app/keepers"
"github.com/NibiruChain/nibiru/eth"
"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/devgas/v1"
Expand Down Expand Up @@ -134,22 +135,17 @@ import (
)

type AppKeepers struct {
// AccountKeeper encodes/decodes accounts using the go-amino (binary) encoding/decoding library
AccountKeeper authkeeper.AccountKeeper
// BankKeeper defines a module interface that facilitates the transfer of coins between accounts
BankKeeper bankkeeper.Keeper
keepers.PublicKeepers
privateKeepers
}

type privateKeepers struct {
capabilityKeeper *capabilitykeeper.Keeper
StakingKeeper *stakingkeeper.Keeper
slashingKeeper slashingkeeper.Keeper
/* DistrKeeper is the keeper of the distribution store */
DistrKeeper distrkeeper.Keeper
GovKeeper govkeeper.Keeper
crisisKeeper crisiskeeper.Keeper
upgradeKeeper upgradekeeper.Keeper
paramsKeeper paramskeeper.Keeper
authzKeeper authzkeeper.Keeper
FeeGrantKeeper feegrantkeeper.Keeper
ConsensusParamsKeeper consensusparamkeeper.Keeper
crisisKeeper crisiskeeper.Keeper
upgradeKeeper upgradekeeper.Keeper
paramsKeeper paramskeeper.Keeper
authzKeeper authzkeeper.Keeper

// --------------------------------------------------------------------
// IBC keepers
Expand All @@ -167,31 +163,6 @@ type AppKeepers struct {
ibcTransferKeeper ibctransferkeeper.Keeper
icaControllerKeeper icacontrollerkeeper.Keeper
icaHostKeeper icahostkeeper.Keeper

// make scoped keepers public for test purposes
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper
ScopedICAHostKeeper capabilitykeeper.ScopedKeeper
ScopedTransferKeeper capabilitykeeper.ScopedKeeper

// make IBC modules public for test purposes
// these modules are never directly routed to by the IBC Router
FeeMockModule ibcmock.IBCModule

// ---------------
// Nibiru keepers
// ---------------
EpochsKeeper epochskeeper.Keeper
OracleKeeper oraclekeeper.Keeper
InflationKeeper inflationkeeper.Keeper
SudoKeeper keeper.Keeper
DevGasKeeper devgaskeeper.Keeper
TokenFactoryKeeper tokenfactorykeeper.Keeper
EvmKeeper evmkeeper.Keeper

// WASM keepers
WasmKeeper wasmkeeper.Keeper
ScopedWasmKeeper capabilitykeeper.ScopedKeeper
}

func initStoreKeys() (
Expand Down
71 changes: 71 additions & 0 deletions app/keepers/all_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package keepers

import (
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
_ "github.com/cosmos/cosmos-sdk/client/docs/statik"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper"
distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"

stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"

// ---------------------------------------------------------------
// IBC imports

ibcmock "github.com/cosmos/ibc-go/v7/testing/mock"

// ---------------------------------------------------------------
// Nibiru Custom Modules

devgaskeeper "github.com/NibiruChain/nibiru/x/devgas/v1/keeper"
epochskeeper "github.com/NibiruChain/nibiru/x/epochs/keeper"
evmkeeper "github.com/NibiruChain/nibiru/x/evm/keeper"
inflationkeeper "github.com/NibiruChain/nibiru/x/inflation/keeper"
oraclekeeper "github.com/NibiruChain/nibiru/x/oracle/keeper"

"github.com/NibiruChain/nibiru/x/sudo/keeper"

tokenfactorykeeper "github.com/NibiruChain/nibiru/x/tokenfactory/keeper"
)

type PublicKeepers struct {
// AccountKeeper encodes/decodes accounts using the go-amino (binary) encoding/decoding library
AccountKeeper authkeeper.AccountKeeper
// BankKeeper defines a module interface that facilitates the transfer of coins between accounts
BankKeeper bankkeeper.Keeper
StakingKeeper *stakingkeeper.Keeper
/* DistrKeeper is the keeper of the distribution store */
DistrKeeper distrkeeper.Keeper
GovKeeper govkeeper.Keeper
FeeGrantKeeper feegrantkeeper.Keeper
ConsensusParamsKeeper consensusparamkeeper.Keeper

// make scoped keepers public for test purposes
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper
ScopedICAHostKeeper capabilitykeeper.ScopedKeeper
ScopedTransferKeeper capabilitykeeper.ScopedKeeper

// make IBC modules public for test purposes
// these modules are never directly routed to by the IBC Router
FeeMockModule ibcmock.IBCModule

// ---------------
// Nibiru keepers
// ---------------
EpochsKeeper epochskeeper.Keeper
OracleKeeper oraclekeeper.Keeper
InflationKeeper inflationkeeper.Keeper
SudoKeeper keeper.Keeper
DevGasKeeper devgaskeeper.Keeper
TokenFactoryKeeper tokenfactorykeeper.Keeper
EvmKeeper evmkeeper.Keeper

// WASM keepers
WasmKeeper wasmkeeper.Keeper
ScopedWasmKeeper capabilitykeeper.ScopedKeeper
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "FunToken",
"sourceName": "contracts/FunToken.sol",
"contractName": "TestERC20",
"sourceName": "contracts/TestERC20.sol",
"abi": [
{
"inputs": [],
Expand Down
2 changes: 1 addition & 1 deletion e2e/evm/test/erc20.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { FunTokenCompiled } from "../types/ethers-contracts"
describe("ERC-20 contract tests", () => {
it("send, balanceOf", async () => {
const contract = (await deployContract(
"FunTokenCompiled.json",
"TestERC20Compiled.json",
)) as FunTokenCompiled
const contractAddress = await contract.getAddress()
expect(contractAddress).toBeDefined()
Expand Down
2 changes: 1 addition & 1 deletion eth/rpc/rpcapi/eth_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (s *TestSuite) SetupSuite() {
s.network = network
s.ethClient = network.Validators[0].JSONRPCClient

s.contractData, err = embeds.SmartContract_FunToken.Load()
s.contractData, err = embeds.SmartContract_TestERC20.Load()
s.Require().NoError(err)

testAccPrivateKey, _ := crypto.GenerateKey()
Expand Down
6 changes: 6 additions & 0 deletions x/common/set/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,9 @@ func New[T comparable](strs ...T) Set[T] {
}
return set
}

func (set Set[T]) AddMulti(sMulti ...T) {
for _, s := range sMulti {
set[s] = struct{}{}
}
}
10 changes: 10 additions & 0 deletions x/evm/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ import (
// AccountKeeper defines the expected account keeper interface
type AccountKeeper interface {
NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI

// GetModuleAccount gets the module account from the auth account store, if the
// account does not exist in the AccountKeeper, then it is created. This
// differs from the "GetModuleAddress" function, which performs a pure
// computation.
GetModuleAccount(ctx sdk.Context, moduleName string) authtypes.ModuleAccountI

// GetModuleAddress returns an address based on the module name, however it
// does not modify state at all. To create initialize the module account,
// instead use "GetModuleAccount".
GetModuleAddress(moduleName string) sdk.AccAddress
GetAllAccounts(ctx sdk.Context) (accounts []authtypes.AccountI)
IterateAccounts(ctx sdk.Context, cb func(account authtypes.AccountI) bool)
Expand Down
22 changes: 22 additions & 0 deletions x/evm/embeds/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
node_modules
.env

contracts
ignition
bun.lockb
package-lock.json

# Hardhat files
/cache
/artifacts

# TypeChain files
/typechain
/typechain-types

# solidity-coverage files
/coverage
/coverage.json

# Hardhat Ignition default folder for deployments against a local node
ignition/deployments/chain-31337
17 changes: 17 additions & 0 deletions x/evm/embeds/IFunToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

/// @dev Implements the "bankSend" functionality for sending ERC20 tokens as bank
/// coins to a Nibiru bech32 address using the "FunToken" mapping between the
/// ERC20 and bank.
interface IFunToken {
/// @dev bankSend sends ERC20 tokens as coins to a Nibiru base account
/// @param erc20 the address of the ERC20 token contract
/// @param amount the amount of tokens to send
/// @param to the receiving Nibiru base account address as a string
function bankSend(address erc20, uint256 amount, string memory to) external;
}

address constant FUNTOKEN_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000800;

IFunToken constant FUNTOKEN_GATEWAY = IFunToken(FUNTOKEN_PRECOMPILE_ADDRESS);
34 changes: 34 additions & 0 deletions x/evm/embeds/IFunTokenCompiled.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IFunToken",
"sourceName": "contracts/IFunToken.sol",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "erc20",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "string",
"name": "to",
"type": "string"
}
],
"name": "bankSend",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
42 changes: 42 additions & 0 deletions x/evm/embeds/compile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env bash

# 1 | Get all .sol files in the current directory
SOL_FILES=$(find . -maxdepth 1 -name "*.sol")

remove_suffix_from() {
local string="$1"
local suffix="$2"
echo "${string%"$suffix"}"
}

compile_contract() {
local contract_name="$1"
echo "Compiling contract \"$contract_name\""

cp "$contract_name" "contracts/$contract_name"
npx hardhat compile

contract_name_no_file_ext=$(remove_suffix_from "$contract_name" ".sol")
local artifact_fname="artifacts/contracts/$contract_name/${contract_name_no_file_ext}.json"
cp "$artifact_fname" "${contract_name_no_file_ext}Compiled.json"
}

npm i --check-files 2>/dev/null 1>/dev/null
rm -f contracts/Lock.sol

# 2 | Iterate through each file
for precompile_interface in $SOL_FILES
do
# Store the file name in a variable
filename=$(basename "$precompile_interface")

# Call the "foo" function with the filename
# Replace this line with the actual "foo" function or command you want to run
compile_contract "$filename"

# Optional: Print the filename being processed
echo "Processed: $filename"
done

# 3 | Echo a success message
echo "Successfully processed all .sol files in the current directory!"
Loading

0 comments on commit a5ff022

Please sign in to comment.