@@ -105,12 +105,12 @@ struct diff_gas_token_tester : erc20_tester {
105
105
// init();
106
106
}
107
107
108
- std::string getSolidityContractAddress () {
109
- auto r = getRegistedTokenInfo ();
108
+ std::string getSolidityContractAddress (uint64_t primary_id = 0 ) {
109
+ auto r = getRegistedTokenInfo (primary_id );
110
110
return vec_to_hex (r.address , true );
111
111
}
112
112
113
- token_t getRegistedTokenInfo () {
113
+ token_t getRegistedTokenInfo (uint64_t primary_id = 0 ) {
114
114
auto & db = const_cast <chainbase::database&>(control->db ());
115
115
116
116
const auto * existing_tid = db.find <table_id_object, by_code_scope_table>(
@@ -119,12 +119,15 @@ struct diff_gas_token_tester : erc20_tester {
119
119
return {};
120
120
}
121
121
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 ();
128
131
}
129
132
130
133
intx::uint256 egressFee (std::optional<exec_callback> callback = {}, std::optional<bytes> context = {}) {
@@ -212,7 +215,7 @@ struct diff_gas_token_tester : erc20_tester {
212
215
}
213
216
}
214
217
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) {
216
219
auto target = evmc::from_hex<evmc::address>(evm_address);
217
220
218
221
auto txn = generate_tx (*target, 0 , 500'000 );
@@ -232,6 +235,26 @@ struct diff_gas_token_tester : erc20_tester {
232
235
throw ;
233
236
}
234
237
}
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
+ }
235
258
};
236
259
237
260
BOOST_AUTO_TEST_SUITE (different_gas_token_tests)
@@ -610,5 +633,152 @@ try {
610
633
}
611
634
FC_LOG_AND_RETHROW ()
612
635
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 ()
613
783
614
784
BOOST_AUTO_TEST_SUITE_END()
0 commit comments