diff --git a/antelope_contracts/contracts/erc20/include/erc20/erc20.hpp b/antelope_contracts/contracts/erc20/include/erc20/erc20.hpp index 830afaa..414ecba 100644 --- a/antelope_contracts/contracts/erc20/include/erc20/erc20.hpp +++ b/antelope_contracts/contracts/erc20/include/erc20/erc20.hpp @@ -56,7 +56,10 @@ class [[eosio::contract]] erc20 : public contract { [[eosio::action]] void withdrawfee(eosio::name token_contract, eosio::asset quantity, eosio::name to, std::string memo); [[eosio::action]] void unregtoken(eosio::name eos_contract_name, eosio::symbol_code token_symbol_code); - [[eosio::action]] void setconfig(std::optional evm_account, std::optional gas_token_symbol, std::optional gaslimit, std::optional init_gaslimit); + + [[eosio::action]] void init(eosio::name evm_account, eosio::symbol gas_token_symbol, uint64_t gaslimit, uint64_t init_gaslimit); + + [[eosio::action]] void setgaslimit(std::optional gaslimit, std::optional init_gaslimit); struct [[eosio::table("implcontract")]] impl_contract_t { uint64_t id = 0; @@ -115,17 +118,17 @@ class [[eosio::contract]] erc20 : public contract { EOSLIB_SERIALIZE(config_t, (evm_gaslimit)(evm_init_gaslimit)(evm_account)(evm_gas_token_symbol)); }; typedef eosio::singleton<"config"_n, config_t> config_singleton_t; + config_t get_config() const { config_singleton_t config(get_self(), get_self().value); - if (!config.exists()) { - return config_t{}; - } else { - return config.get(); - } + eosio::check(config.exists(), "erc20 config not exist"); + return config.get(); } - intx::uint256 get_minimum_natively_representable() const { - return intx::exp(10_u256, intx::uint256(evm_precision - get_config().evm_gas_token_symbol.precision())); + + intx::uint256 get_minimum_natively_representable(const config_t& config) const { + return intx::exp(10_u256, intx::uint256(evm_precision - config.evm_gas_token_symbol.precision())); } + void set_config(const config_t &v) { config_singleton_t config(get_self(), get_self().value); config.set(v, get_self()); diff --git a/antelope_contracts/contracts/erc20/src/erc20.cpp b/antelope_contracts/contracts/erc20/src/erc20.cpp index 875099d..1f77ad3 100644 --- a/antelope_contracts/contracts/erc20/src/erc20.cpp +++ b/antelope_contracts/contracts/erc20/src/erc20.cpp @@ -122,7 +122,7 @@ void erc20::upgradeto(std::string impl_address) { eosio::check(egress_fee.symbol == config.evm_gas_token_symbol, "egress_fee should have native token symbol"); intx::uint256 egress_fee_evm = egress_fee.amount; - egress_fee_evm *= get_minimum_natively_representable(); + egress_fee_evm *= get_minimum_natively_representable(config); token_table_t token_table(_self, _self.value); auto index_symbol = token_table.get_index<"by.symbol"_n>(); @@ -414,7 +414,7 @@ void erc20::setegressfee(eosio::name token_contract, eosio::symbol_code token_sy eosio::check(egress_fee >= message_receivers_iter->min_fee, "egress fee must be at least as large as the receiver's minimum fee"); intx::uint256 egress_fee_evm = egress_fee.amount; - egress_fee_evm *= get_minimum_natively_representable(); + egress_fee_evm *= get_minimum_natively_representable(config); auto pack_uint256 = [&](bytes &ds, const intx::uint256 &val) { uint8_t val_[32] = {}; @@ -446,12 +446,28 @@ void erc20::unregtoken(eosio::name token_contract, eosio::symbol_code token_symb index_symbol.erase(token_table_iter); } -void erc20::setconfig(std::optional evm_account, std::optional gas_token_symbol, std::optional gaslimit, std::optional init_gaslimit) { +void erc20::init(eosio::name evm_account, eosio::symbol gas_token_symbol, uint64_t gaslimit, uint64_t init_gaslimit) { + require_auth(get_self()); + + config_singleton_t config_table(get_self(), get_self().value); + eosio::check(!config_table.exists(), "erc20 config already initialized"); + + config_t config; + token_table_t token_table(_self, _self.value); + if (token_table.begin() != token_table.end()) { + eosio::check(evm_account == default_evm_account && gas_token_symbol == default_native_token_symbol, "can only init with native EOS symbol"); + } + config.evm_account = evm_account; + config.evm_gas_token_symbol = gas_token_symbol; + config.evm_gaslimit = gaslimit; + config.evm_init_gaslimit = init_gaslimit; + set_config(config); +} + +void erc20::setgaslimit(std::optional gaslimit, std::optional init_gaslimit) { require_auth(get_self()); config_t config = get_config(); - if (evm_account.has_value()) config.evm_account = *evm_account; - if (gas_token_symbol.has_value()) config.evm_gas_token_symbol = *gas_token_symbol; if (gaslimit.has_value()) config.evm_gaslimit = *gaslimit; if (init_gaslimit.has_value()) config.evm_init_gaslimit = *init_gaslimit; set_config(config); diff --git a/antelope_contracts/tests/erc20/erc20_tester.cpp b/antelope_contracts/tests/erc20/erc20_tester.cpp index 5e68c20..287c2f8 100644 --- a/antelope_contracts/tests/erc20/erc20_tester.cpp +++ b/antelope_contracts/tests/erc20/erc20_tester.cpp @@ -114,7 +114,7 @@ evm_eoa::~evm_eoa() { secp256k1_context_destroy(ctx); } -erc20_tester::erc20_tester(bool use_real_evm, std::string native_symbol_str) : native_symbol(symbol::from_string(native_symbol_str)) { +erc20_tester::erc20_tester(bool use_real_evm, eosio::chain::name evm_account_, std::string native_symbol_str) : evm_account(evm_account_), native_symbol(symbol::from_string(native_symbol_str)) { auto def_conf = default_config(tempdir, 4096); cfg = def_conf.first; @@ -171,6 +171,15 @@ erc20_tester::erc20_tester(bool use_real_evm, std::string native_symbol_str) : n set_abi(erc20_account, testing::contracts::erc20_abi().data()); produce_block(); + + if (native_symbol_str.length()) { + push_action(erc20_account, "init"_n, erc20_account, mvo("evm_account", evm_account)("gas_token_symbol", native_symbol_str)("gaslimit", 500000)("init_gaslimit", 10000000)); + + BOOST_REQUIRE_EXCEPTION( + push_action(erc20_account, "init"_n, erc20_account, mvo("evm_account", evm_account)("gas_token_symbol", native_symbol_str)("gaslimit", 1)("init_gaslimit", 1)), + eosio_assert_message_exception, + testing::eosio_assert_message_is("erc20 config already initialized")); + } if (use_real_evm) { set_code(evm_account, testing::contracts::evm_wasm()); @@ -316,6 +325,7 @@ transaction_trace_ptr erc20_tester::push_action(const account_name& code, transaction_trace_ptr erc20_tester::pushtx(const silkworm::Transaction& trx, name miner) { + if (miner == name()) miner = evm_account; silkworm::Bytes rlp; silkworm::rlp::encode(rlp, trx); diff --git a/antelope_contracts/tests/erc20/erc20_tester.hpp b/antelope_contracts/tests/erc20/erc20_tester.hpp index 5905ac6..18d07d3 100644 --- a/antelope_contracts/tests/erc20/erc20_tester.hpp +++ b/antelope_contracts/tests/erc20/erc20_tester.hpp @@ -113,7 +113,6 @@ constexpr uint64_t suggested_gas_price = 150'000'000'000; // 150 gwei constexpr uint32_t suggested_miner_cut = 10'000; // 10% constexpr uint64_t suggested_ingress_bridge_fee_amount = 70; // 0.0070 EOS -extern const eosio::chain::name evm_account; extern const eosio::chain::name faucet_account_name; extern const eosio::chain::name erc20_account; extern const eosio::chain::name evmin_account; @@ -126,14 +125,15 @@ class erc20_tester : public eosio::testing::base_tester { using testing::base_tester::push_action; static constexpr eosio::chain::name token_account = "tethertether"_n; - static constexpr eosio::chain::name evm_account = "eosio.evm"_n; + static constexpr eosio::chain::name faucet_account_name = "eosio.faucet"_n; static constexpr eosio::chain::name erc20_account = "eosio.erc2o"_n; static constexpr eosio::chain::name eos_system_account = "eosio"_n; static constexpr eosio::chain::name eos_token_account = "eosio.token"_n; + const eosio::chain::name evm_account = "eosio.evm"_n; const eosio::chain::symbol native_symbol; - explicit erc20_tester(bool use_real_evm = false, std::string native_symbol_str = "4,EOS"); + explicit erc20_tester(bool use_real_evm = false, eosio::chain::name evm_account_ = "eosio.evm"_n, std::string native_symbol_str = "4,EOS"); unsigned int exec_count = 0; // ensure uniqueness in exec @@ -141,7 +141,7 @@ class erc20_tester : public eosio::testing::base_tester { eosio::chain::asset make_asset(int64_t amount, const eosio::chain::symbol& target_symbol) const { return eosio::chain::asset(amount, target_symbol); } eosio::chain::transaction_trace_ptr transfer_token(eosio::chain::name token_account_name, eosio::chain::name from, eosio::chain::name to, eosio::chain::asset quantity, std::string memo = ""); void prepare_self_balance(uint64_t fund_amount = 100'0000); - transaction_trace_ptr bridgereg(eosio::chain::name receiver, eosio::chain::name handler, eosio::chain::asset min_fee, vector extra_signers={evm_account}); + transaction_trace_ptr bridgereg(eosio::chain::name receiver, eosio::chain::name handler, eosio::chain::asset min_fee, vector extra_signers={"eosio.evm"_n}); void open(name owner); transaction_trace_ptr exec(const exec_input& input, const std::optional& callback); eosio::chain::action get_action( account_name code, action_name acttype, std::vector auths, @@ -158,7 +158,7 @@ class erc20_tester : public eosio::testing::base_tester { generate_tx(const evmc::address& to, const intx::uint256& value, uint64_t gas_limit = 21000) const; silkworm::Transaction prepare_deploy_contract_tx(const unsigned char* contract, size_t size, uint64_t gas_limit) const; - transaction_trace_ptr pushtx(const silkworm::Transaction& trx, name miner = evm_account); + transaction_trace_ptr pushtx(const silkworm::Transaction& trx, name miner = {}); eosio::chain::abi_serializer abi_ser; eosio::chain::abi_serializer token_abi_ser; diff --git a/antelope_contracts/tests/erc20/integrated_tests.cpp b/antelope_contracts/tests/erc20/integrated_tests.cpp index 5cafe01..515db5b 100644 --- a/antelope_contracts/tests/erc20/integrated_tests.cpp +++ b/antelope_contracts/tests/erc20/integrated_tests.cpp @@ -407,6 +407,19 @@ try { BOOST_REQUIRE(tokenInfo.fee_balance == make_asset(200, token_symbol)); produce_block(); + // setting a lower gas limit, USDT(EOS)-> USDT(EVM) will fails + push_action(erc20_account, "setgaslimit"_n, erc20_account, mvo("gaslimit", 21001)("init_gaslimit", 10000000)); + + BOOST_REQUIRE_EXCEPTION( + transfer_token(token_account, "alice"_n, erc20_account, make_asset(102, token_symbol), evm1.address_0x().c_str()), + eosio_assert_message_exception, + eosio_assert_message_is("pre_validate_transaction error: 22 Intrinsic gas too low") + ); + + // set it back + push_action(erc20_account, "setgaslimit"_n, erc20_account, mvo("gaslimit", 500000)("init_gaslimit", 10000000)); + transfer_token(token_account, "alice"_n, erc20_account, make_asset(103, token_symbol), evm1.address_0x().c_str()); + } FC_LOG_AND_RETHROW()