diff --git a/antelope_contracts/contracts/erc20/include/erc20/erc20.hpp b/antelope_contracts/contracts/erc20/include/erc20/erc20.hpp index 414ecba..bf711e4 100644 --- a/antelope_contracts/contracts/erc20/include/erc20/erc20.hpp +++ b/antelope_contracts/contracts/erc20/include/erc20/erc20.hpp @@ -60,6 +60,7 @@ class [[eosio::contract]] erc20 : public contract { [[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); + [[eosio::action]] void callupgrade(eosio::name token_contract, eosio::symbol token_symbol); struct [[eosio::table("implcontract")]] impl_contract_t { uint64_t id = 0; @@ -136,6 +137,7 @@ class [[eosio::contract]] erc20 : public contract { uint64_t get_next_nonce(); void handle_erc20_transfer(const token_t &token, eosio::asset quantity, const std::string &memo); + void handle_call_upgrade(const bytes& proxy_address); private: eosio::name receiver_account()const; diff --git a/antelope_contracts/contracts/erc20/src/erc20.cpp b/antelope_contracts/contracts/erc20/src/erc20.cpp index 1f77ad3..05bf401 100644 --- a/antelope_contracts/contracts/erc20/src/erc20.cpp +++ b/antelope_contracts/contracts/erc20/src/erc20.cpp @@ -84,7 +84,7 @@ void erc20::upgrade() { evmc::address impl_addr = silkworm::create_address(reserved_addr, next_nonce); contract_table.emplace(_self, [&](auto &v) { - v.id = id; + v.id = contract_table.available_primary_key(); v.address.resize(kAddressLength); memcpy(&(v.address[0]), impl_addr.bytes, kAddressLength); }); @@ -100,7 +100,7 @@ void erc20::upgradeto(std::string impl_address) { impl_contract_table_t contract_table(_self, _self.value); contract_table.emplace(_self, [&](auto &v) { - v.id = id; + v.id = contract_table.available_primary_key(); v.address.resize(kAddressLength); memcpy(&(v.address[0]), address_bytes->data(), kAddressLength); }); @@ -477,4 +477,47 @@ inline eosio::name erc20::receiver_account()const { return get_self(); } +void erc20::callupgrade(eosio::name token_contract, eosio::symbol token_symbol){ + require_auth(get_self()); + + token_table_t token_table(_self, _self.value); + auto index_symbol = token_table.get_index<"by.symbol"_n>(); + auto token_table_iter = index_symbol.find(token_symbol_key(token_contract, token_symbol.code())); + eosio::check(token_table_iter != index_symbol.end(), "token not registered"); + + handle_call_upgrade(token_table_iter->address); +} + +void erc20::handle_call_upgrade(const bytes& proxy_address) { + config_t config = get_config(); + impl_contract_table_t contract_table(_self, _self.value); + eosio::check(contract_table.begin() != contract_table.end(), "no implementaion contract available"); + auto contract_itr = contract_table.end(); + --contract_itr; + + auto pack_uint32 = [&](bytes &ds, uint32_t val) { + uint8_t val_[32] = {}; + val_[28] = (uint8_t)(val >> 24); + val_[29] = (uint8_t)(val >> 16); + val_[30] = (uint8_t)(val >> 8); + val_[31] = (uint8_t)val; + ds.insert(ds.end(), val_, val_ + sizeof(val_)); + }; + + bytes call_data; + // sha(upgradeTo(address)) == 3659cfe6 + uint8_t func_[4] = {0x36,0x59,0xcf,0xe6}; + call_data.insert(call_data.end(), func_, func_ + sizeof(func_)); + + + call_data.insert(call_data.end(), 32 - kAddressLength, 0); // padding for address offset 0 + call_data.insert(call_data.end(), contract_itr->address.begin(), contract_itr->address.end()); + + bytes value_zero; + value_zero.resize(32, 0); + + evm_runtime::call_action call_act(config.evm_account, {{receiver_account(), "active"_n}}); + call_act.send(receiver_account(), proxy_address, value_zero, call_data, config.evm_gaslimit); +} + } // namespace erc20 \ No newline at end of file diff --git a/antelope_contracts/tests/erc20/integrated_tests.cpp b/antelope_contracts/tests/erc20/integrated_tests.cpp index 515db5b..fb2e08a 100644 --- a/antelope_contracts/tests/erc20/integrated_tests.cpp +++ b/antelope_contracts/tests/erc20/integrated_tests.cpp @@ -14,6 +14,7 @@ #include #include "erc20_tester.hpp" +#include using namespace eosio; using namespace eosio::chain; @@ -273,6 +274,89 @@ try { } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(it_upgrade, it_tester) +try { + + + + evm_eoa evm1; + auto addr_alice = silkworm::make_reserved_address("alice"_n.to_uint64_t()); + + // Give evm1 some EOS + transfer_token(eos_token_account, "alice"_n, evm_account, make_asset(1000000, eos_token_symbol), evm1.address_0x().c_str()); + produce_block(); + + + // USDT balance should be zero + auto bal = balanceOf(evm1.address_0x().c_str()); + BOOST_REQUIRE(bal == 0); + + produce_block(); + + transfer_token(token_account, "alice"_n, erc20_account, make_asset(10000, token_symbol), evm1.address_0x().c_str()); + + bal = balanceOf(evm1.address_0x().c_str()); + BOOST_REQUIRE(bal == 990000); + BOOST_REQUIRE(99990000 == get_balance("alice"_n, token_account, symbol::from_string("4,USDT")).get_amount()); + auto tokenInfo = getRegistedTokenInfo(); + BOOST_REQUIRE(tokenInfo.balance == make_asset(9900, token_symbol)); + BOOST_REQUIRE(tokenInfo.fee_balance == make_asset(100, token_symbol)); + + produce_block(); + + auto fee = egressFee(); + // received = 1000/1e6*1e4 = 10 + bridgeTransferERC20(evm1, addr_alice, 1000, "aaa", fee); + produce_block(); + + bal = balanceOf(evm1.address_0x().c_str()); + + BOOST_REQUIRE(bal == 989000); + bal = get_balance("alice"_n, token_account, symbol::from_string("4,USDT")).get_amount(); + + BOOST_REQUIRE(99990010 == get_balance("alice"_n, token_account, symbol::from_string("4,USDT")).get_amount()); + + // upgrade + + evm_eoa deployer; + evmc::address impl_addr = silkworm::create_address(deployer.address, deployer.next_nonce); + + transfer_token(eos_token_account, faucet_account_name, evmin_account, make_asset(1000000, eos_token_symbol), deployer.address_0x().c_str()); + + auto txn = prepare_deploy_contract_tx(solidity::erc20::bytecode, sizeof(solidity::erc20::bytecode), 10'000'000); + + deployer.sign(txn); + pushtx(txn); + produce_block(); + + push_action(erc20_account, "upgradeto"_n, erc20_account, mvo()("impl_address",fc::variant(impl_addr).as_string())); + + produce_block(); + + push_action(erc20_account, "callupgrade"_n, erc20_account, mvo()("token_contract",token_account)("token_symbol",symbol::from_string("4,USDT"))); + + produce_block(); + + // Perform some basic tests again + + transfer_token(token_account, "alice"_n, erc20_account, make_asset(10000, token_symbol), evm1.address_0x().c_str()); + + bal = balanceOf(evm1.address_0x().c_str()); + + BOOST_REQUIRE(bal == 989000 + 990000); + + fee = egressFee(); + // received = 1000/1e6*1e4 = 10 + bridgeTransferERC20(evm1, addr_alice, 1000, "aaa", fee); + produce_block(); + + bal = balanceOf(evm1.address_0x().c_str()); + + BOOST_REQUIRE(bal == 989000 * 2); + +} +FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(it_unregtoken, it_tester) try { evm_eoa evm1;