Skip to content

Commit ea5cfa8

Browse files
committed
add evm2native bridge unittest for different gas token
1 parent e614d51 commit ea5cfa8

File tree

4 files changed

+297
-121
lines changed

4 files changed

+297
-121
lines changed

antelope_contracts/tests/erc20/different_gas_token_tests.cpp

+180-10
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@ struct diff_gas_token_tester : erc20_tester {
105105
// init();
106106
}
107107

108-
std::string getSolidityContractAddress() {
109-
auto r = getRegistedTokenInfo();
108+
std::string getSolidityContractAddress(uint64_t primary_id = 0) {
109+
auto r = getRegistedTokenInfo(primary_id);
110110
return vec_to_hex(r.address, true);
111111
}
112112

113-
token_t getRegistedTokenInfo() {
113+
token_t getRegistedTokenInfo(uint64_t primary_id = 0) {
114114
auto& db = const_cast<chainbase::database&>(control->db());
115115

116116
const auto* existing_tid = db.find<table_id_object, by_code_scope_table>(
@@ -119,12 +119,15 @@ struct diff_gas_token_tester : erc20_tester {
119119
return {};
120120
}
121121
const auto* kv_obj = db.find<chain::key_value_object, chain::by_scope_primary>(
122-
boost::make_tuple(existing_tid->id, 0));
123-
124-
auto r = fc::raw::unpack<token_t>(
125-
kv_obj->value.data(),
126-
kv_obj->value.size());
127-
return r;
122+
boost::make_tuple(existing_tid->id, primary_id));
123+
124+
if (kv_obj) {
125+
auto r = fc::raw::unpack<token_t>(
126+
kv_obj->value.data(),
127+
kv_obj->value.size());
128+
return r;
129+
}
130+
else return token_t();
128131
}
129132

130133
intx::uint256 egressFee(std::optional<exec_callback> callback = {}, std::optional<bytes> context = {}) {
@@ -212,7 +215,7 @@ struct diff_gas_token_tester : erc20_tester {
212215
}
213216
}
214217

215-
void transferERC20(evm_eoa& from, evmc::address& to, intx::uint256 amount) {
218+
void transferERC20(evm_eoa& from, const evmc::address& to, intx::uint256 amount) {
216219
auto target = evmc::from_hex<evmc::address>(evm_address);
217220

218221
auto txn = generate_tx(*target, 0, 500'000);
@@ -232,6 +235,26 @@ struct diff_gas_token_tester : erc20_tester {
232235
throw;
233236
}
234237
}
238+
239+
void approveERC20(evmc::address erc20_contract_addr, evm_eoa& from, const evmc::address& spender, intx::uint256 amount) {
240+
241+
auto txn = generate_tx(erc20_contract_addr, 0, 500'000);
242+
// approve(address spender, uint amount) = 0x095ea7b3
243+
txn.data = evmc::from_hex("0x095ea7b3").value();
244+
txn.data += evmc::from_hex(address_str32(spender)).value(); // param1 (spender: address)
245+
txn.data += evmc::from_hex(uint256_str32(amount)).value(); // param2 (amount: uint256)
246+
247+
auto old_nonce = from.next_nonce;
248+
from.sign(txn);
249+
250+
try {
251+
auto r = pushtx(txn);
252+
// dlog("action trace: ${a}", ("a", r));
253+
} catch (...) {
254+
from.next_nonce = old_nonce;
255+
throw;
256+
}
257+
}
235258
};
236259

237260
BOOST_AUTO_TEST_SUITE(different_gas_token_tests)
@@ -610,5 +633,152 @@ try {
610633
}
611634
FC_LOG_AND_RETHROW()
612635

636+
BOOST_FIXTURE_TEST_CASE(it_evm2native_bridge, diff_gas_token_tester)
637+
try {
638+
auto str_to_bytes = [](const char pri_key[65]) -> std::basic_string<uint8_t> {
639+
std::basic_string<uint8_t> pri_key_bytes;
640+
pri_key_bytes.resize(32, 0);
641+
for (size_t i = 0; i < 32; ++i) {
642+
uint8_t v = from_hex_digit(pri_key[i * 2]);
643+
v <<= 4;
644+
v += from_hex_digit(pri_key[i * 2 + 1]);
645+
pri_key_bytes[i] = v;
646+
}
647+
return pri_key_bytes;
648+
};
649+
650+
// address 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
651+
evm_eoa evm1{str_to_bytes("503f38a9c967ed597e47fe25643985f032b072db8075426a92110f82df48dfcb")};
652+
BOOST_REQUIRE(evm1.address_0x() == "0x5b38da6a701c568545dcfcb03fcb875f56beddc4");
653+
654+
// address 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
655+
evm_eoa evm2{str_to_bytes("7e5bfb82febc4c2c8529167104271ceec190eafdca277314912eaabdb67c6e5f")};
656+
657+
// track the number of evm account from evm runtime contract table
658+
size_t evm_account_total = 0;
659+
while (getEVMAccountInfo(evm_account_total).has_value()) ++evm_account_total;
660+
661+
// Give evm1 some BTC
662+
transfer_token(btc_token_account, "alice"_n, btc_evm_account, make_asset(90'00000000, btc_symbol), evm1.address_0x().c_str());
663+
produce_block();
664+
665+
size_t evm1_account_id = evm_account_total;
666+
std::optional<evm_contract_account_t> acc = getEVMAccountInfo(evm1_account_id);
667+
BOOST_REQUIRE(acc.has_value()); // evm1 account created
668+
BOOST_REQUIRE(acc->address_0x() == "0x5b38da6a701c568545dcfcb03fcb875f56beddc4");
669+
670+
// evm1 deploy gold ERC-20 contract (calculated address 0xd9145cce52d386f254917e481eb44e9943f39138)
671+
deploy_test_erc20_token(evm1);
672+
produce_block();
673+
674+
// ensure deployment is ok
675+
std::optional<evm_contract_account_t> gold_evm_acc = getEVMAccountInfo(evm1_account_id + 1);
676+
BOOST_REQUIRE(gold_evm_acc.has_value()); // gold contract evm account created
677+
BOOST_REQUIRE(gold_evm_acc->code_id.has_value());
678+
BOOST_REQUIRE(gold_evm_acc->address_0x() == "0xd9145cce52d386f254917e481eb44e9943f39138");
679+
680+
// upgdevm2nat
681+
push_action(erc20_account, "upgdevm2nat"_n, erc20_account, mvo());
682+
683+
// before token 1 registerred
684+
BOOST_REQUIRE(getSolidityContractAddress(1) == "0x");
685+
686+
// regevm2nat
687+
push_action(erc20_account, "regevm2nat"_n, erc20_account,
688+
mvo()("erc20_token_address", gold_evm_acc->address_0x())
689+
("native_token_contract", gold_token_account_name)
690+
("ingress_fee", "0.1000 GOLD")
691+
("egress_fee", "0.00000100 BTC")
692+
("erc20_precision", 18)
693+
("override_impl_address", ""));
694+
695+
// Give evm2 some BTC
696+
transfer_token(btc_token_account, "alice"_n, btc_evm_account, make_asset(1'00000000, btc_symbol), evm2.address_0x().c_str());
697+
produce_block();
698+
699+
// refresh evm token address to transfer within EVM world (evm1->evm2), now evm2 has 1.234 GOLD
700+
evm_address = gold_evm_acc->address_0x();
701+
transferERC20(evm1, *(evmc::from_hex<evmc::address>(evm2.address_0x())), (uint64_t)(1'234'000'000'000'000'000));
702+
703+
auto bal = balanceOf(evm2.address_0x().c_str());
704+
BOOST_REQUIRE(bal == 1'234'000'000'000'000'000);
705+
706+
std::string proxy_address = getSolidityContractAddress(1);// <- proxy contract address
707+
evm_address = proxy_address;
708+
// refresh evm token address, using id 1 (proxy contract)
709+
BOOST_REQUIRE(proxy_address == "0x33b57dc70014fd7aa6e1ed3080eed2b619632b8e");
710+
711+
// before calling bridge trnasfer, we need to approve the proxy contract as the spender
712+
approveERC20(*(evmc::from_hex<evmc::address>(gold_evm_acc->address_0x())),
713+
evm2,
714+
*(evmc::from_hex<evmc::address>(proxy_address)), // <- proxy contract address
715+
(uint64_t)(1'000'000'000'000'000'000));
716+
717+
auto addr_alice = silkworm::make_reserved_address("alice"_n.to_uint64_t());
718+
719+
auto fee = egressFee();
720+
// EVM -> native
721+
bridgeTransferERC20(evm2, addr_alice, (uint64_t)700'000'000'000'000'000, "hello world", fee);
722+
produce_block();
723+
724+
evm_address = gold_evm_acc->address_0x();
725+
bal = balanceOf(evm2.address_0x().c_str());
726+
BOOST_REQUIRE(bal == 534'000'000'000'000'000);
727+
728+
BOOST_REQUIRE(7000 == get_balance("alice"_n, gold_token_account_name, symbol::from_string("4,GOLD")).get_amount());
729+
730+
// native -> EVM, 0.2 GOLD (0.1 ingress fee)
731+
transfer_token(gold_token_account_name, "alice"_n, erc20_account, make_asset(2000, symbol::from_string("4,GOLD")), evm2.address_0x().c_str());
732+
733+
evm_address = gold_evm_acc->address_0x();
734+
bal = balanceOf(evm2.address_0x().c_str());
735+
BOOST_REQUIRE(bal == 634'000'000'000'000'000);
736+
737+
// set egress fee to 0.5 EOS
738+
constexpr intx::uint256 minimum_natively_representable = intx::exp(10_u256, intx::uint256(18 - 8));
739+
evm_address = proxy_address;
740+
push_action(erc20_account, "setegressfee"_n, erc20_account,
741+
mvo()("token_contract", gold_token_account_name)("token_symbol_code", "GOLD")("egress_fee", "0.00000789 BTC"));
742+
BOOST_REQUIRE(789 * minimum_natively_representable == egressFee());
743+
744+
// EVM -> native with old fee, should not work
745+
evm_address = proxy_address;
746+
bridgeTransferERC20(evm2, addr_alice, (uint64_t)100'000'000'000'000'000, "hello world", fee);
747+
produce_block();
748+
749+
evm_address = gold_evm_acc->address_0x();
750+
bal = balanceOf(evm2.address_0x().c_str());
751+
BOOST_REQUIRE(bal == 634'000'000'000'000'000);
752+
753+
// EVM -> native with new fee, should work
754+
evm_address = proxy_address;
755+
fee = egressFee();
756+
bridgeTransferERC20(evm2, addr_alice, (uint64_t)100'000'000'000'000'000, "hello world", fee);
757+
produce_block();
758+
759+
evm_address = gold_evm_acc->address_0x();
760+
bal = balanceOf(evm2.address_0x().c_str());
761+
BOOST_REQUIRE(bal == 534'000'000'000'000'000);
762+
763+
// unregtoken
764+
push_action(
765+
erc20_account, "unregtoken"_n, erc20_account, mvo()("eos_contract_name", gold_token_account_name)("token_symbol_code", "GOLD"));
766+
767+
// EOS->EVM not allowed after unregtoken
768+
BOOST_REQUIRE_EXCEPTION(
769+
transfer_token(gold_token_account_name, "alice"_n, erc20_account, make_asset(2000, symbol::from_string("4,GOLD")), evm2.address_0x().c_str()),
770+
eosio_assert_message_exception,
771+
eosio_assert_message_is("received unregistered token"));
772+
773+
// EVM -> native not allowed
774+
evm_address = proxy_address;
775+
fee = egressFee();
776+
BOOST_REQUIRE_EXCEPTION(
777+
bridgeTransferERC20(evm2, addr_alice, (uint64_t)100'000'000'000'000'000, "hello world", fee),
778+
eosio_assert_message_exception,
779+
eosio_assert_message_is("ERC-20 token not registerred"));
780+
781+
}
782+
FC_LOG_AND_RETHROW()
613783

614784
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)