From fba5ccc419d82c026900a1c6f7e5d9bad65f61e5 Mon Sep 17 00:00:00 2001 From: Damon Chen Date: Mon, 4 Jul 2022 13:08:48 +0800 Subject: [PATCH] Problem: Missing examples of using the cpp sdk (fix #103) Close: - #103 Solution: - Add examples --- Makefile | 11 +- defi-wallet-core-rs | 2 +- demo/CMakeLists.txt | 2 + demo/examples/CMakeLists.txt | 51 +++++ demo/examples/src/chainmain_bank_send.cc | 68 ++++++ demo/examples/src/chainmain_nft.cc | 199 ++++++++++++++++++ demo/examples/src/create_payment.cc | 92 ++++++++ demo/examples/src/erc1155.cc | 130 ++++++++++++ demo/examples/src/erc20.cc | 64 ++++++ demo/examples/src/erc721.cc | 103 +++++++++ demo/examples/src/eth.cc | 53 +++++ demo/examples/src/eth_login.cc | 40 ++++ .../get_erc20_transfer_history_blocking.cc | 72 +++++++ .../get_erc721_transfer_history_blocking.cc | 83 ++++++++ .../src/get_token_transfers_blocking.cc | 22 ++ demo/examples/src/get_tokens_blocking.cc | 23 ++ demo/examples/src/new_wallet.cc | 14 ++ demo/examples/src/restore_wallet.cc | 18 ++ demo/examples/src/uint.cc | 22 ++ demo/examples/src/wallet_connect.cc | 145 +++++++++++++ integration_test.sh | 40 ++++ 21 files changed, 1244 insertions(+), 10 deletions(-) create mode 100644 demo/examples/CMakeLists.txt create mode 100644 demo/examples/src/chainmain_bank_send.cc create mode 100644 demo/examples/src/chainmain_nft.cc create mode 100644 demo/examples/src/create_payment.cc create mode 100644 demo/examples/src/erc1155.cc create mode 100644 demo/examples/src/erc20.cc create mode 100644 demo/examples/src/erc721.cc create mode 100644 demo/examples/src/eth.cc create mode 100644 demo/examples/src/eth_login.cc create mode 100644 demo/examples/src/get_erc20_transfer_history_blocking.cc create mode 100644 demo/examples/src/get_erc721_transfer_history_blocking.cc create mode 100644 demo/examples/src/get_token_transfers_blocking.cc create mode 100644 demo/examples/src/get_tokens_blocking.cc create mode 100644 demo/examples/src/new_wallet.cc create mode 100644 demo/examples/src/restore_wallet.cc create mode 100644 demo/examples/src/uint.cc create mode 100644 demo/examples/src/wallet_connect.cc create mode 100755 integration_test.sh diff --git a/Makefile b/Makefile index 821a0ba1..bca2f1ec 100644 --- a/Makefile +++ b/Makefile @@ -26,15 +26,8 @@ cpp: build_cpp # cd demo && git submodule update --init --recursive && make build cd demo && make run -cpp-ci-tests: build_cpp -# Please notice: some env, for example, CRONOSCAN_API_KEY, PAY_API_KEY, and PAY_WEBSOCKET_PORT -# will be loaded in test.yml -# -# Or you can edit `demo/.env` then run `source demo/.env` to load them -# -# Set up `CPP_EXAMPLE_PATH` for cpp integration test - export CPP_EXAMPLE_PATH='$(PWD)/demo/bin/demostatic' && \ - nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests +cpp-ci-tests: + ./integration_test.sh webhook: # 1. Install ngrok for crypto pay api testing: https://ngrok.com/download diff --git a/defi-wallet-core-rs b/defi-wallet-core-rs index 72c65637..32e20683 160000 --- a/defi-wallet-core-rs +++ b/defi-wallet-core-rs @@ -1 +1 @@ -Subproject commit 72c656375652a995086f6ddcd29443d6ecb05c37 +Subproject commit 32e20683999a77fd5ad1b666cac7a9cce2004127 diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index 2d3d54b4..f8ce0a17 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -49,3 +49,5 @@ if (UNIX AND NOT APPLE) # link library play_cpp_sdk built from subdirectory target_link_libraries(demo PUBLIC play_cpp_sdk) endif() + +add_subdirectory(examples) diff --git a/demo/examples/CMakeLists.txt b/demo/examples/CMakeLists.txt new file mode 100644 index 00000000..271bf6c3 --- /dev/null +++ b/demo/examples/CMakeLists.txt @@ -0,0 +1,51 @@ +# add examples +include_directories(../sdk/include/) +include_directories(../third_party/) + +add_executable(new_wallet src/new_wallet.cc) +target_link_libraries(new_wallet PUBLIC play_cpp_sdk) + +add_executable(restore_wallet src/restore_wallet.cc) +target_link_libraries(restore_wallet PUBLIC play_cpp_sdk) + +add_executable(chainmain_bank_send src/chainmain_bank_send.cc) +target_link_libraries(chainmain_bank_send PUBLIC play_cpp_sdk) + +add_executable(chainmain_nft src/chainmain_nft.cc) +target_link_libraries(chainmain_nft PUBLIC play_cpp_sdk) + +add_executable(uint src/uint.cc) +target_link_libraries(uint PUBLIC play_cpp_sdk) + +add_executable(eth src/eth.cc) +target_link_libraries(eth PUBLIC play_cpp_sdk) + +add_executable(eth_login src/eth_login.cc) +target_link_libraries(eth_login PUBLIC play_cpp_sdk) + +add_executable(erc20 src/erc20.cc) +target_link_libraries(erc20 PUBLIC play_cpp_sdk) + +add_executable(erc721 src/erc721.cc) +target_link_libraries(erc721 PUBLIC play_cpp_sdk) + +add_executable(erc1155 src/erc1155.cc) +target_link_libraries(erc1155 PUBLIC play_cpp_sdk) + +add_executable(get_erc20_transfer_history_blocking src/get_erc20_transfer_history_blocking.cc) +target_link_libraries(get_erc20_transfer_history_blocking PUBLIC play_cpp_sdk) + +add_executable(get_erc721_transfer_history_blocking src/get_erc721_transfer_history_blocking.cc) +target_link_libraries(get_erc721_transfer_history_blocking PUBLIC play_cpp_sdk) + +add_executable(get_tokens_blocking src/get_tokens_blocking.cc) +target_link_libraries(get_tokens_blocking PUBLIC play_cpp_sdk) + +add_executable(get_token_transfers_blocking src/get_token_transfers_blocking.cc) +target_link_libraries(get_token_transfers_blocking PUBLIC play_cpp_sdk) + +add_executable(create_payment src/create_payment.cc ../third_party/easywsclient/easywsclient.cpp) +target_link_libraries(create_payment PUBLIC play_cpp_sdk) + +add_executable(wallet_connect src/wallet_connect.cc) +target_link_libraries(wallet_connect PUBLIC play_cpp_sdk) diff --git a/demo/examples/src/chainmain_bank_send.cc b/demo/examples/src/chainmain_bank_send.cc new file mode 100644 index 00000000..8e25a300 --- /dev/null +++ b/demo/examples/src/chainmain_bank_send.cc @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +using namespace org::defi_wallet_core; + +CosmosSDKTxInfoRaw build_txinfo() { + CosmosSDKTxInfoRaw ret; + ret.account_number = 0; + ret.sequence_number = 0; + ret.gas_limit = 5000000; + ret.fee_amount = 25000000000; + ret.fee_denom = "basecro"; + ret.timeout_height = 0; + ret.memo_note = ""; + ret.chain_id = "chainmain-1"; + ret.coin_type = 394; + ret.bech32hrp = "cro"; + return ret; +} + +int main(int argc, char *argv[]) { + CosmosSDKTxInfoRaw tx_info = build_txinfo(); + rust::String from = "cro1u08u5dvtnpmlpdq333uj9tcj75yceggszxpnsy"; + rust::String to = "cro1apdh4yc2lnpephevc6lmpvkyv6s5cjh652n6e4"; + rust::String servercosmos = "http://127.0.0.1:26804"; + rust::String servertendermint = "http://127.0.0.1:26807"; + rust::Box wallet = + restore_wallet("shed crumble dismiss loyal latin million oblige gesture " + "shrug still oxygen custom remove ribbon disorder palace " + "addict again blanket sad flock consider obey popular", + ""); + + // check the original balance + rust::String balance = query_account_balance(servercosmos, to, "basecro", 1); + std::cout << "balance=" << balance << std::endl; + + // query account detils + rust::String detailjson = query_account_details(servercosmos, from); + std::cout << "detailjson=" << detailjson << std::endl; + + // update account_number and sequence_number after querying account details + // info + CosmosAccountInfoRaw detailinfo = + query_account_details_info(servercosmos, from); + tx_info.account_number = detailinfo.account_number; + tx_info.sequence_number = detailinfo.sequence_number; + + // get the private key + rust::Box privatekey = wallet->get_key("m/44'/394'/0'/0/0"); + + // transfer 1 basecro + rust::Vec signedtx = + get_single_bank_send_signed_tx(tx_info, *privatekey, to, 1, "basecro"); + CosmosTransactionReceiptRaw resp = broadcast_tx(servertendermint, signedtx); + std::cout << "tx_hash_hex: " << resp.tx_hash_hex << std::endl + << "code: " << resp.code << std::endl + << "log: " << resp.log << std::endl; + + // dealy and make sure the block is updated + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // check balance updated + balance = query_account_balance(servercosmos, to, "basecro", 1); + std::cout << "balance=" << balance << std::endl; +} diff --git a/demo/examples/src/chainmain_nft.cc b/demo/examples/src/chainmain_nft.cc new file mode 100644 index 00000000..44f60e76 --- /dev/null +++ b/demo/examples/src/chainmain_nft.cc @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include +#include +using namespace org::defi_wallet_core; + +CosmosSDKTxInfoRaw build_txinfo() { + CosmosSDKTxInfoRaw ret; + ret.account_number = 0; + ret.sequence_number = 0; + ret.gas_limit = 5000000; + ret.fee_amount = 25000000000; + ret.fee_denom = "basecro"; + ret.timeout_height = 0; + ret.memo_note = ""; + ret.chain_id = "chainmain-1"; + ret.coin_type = 394; + ret.bech32hrp = "cro"; + return ret; +} + +int main(int argc, char *argv[]) { + CosmosSDKTxInfoRaw tx_info = build_txinfo(); + + rust::String myservertendermint = "http://127.0.0.1:26807"; + rust::String mygrpc = "http://127.0.0.1:26803"; + rust::String myservercosmos = "http://127.0.0.1:26804"; + + rust::String from = "cro1u08u5dvtnpmlpdq333uj9tcj75yceggszxpnsy"; + rust::String to = "cro1apdh4yc2lnpephevc6lmpvkyv6s5cjh652n6e4"; + + rust::Box signer1_wallet = + restore_wallet("shed crumble dismiss loyal latin million oblige gesture " + "shrug still oxygen custom remove ribbon disorder palace " + "addict again blanket sad flock consider obey popular", + ""); + rust::Box signer1_privatekey = + signer1_wallet->get_key("m/44'/394'/0'/0/0"); + + rust::Box signer2_wallet = + restore_wallet("night renew tonight dinner shaft scheme domain oppose " + "echo summer broccoli agent face guitar surface belt " + "veteran siren poem alcohol menu custom crunch index", + ""); + rust::Box signer2_privatekey = + signer2_wallet->get_key("m/44'/394'/0'/0/0"); + + CosmosAccountInfoRaw detailinfo = + query_account_details_info(myservercosmos, from); + auto signer1_sn = detailinfo.sequence_number; + auto signer1_ac = detailinfo.account_number; + + detailinfo = query_account_details_info(myservercosmos, to); + auto signer2_sn = detailinfo.sequence_number; + auto signer2_ac = detailinfo.account_number; + + tx_info.account_number = signer1_ac; + tx_info.sequence_number = signer1_sn; + + // chainmain nft tests + auto denom_id = "testdenomid"; + auto denom_name = "testdenomname"; + auto schema = R""""( + { + "title": "Asset Metadata", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "testidentity" + }, + "description": { + "type": "string", + "description": "testdescription" + }, + "image": { + "type": "string", + "description": "testdescription" + } + } + })""""; + + // issue: from + // signer1_sn += 1; // No need to add sn here, it is the first one + tx_info.sequence_number = signer1_sn; + rust::Vec signedtx = get_nft_issue_denom_signed_tx( + tx_info, *signer1_privatekey, denom_id, denom_name, schema); + + rust::String resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; + std::cout << "issue response: " << resp << std::endl; + + auto token_id = "testtokenid"; + auto token_name = "testtokenname"; + auto token_uri = "testtokenuri"; + auto token_data = ""; + + // mint: from -> to + signer1_sn += 1; + tx_info.sequence_number = signer1_sn; + signedtx = + get_nft_mint_signed_tx(tx_info, *signer1_privatekey, token_id, denom_id, + token_name, token_uri, token_data, to); + resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; + std::cout << "mint response: " << resp << std::endl; + + std::this_thread::sleep_for(std::chrono::seconds(3)); + rust::Box grpc_client = new_grpc_client(mygrpc); + + Pagination pagination; + assert(pagination.enable == false); + assert(pagination.key.size() == 0); + assert(pagination.offset == 0); + assert(pagination.limit == 100); + assert(pagination.count_total == false); + assert(pagination.reverse == false); + rust::Vec denoms = grpc_client->denoms(pagination); + assert(denoms.size() == 1); + assert(denoms[0].id == denom_id); + assert(denoms[0].name == denom_name); + assert(denoms[0].schema == schema); + assert(denoms[0].creator == from); + + BaseNft nft = grpc_client->nft(denom_id, token_id); + std::cout << "nft: " << nft.to_string() << std::endl; + assert(nft.id == token_id); + assert(nft.name == token_name); + assert(nft.uri == token_uri); + assert(nft.data == token_data); + assert(nft.owner == to); + + Collection collection = grpc_client->collection(denom_id, pagination); + std::cout << "collection: " << collection.to_string() << std::endl; + Owner owner = grpc_client->owner(denom_id, to, pagination); + std::cout << "owner: " << owner.to_string() << std::endl; + assert(owner.address == to); + assert(owner.id_collections.size() == 1); + assert(owner.id_collections[0].denom_id == denom_id); + assert(owner.id_collections[0].token_ids.size() == 1); + assert(owner.id_collections[0].token_ids[0] == token_id); + + // transfer: to -> from + tx_info.account_number = signer2_ac; + tx_info.sequence_number = signer2_sn; + signedtx = get_nft_transfer_signed_tx(tx_info, *signer2_privatekey, token_id, + denom_id, from); + resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; + std::cout << "transfer response: " << resp << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(3)); + nft = grpc_client->nft(denom_id, token_id); + std::cout << "nft: " << nft.to_string() << std::endl; + assert(nft.id == token_id); + assert(nft.name == token_name); + assert(nft.uri == token_uri); + assert(nft.data == token_data); + assert(nft.owner == from); + owner = grpc_client->owner(denom_id, from, pagination); + std::cout << "owner: " << owner.to_string() << std::endl; + assert(owner.address == from); + assert(owner.id_collections.size() == 1); + assert(owner.id_collections[0].denom_id == denom_id); + assert(owner.id_collections[0].token_ids.size() == 1); + assert(owner.id_collections[0].token_ids[0] == token_id); + + // edit + tx_info.account_number = signer1_ac; + signer1_sn += 1; + tx_info.sequence_number = signer1_sn; + signedtx = get_nft_edit_signed_tx(tx_info, *signer1_privatekey, token_id, + denom_id, "newname", "newuri", "newdata"); + resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; + std::cout << "edit response: " << resp << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(3)); + nft = grpc_client->nft(denom_id, token_id); + std::cout << "nft: " << nft.to_string() << std::endl; + assert(nft.id == token_id); + assert(nft.name == "newname"); + assert(nft.uri == "newuri"); + assert(nft.data == "newdata"); + assert(nft.owner == from); + uint64_t supply = grpc_client->supply(denom_id, from); + std::cout << "supply: " << supply << std::endl; + assert(supply == 1); + + // burn + signer1_sn += 1; + tx_info.sequence_number = signer1_sn; + signedtx = + get_nft_burn_signed_tx(tx_info, *signer1_privatekey, token_id, denom_id); + resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; + std::cout << "burn response: " << resp << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(3)); + supply = grpc_client->supply(denom_id, from); + std::cout << "supply: " << supply << std::endl; + assert(supply == 0); + + return 0; +} diff --git a/demo/examples/src/create_payment.cc b/demo/examples/src/create_payment.cc new file mode 100644 index 00000000..d9e70d55 --- /dev/null +++ b/demo/examples/src/create_payment.cc @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace com::crypto::game_sdk; +using namespace nlohmann; + +void websocket_client_thread(std::atomic &stop_thread, rust::String &id); + +inline rust::String getEnv(rust::String key) { + rust::String ret; + if (getenv(key.c_str()) != nullptr) { + ret = getenv(key.c_str()); + } + return ret; +} + +// Read pay api key in env +const rust::String PAY_API_KEY = getEnv("PAY_API_KEY"); +// Read websocket port in env +const rust::String PAY_WEBSOCKET_PORT = getEnv("PAY_WEBSOCKET_PORT"); + +int main(int argc, char *argv[]) { + if (PAY_API_KEY == "") + return -1; + + std::atomic stop_thread_1{false}; + rust::String id = ""; + std::thread t1(websocket_client_thread, std::ref(stop_thread_1), + std::ref(id)); + + OptionalArguments opiton_args; + opiton_args.description = "Crypto.com Tee (Unisex)"; + CryptoComPaymentResponse resp = + create_payment(PAY_API_KEY, "2500", "USD", opiton_args); + std::cout << "create payment:" << resp.id << " "; + std::cout << resp.main_app_qr_code << " "; + std::cout << resp.onchain_deposit_address << " "; + std::cout << resp.base_amount << " "; + std::cout << resp.currency << " "; + std::cout << resp.expiration << " "; + std::cout << resp.status << std::endl; + + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + stop_thread_1 = true; // force stopping websocket thread after timeout + id = resp.id; // pass the id to the thread + t1.join(); // pauses until t1 finishes + + return 0; +} + +// A simple websocket client thread +void websocket_client_thread(std::atomic &stop_thread, rust::String &id) { + using easywsclient::WebSocket; + rust::String r_port = PAY_WEBSOCKET_PORT; + std::string port = r_port.c_str(); + std::unique_ptr ws(WebSocket::from_url("ws://127.0.0.1:" + port)); + if (ws == nullptr) + return; + while (ws->getReadyState() != WebSocket::CLOSED) { + WebSocket::pointer wsp = + &*ws; // <-- because a unique_ptr cannot be copied into a lambda + ws->poll(); + ws->dispatch([wsp](std::string msg) { + // std::cout << "Receive webhook event: " << msg << std::endl; + try { + auto message = json::parse(msg); + assert(message.at("type") == "payment.created"); + rust::String id = message.at("data").at("object").at("id"); + CryptoComPaymentResponse resp = get_payment(PAY_API_KEY, id); + std::cout << "get payment: " << resp.id << " "; + std::cout << resp.main_app_qr_code << " "; + std::cout << resp.onchain_deposit_address << " "; + std::cout << resp.base_amount << " "; + std::cout << resp.currency << " "; + std::cout << resp.expiration << " "; + std::cout << resp.status << std::endl; + wsp->close(); + } catch (const nlohmann::detail::parse_error &e) { + std::cout << e.what() << std::endl; + wsp->close(); + } + }); + if (stop_thread) { + return; + } + } + std::cout << "websocket client thread ends" << std::endl; +} diff --git a/demo/examples/src/erc1155.cc b/demo/examples/src/erc1155.cc new file mode 100644 index 00000000..d9a718b9 --- /dev/null +++ b/demo/examples/src/erc1155.cc @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +using namespace org::defi_wallet_core; + +int main(int argc, char *argv[]) { + rust::Box signer1_wallet = + restore_wallet("shed crumble dismiss loyal latin million oblige gesture " + "shrug still oxygen custom remove ribbon disorder palace " + "addict again blanket sad flock consider obey popular", + ""); + rust::String signer1_address = signer1_wallet->get_eth_address(0); + rust::Box signer1_privatekey = + signer1_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::Box signer2_wallet = + restore_wallet("night renew tonight dinner shaft scheme domain oppose " + "echo summer broccoli agent face guitar surface belt " + "veteran siren poem alcohol menu custom crunch index", + ""); + rust::String signer2_address = signer2_wallet->get_eth_address(0); + rust::Box signer2_privatekey = + signer2_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::Box validator1_wallet = + restore_wallet("visit craft resemble online window solution west chuckle " + "music diesel vital settle comic tribe project blame bulb " + "armed flower region sausage mercy arrive release", + ""); + rust::String validator1_address = validator1_wallet->get_eth_address(0); + rust::Box validator1_privatekey = + validator1_wallet->get_key("m/44'/60'/0'/0/0"); + + Erc1155 erc1155 = new_erc1155("0x939D7350c54228e4958e05b65512C4a5BB6A2ACc", + "http://127.0.0.1:26651", 777) + .legacy(); + // To be improved in the contract, now all uri are the same + assert(erc1155.uri("0") == "https://game.example/api/item/{id}.json"); + assert(erc1155.uri("1") == "https://game.example/api/item/{id}.json"); + assert(erc1155.uri("2") == "https://game.example/api/item/{id}.json"); + assert(erc1155.uri("3") == "https://game.example/api/item/{id}.json"); + assert(erc1155.uri("4") == "https://game.example/api/item/{id}.json"); + assert(erc1155.balance_of(signer1_address, "0") == + u256("1000000000000000000")); + assert(erc1155.balance_of(signer1_address, "1") == + u256("1000000000000000000000000000")); + assert(erc1155.balance_of(signer1_address, "2") == u256("1")); + assert(erc1155.balance_of(signer1_address, "3") == u256("1000000000")); + assert(erc1155.balance_of(signer1_address, "4") == u256("1000000000")); + + // safe transfer erc1155 from signer1 to signer2 + rust::Vec erc1155_data; + rust::String status = + erc1155.interval(3000) + .safe_transfer_from(signer1_address, signer2_address, "0", "150", + erc1155_data, *signer1_privatekey) + .status; + assert(status == "1"); + assert(erc1155.balance_of(signer1_address, "0") == + u256("999999999999999850")); + + // safe batch transfer erc1155 from signer1 to signer2 + rust::Vec token_ids, amounts; + token_ids.push_back("1"); + token_ids.push_back("2"); + token_ids.push_back("3"); + token_ids.push_back("4"); + + amounts.push_back("200"); + amounts.push_back("1"); + amounts.push_back("300"); + amounts.push_back("400"); + status = + erc1155 + .safe_batch_transfer_from(signer1_address, signer2_address, token_ids, + amounts, erc1155_data, *signer1_privatekey) + .status; + assert(status == "1"); + assert(erc1155.balance_of(signer1_address, "1") == + u256("999999999999999999999999800")); + assert(erc1155.balance_of(signer1_address, "2") == u256("0")); + assert(erc1155.balance_of(signer1_address, "3") == u256("999999700")); + assert(erc1155.balance_of(signer1_address, "4") == u256("999999600")); + + // toggle set_approval_for_all + assert(erc1155.is_approved_for_all(signer1_address, signer2_address) == 0); + erc1155.set_approval_for_all(signer2_address, true, *signer1_privatekey); + assert(erc1155.is_approved_for_all(signer1_address, signer2_address) == 1); + erc1155.set_approval_for_all(signer2_address, false, *signer1_privatekey); + assert(erc1155.is_approved_for_all(signer1_address, signer2_address) == 0); + // set approval for signer2 + erc1155.set_approval_for_all(signer2_address, true, *signer1_privatekey); + assert(erc1155.is_approved_for_all(signer1_address, signer2_address) == 1); + token_ids.clear(); + token_ids.push_back("1"); + token_ids.push_back("3"); + token_ids.push_back("4"); + + amounts.clear(); + amounts.push_back("500"); + amounts.push_back("600"); + amounts.push_back("700"); + // and safe batch transfer from signer1 to validator1 + status = erc1155 + .safe_batch_transfer_from(signer1_address, validator1_address, + token_ids, amounts, erc1155_data, + *signer2_privatekey) + .status; + assert(status == "1"); + assert(erc1155.balance_of(signer1_address, "1") == + u256("999999999999999999999999300")); + assert(erc1155.balance_of(signer1_address, "2") == u256("0")); + assert(erc1155.balance_of(signer1_address, "3") == u256("999999100")); + assert(erc1155.balance_of(signer1_address, "4") == u256("999998900")); + + assert(erc1155.balance_of(signer2_address, "1") == u256("200")); + assert(erc1155.balance_of(signer2_address, "2") == u256("1")); + assert(erc1155.balance_of(signer2_address, "3") == u256("300")); + assert(erc1155.balance_of(signer2_address, "4") == u256("400")); + + assert(erc1155.balance_of(validator1_address, "1") == u256("500")); + assert(erc1155.balance_of(validator1_address, "2") == u256("0")); + assert(erc1155.balance_of(validator1_address, "3") == u256("600")); + assert(erc1155.balance_of(validator1_address, "4") == u256("700")); + + return 0; +} diff --git a/demo/examples/src/erc20.cc b/demo/examples/src/erc20.cc new file mode 100644 index 00000000..d694f024 --- /dev/null +++ b/demo/examples/src/erc20.cc @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include +using namespace org::defi_wallet_core; + +int main(int argc, char *argv[]) { + rust::Box signer1_wallet = + restore_wallet("shed crumble dismiss loyal latin million oblige gesture " + "shrug still oxygen custom remove ribbon disorder palace " + "addict again blanket sad flock consider obey popular", + ""); + rust::String signer1_address = signer1_wallet->get_eth_address(0); + rust::Box signer1_privatekey = + signer1_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::Box signer2_wallet = + restore_wallet("night renew tonight dinner shaft scheme domain oppose " + "echo summer broccoli agent face guitar surface belt " + "veteran siren poem alcohol menu custom crunch index", + ""); + rust::String signer2_address = signer2_wallet->get_eth_address(0); + rust::Box signer2_privatekey = + signer2_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::Box validator1_wallet = + restore_wallet("visit craft resemble online window solution west chuckle " + "music diesel vital settle comic tribe project blame bulb " + "armed flower region sausage mercy arrive release", + ""); + rust::String validator1_address = validator1_wallet->get_eth_address(0); + + Erc20 erc20 = new_erc20("0x5003c1fcc043D2d81fF970266bf3fa6e8C5a1F3A", + "http://127.0.0.1:26651", 777) + .legacy(); + assert(erc20.name() == "Gold"); + assert(erc20.symbol() == "GLD"); + assert(erc20.decimals() == 18); + U256 erc20_total_supply = erc20.total_supply(); + assert(erc20_total_supply == u256("100000000000000000000000000")); + U256 erc20_balance = erc20.balance_of(signer1_address); + assert(erc20_balance == erc20_total_supply); + + // transfer erc20 token from signer1 to signer2 + rust::String status = + erc20.transfer(signer2_address, "100", *signer1_privatekey).status; + assert(status == "1"); + assert(erc20.balance_of(signer1_address) == erc20_balance.sub(u256("100"))); + + // signer1 approve singer2 allowance + erc20.interval(3000).approve(signer2_address, "1000", *signer1_privatekey); + rust::String allowance = erc20.allowance(signer1_address, signer2_address); + assert(allowance == "1000"); + + // transfer from signer1 to validator1 using the allowance mechanism + erc20.transfer_from(signer1_address, validator1_address, "100", + *signer2_privatekey); + allowance = erc20.allowance(signer1_address, signer2_address); + assert(allowance == "900"); + + return 0; +} diff --git a/demo/examples/src/erc721.cc b/demo/examples/src/erc721.cc new file mode 100644 index 00000000..8b45e301 --- /dev/null +++ b/demo/examples/src/erc721.cc @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +using namespace org::defi_wallet_core; + +int main(int argc, char *argv[]) { + rust::Box signer1_wallet = + restore_wallet("shed crumble dismiss loyal latin million oblige gesture " + "shrug still oxygen custom remove ribbon disorder palace " + "addict again blanket sad flock consider obey popular", + ""); + rust::String signer1_address = signer1_wallet->get_eth_address(0); + rust::Box signer1_privatekey = + signer1_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::Box signer2_wallet = + restore_wallet("night renew tonight dinner shaft scheme domain oppose " + "echo summer broccoli agent face guitar surface belt " + "veteran siren poem alcohol menu custom crunch index", + ""); + rust::String signer2_address = signer2_wallet->get_eth_address(0); + rust::Box signer2_privatekey = + signer2_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::Box validator1_wallet = + restore_wallet("visit craft resemble online window solution west chuckle " + "music diesel vital settle comic tribe project blame bulb " + "armed flower region sausage mercy arrive release", + ""); + rust::String validator1_address = validator1_wallet->get_eth_address(0); + rust::Box validator1_privatekey = + validator1_wallet->get_key("m/44'/60'/0'/0/0"); + + Erc721 erc721 = new_erc721("0x2305f3980715c9D247455504080b41072De38aB9", + "http://127.0.0.1:26651", 777) + .legacy(); + assert(erc721.name() == "GameItem"); + assert(erc721.symbol() == "ITM"); + assert(erc721.token_uri("1") == "https://game.example/item-id-8u5h2m.json"); + // cout << "Total Supply of ERC721=" << erc721.total_supply() << endl; // the + // contract must support IERC721Enumerable + assert(erc721.owner_of("1") == signer1_address); + assert(erc721.balance_of(signer1_address) == u256("1")); + + // transfer erc721 from signer1 to signer2 + rust::String status = erc721 + .transfer_from(signer1_address, signer2_address, + "1", *signer1_privatekey) + .status; + assert(status == "1"); + assert(erc721.balance_of(signer1_address) == u256("0")); + assert(erc721.owner_of("1") == signer2_address); + + // safe transfer erc721 from signer2 to signer1 + status = erc721 + .safe_transfer_from(signer2_address, signer1_address, "1", + *signer2_privatekey) + .status; + assert(status == "1"); + assert(erc721.balance_of(signer1_address) == u256("1")); + assert(erc721.owner_of("1") == signer1_address); + + assert(erc721.balance_of(signer1_address) == u256("1")); + assert(erc721.get_approved("1") == + "0x0000000000000000000000000000000000000000"); + // toggle set_approval_for_all + assert(erc721.is_approved_for_all(signer1_address, signer2_address) == 0); + erc721.set_approval_for_all(signer2_address, true, *signer1_privatekey); + assert(erc721.is_approved_for_all(signer1_address, signer2_address) == 1); + erc721.set_approval_for_all(signer2_address, false, *signer1_privatekey); + assert(erc721.is_approved_for_all(signer1_address, signer2_address) == 0); + + // signer1 approve singer2 to transfer erc721 + erc721.approve(signer2_address, "1", *signer1_privatekey); + assert(erc721.get_approved("1") == signer2_address); + + // safe transfer erc721 from signer1 to validator1 + status = erc721 + .safe_transfer_from(signer1_address, validator1_address, "1", + *signer2_privatekey) + .status; + assert(status == "1"); + assert(erc721.balance_of(validator1_address) == u256("1")); + assert(erc721.owner_of("1") == validator1_address); + + // validator1 set_approval_for_all for singer2 to transfer all assets + assert(erc721.is_approved_for_all(validator1_address, signer2_address) == 0); + erc721.set_approval_for_all(signer2_address, true, *validator1_privatekey); + assert(erc721.is_approved_for_all(validator1_address, signer2_address) == 1); + // safe transfer erc721 from validator1 to signer1 + status = erc721 + .safe_transfer_from(validator1_address, signer1_address, "1", + *signer2_privatekey) + .status; + assert(status == "1"); + assert(erc721.balance_of(signer1_address) == u256("1")); + assert(erc721.owner_of("1") == signer1_address); + + return 0; +} diff --git a/demo/examples/src/eth.cc b/demo/examples/src/eth.cc new file mode 100644 index 00000000..1a08bc65 --- /dev/null +++ b/demo/examples/src/eth.cc @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +using namespace org::defi_wallet_core; + +int main(int argc, char *argv[]) { + rust::Box signer1_wallet = + restore_wallet("shed crumble dismiss loyal latin million oblige gesture " + "shrug still oxygen custom remove ribbon disorder palace " + "addict again blanket sad flock consider obey popular", + ""); + rust::String signer1_address = signer1_wallet->get_eth_address(0); + rust::Box signer1_privatekey = + signer1_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::Box signer2_wallet = + restore_wallet("night renew tonight dinner shaft scheme domain oppose " + "echo summer broccoli agent face guitar surface belt " + "veteran siren poem alcohol menu custom crunch index", + ""); + rust::String signer2_address = signer2_wallet->get_eth_address(0); + rust::Box signer2_privatekey = + signer2_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::String cronosrpc = "http://127.0.0.1:26651"; + + // build transaction information + EthTxInfoRaw eth_tx_info = new_eth_tx_info(); + eth_tx_info.to_address = signer2_address; + eth_tx_info.nonce = get_eth_nonce(signer1_address, cronosrpc); + eth_tx_info.amount = "1"; + eth_tx_info.amount_unit = EthAmount::EthDecimal; + + // build signed transaction + rust::Vec signedtx = + build_eth_signed_tx(eth_tx_info, 777, true, *signer1_privatekey); + U256 balance = get_eth_balance(signer1_address, cronosrpc); + std::cout << "address=" << signer1_address + << " balance=" << balance.to_string() << std::endl; + + // broadcast signed transaction + rust::String status = + broadcast_eth_signed_raw_tx(signedtx, cronosrpc, 1000).status; + assert(status == "1"); + + balance = get_eth_balance(signer1_address, cronosrpc); + std::cout << "address=" << signer1_address + << " balance=" << balance.to_string() << std::endl; + + return 0; +} diff --git a/demo/examples/src/eth_login.cc b/demo/examples/src/eth_login.cc new file mode 100644 index 00000000..29534cef --- /dev/null +++ b/demo/examples/src/eth_login.cc @@ -0,0 +1,40 @@ +#include +#include +#include +#include +using namespace org::defi_wallet_core; + +int main(int argc, char *argv[]) { + // no \n in end of string + std::string info = + "service.org wants you to sign in with your Ethereum account:\n" + "0xD09F7C8C4529CB5D387AA17E33D707C529A6F694\n" + "\n" + "I accept the ServiceOrg Terms of Service: https://service.org/tos\n" + "\n" + "URI: https://service.org/login\n" + "Version: 1\n" + "Chain ID: 1\n" + "Nonce: 32891756\n" + "Issued At: 2021-09-30T16:25:24Z\n" + "Resources:\n" + "- ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/\n" + "- https://example.com/my-web2-claim.json"; + rust::Box logininfo = new_logininfo(info); + + rust::Box signer1_wallet = + restore_wallet("shed crumble dismiss loyal latin million oblige gesture " + "shrug still oxygen custom remove ribbon disorder palace " + "addict again blanket sad flock consider obey popular", + ""); + rust::Box signer1_privatekey = + signer1_wallet->get_key("m/44'/60'/0'/0/0"); + + rust::String default_address = + signer1_wallet->get_default_address(CoinType::CronosMainnet); + rust::Vec signature = logininfo->sign_logininfo(*signer1_privatekey); + assert(signature.size() == 65); + rust::Slice slice{signature.data(), signature.size()}; + logininfo->verify_logininfo(slice); + return 0; +} diff --git a/demo/examples/src/get_erc20_transfer_history_blocking.cc b/demo/examples/src/get_erc20_transfer_history_blocking.cc new file mode 100644 index 00000000..5158b37e --- /dev/null +++ b/demo/examples/src/get_erc20_transfer_history_blocking.cc @@ -0,0 +1,72 @@ +#include +#include +#include +using namespace com::crypto::game_sdk; + +inline rust::String getEnv(rust::String key) { + rust::String ret; + if (getenv(key.c_str()) != nullptr) { + ret = getenv(key.c_str()); + } + return ret; +} + +// Read CronoScan api key in env +const rust::String CRONOSCAN_API_KEY = getEnv("CRONOSCAN_API_KEY"); + +int main(int argc, char *argv[]) { + if (CRONOSCAN_API_KEY == "") + return -1; + + // Get a list of "CRC20 - Token Transfer Events" by Address + // Returns up to a maximum of the last 10000 transactions only + // https://cronoscan.com/tokentxns?a=0xa9b34a4b568e640d5e5d1e6e13101025e1262864 + rust::Vec erc20_txs = get_erc20_transfer_history_blocking( + "0xa9b34a4b568e640d5e5d1e6e13101025e1262864", "", QueryOption::ByAddress, + CRONOSCAN_API_KEY); + + for (rust::Vec::iterator ptr = erc20_txs.begin(); + ptr < erc20_txs.end(); ptr++) { + std::cout << "hash: " << ptr->hash << " "; + std::cout << "to: " << ptr->to_address << " "; + std::cout << "from: " << ptr->from_address << " "; + std::cout << "value:" << ptr->value << " "; + std::cout << "block_no: " << ptr->block_no << " "; + std::cout << "timestamp: " << ptr->timestamp << " "; + std::cout << "contract: " << ptr->contract_address << " " << std::endl; + } + + std::cout << "A total of " << erc20_txs.size() << " transactions" + << std::endl; + + // Get a list of "CRC20 - Token Transfer Events" by ByAddressAndContract + // Returns up to a maximum of the last 10000 transactions only + // https://cronoscan.com/token/0x2d03bece6747adc00e1a131bba1469c15fd11e03?a=0xa9b34a4b568e640d5e5d1e6e13101025e1262864 + erc20_txs = get_erc20_transfer_history_blocking( + "0xa9b34a4b568e640d5e5d1e6e13101025e1262864", + "0x2D03bECE6747ADC00E1a131BBA1469C15fD11e03", + QueryOption::ByAddressAndContract, CRONOSCAN_API_KEY); + + for (rust::Vec::iterator ptr = erc20_txs.begin(); + ptr < erc20_txs.end(); ptr++) { + std::cout << "hash: " << ptr->hash << " "; + std::cout << "to: " << ptr->to_address << " "; + std::cout << "from: " << ptr->from_address << " "; + std::cout << "value:" << ptr->value << " "; + std::cout << "block_no: " << ptr->block_no << " "; + std::cout << "timestamp: " << ptr->timestamp << " "; + std::cout << "contract: " << ptr->contract_address << " " << std::endl; + } + std::cout << "A total of " << erc20_txs.size() << " transactions" + << std::endl; + + // Get a list of "CRC20 - Token Transfer Events" by ByContract + // Returns up to a maximum of the last 10000 transactions only + erc20_txs = get_erc20_transfer_history_blocking( + "", "0x66e428c3f67a68878562e79A0234c1F83c208770", QueryOption::ByContract, + CRONOSCAN_API_KEY); + + std::cout << "A total of " << erc20_txs.size() << " transactions" + << std::endl; + return 0; +} diff --git a/demo/examples/src/get_erc721_transfer_history_blocking.cc b/demo/examples/src/get_erc721_transfer_history_blocking.cc new file mode 100644 index 00000000..d8fee04e --- /dev/null +++ b/demo/examples/src/get_erc721_transfer_history_blocking.cc @@ -0,0 +1,83 @@ +#include +#include +#include +using namespace com::crypto::game_sdk; + +inline rust::String getEnv(rust::String key) { + rust::String ret; + if (getenv(key.c_str()) != nullptr) { + ret = getenv(key.c_str()); + } + return ret; +} + +// Read CronoScan api key in env +const rust::String CRONOSCAN_API_KEY = getEnv("CRONOSCAN_API_KEY"); + +int main(int argc, char *argv[]) { + if (CRONOSCAN_API_KEY == "") + return -1; + + // Get a list of "ERC721 - Token Transfer Events" by Address + // Returns up to a maximum of the last 10000 transactions only + // https://cronoscan.com/tokentxns-nft?a=0x668f126b87936df4f9a98f18c44eb73868fffea0 + rust::Vec erc721_txs = get_erc721_transfer_history_blocking( + "0x668f126b87936df4f9a98f18c44eb73868fffea0", "", QueryOption::ByAddress, + CRONOSCAN_API_KEY); + + for (rust::Vec::iterator ptr = erc721_txs.begin(); + ptr < erc721_txs.end(); ptr++) { + std::cout << "hash: " << ptr->hash << " "; + std::cout << "to: " << ptr->to_address << " "; + std::cout << "from: " << ptr->from_address << " "; + std::cout << "TokenID:" << ptr->value << " "; + std::cout << "block_no: " << ptr->block_no << " "; + std::cout << "timestamp: " << ptr->timestamp << " "; + std::cout << "contract: " << ptr->contract_address << " " << std::endl; + } + + std::cout << "A total of " << erc721_txs.size() << " transactions" + << std::endl; + + // Get a list of "ERC721 - Token Transfer Events" ByAddressAndContract + // Returns up to a maximum of the last 10000 transactions only + // https://cronoscan.com/token/0x562f021423d75a1636db5be1c4d99bc005ccebfe?a=0x668f126b87936df4f9a98f18c44eb73868fffea0 + erc721_txs = get_erc721_transfer_history_blocking( + "0x668f126b87936df4f9a98f18c44eb73868fffea0", + "0x562F021423D75A1636DB5bE1C4D99Bc005ccebFe", + QueryOption::ByAddressAndContract, CRONOSCAN_API_KEY); + + for (rust::Vec::iterator ptr = erc721_txs.begin(); + ptr < erc721_txs.end(); ptr++) { + std::cout << "hash: " << ptr->hash << " "; + std::cout << "to: " << ptr->to_address << " "; + std::cout << "from: " << ptr->from_address << " "; + std::cout << "TokenID:" << ptr->value << " "; + std::cout << "block_no: " << ptr->block_no << " "; + std::cout << "timestamp: " << ptr->timestamp << " "; + std::cout << "contract: " << ptr->contract_address << " " << std::endl; + } + std::cout << "A total of " << erc721_txs.size() << " transactions" + << std::endl; + + // Get a list of "ERC721 - Token Transfer Events" ByContract + // Returns up to a maximum of the last 10000 transactions only + // https://cronoscan.com/token/0x18b73d1f9e2d97057dec3f8d6ea9e30fcadb54d7 + erc721_txs = get_erc721_transfer_history_blocking( + "", "0x18b73D1f9e2d97057deC3f8D6ea9e30FCADB54D7", QueryOption::ByContract, + CRONOSCAN_API_KEY); + for (rust::Vec::iterator ptr = erc721_txs.begin(); + ptr < erc721_txs.end(); ptr++) { + std::cout << "hash: " << ptr->hash << " "; + std::cout << "to: " << ptr->to_address << " "; + std::cout << "from: " << ptr->from_address << " "; + std::cout << "TokenID:" << ptr->value << " "; + std::cout << "block_no: " << ptr->block_no << " "; + std::cout << "timestamp: " << ptr->timestamp << " "; + std::cout << "contract: " << ptr->contract_address << " " << std::endl; + } + + std::cout << "A total of " << erc721_txs.size() << " transactions" + << std::endl; + return 0; +} diff --git a/demo/examples/src/get_token_transfers_blocking.cc b/demo/examples/src/get_token_transfers_blocking.cc new file mode 100644 index 00000000..a19ec916 --- /dev/null +++ b/demo/examples/src/get_token_transfers_blocking.cc @@ -0,0 +1,22 @@ +#include +#include +#include +using namespace com::crypto::game_sdk; + +int main(int argc, char *argv[]) { + rust::Vec token_transfer_txs = get_token_transfers_blocking( + "https://cronos.org/explorer/testnet3/api", + "0x841a15D12aEc9c6039FD132c2FbFF112eD355700", "", QueryOption::ByAddress); + for (rust::Vec::iterator ptr = token_transfer_txs.begin(); + ptr < token_transfer_txs.end(); ptr++) { + std::cout << ptr->hash << " "; + std::cout << ptr->to_address << " "; + std::cout << ptr->from_address << " "; + std::cout << ptr->value << " "; + std::cout << ptr->block_no << " "; + std::cout << ptr->timestamp << " "; + std::cout << ptr->contract_address << " " << std::endl; + } + + return 0; +} diff --git a/demo/examples/src/get_tokens_blocking.cc b/demo/examples/src/get_tokens_blocking.cc new file mode 100644 index 00000000..cc1fd7d3 --- /dev/null +++ b/demo/examples/src/get_tokens_blocking.cc @@ -0,0 +1,23 @@ +#include +#include +#include +using namespace com::crypto::game_sdk; + +int main(int argc, char *argv[]) { + // Blockscout examples + rust::Vec tokens_txs = + get_tokens_blocking("https://blockscout.com/xdai/mainnet/api", + "0x652d53227d7013f3FbBeA542443Dc2eeF05719De"); + for (rust::Vec::iterator ptr = tokens_txs.begin(); + ptr < tokens_txs.end(); ptr++) { + std::cout << ptr->balance << " "; + std::cout << ptr->contract_address << " "; + std::cout << ptr->decimals << " "; + std::cout << ptr->id << " "; + std::cout << ptr->name << " "; + std::cout << ptr->symbol << " "; + std::cout << ptr->token_type << std::endl; + } + + return 0; +} diff --git a/demo/examples/src/new_wallet.cc b/demo/examples/src/new_wallet.cc new file mode 100644 index 00000000..ab3b0aae --- /dev/null +++ b/demo/examples/src/new_wallet.cc @@ -0,0 +1,14 @@ +#include +#include +#include +using namespace org::defi_wallet_core; + +int main(int argc, char *argv[]) { + rust::Box wallet = new_wallet("", MnemonicWordCount::TwentyFour); + std::cout << wallet->get_default_address(CoinType::CronosMainnet) + << std::endl; + std::cout << wallet->get_address(CoinType::CronosMainnet, 0) << std::endl; + std::cout << wallet->get_eth_address(0) << std::endl; + rust::Box private_key = wallet->get_key("m/44'/60/0'/0/0"); + return 0; +} diff --git a/demo/examples/src/restore_wallet.cc b/demo/examples/src/restore_wallet.cc new file mode 100644 index 00000000..1dbab202 --- /dev/null +++ b/demo/examples/src/restore_wallet.cc @@ -0,0 +1,18 @@ +#include +#include +#include +using namespace org::defi_wallet_core; + +int main(int argc, char *argv[]) { + rust::Box wallet = + restore_wallet("shed crumble dismiss loyal latin million oblige gesture " + "shrug still oxygen custom remove ribbon disorder palace " + "addict again blanket sad flock consider obey popular", + ""); + std::cout << wallet->get_default_address(CoinType::CronosMainnet) + << std::endl; + std::cout << wallet->get_address(CoinType::CronosMainnet, 0) << std::endl; + std::cout << wallet->get_eth_address(0) << std::endl; + rust::Box private_key = wallet->get_key("m/44'/60/0'/0/0"); + return 0; +} diff --git a/demo/examples/src/uint.cc b/demo/examples/src/uint.cc new file mode 100644 index 00000000..e9803007 --- /dev/null +++ b/demo/examples/src/uint.cc @@ -0,0 +1,22 @@ +#include +#include +#include +using namespace org::defi_wallet_core; + +int main(int argc, char *argv[]) { + assert(u256("15") == u256("15", 10)); + assert(u256("15") == u256("0xf", 16)); + assert(u256("1000") == u256("100").add(u256("900"))); + assert(u256("999999999999999999999999300") == + u256("1000000000000000000000000000").sub(u256("700"))); + assert(u256("199999999999999999980000200") == + u256("99999999999999999990000100").mul(u256("2"))); + assert(u256("1999999999999999999800002") == + u256("199999999999999999980000200").div(u256("100"))); + assert(u256("800002") == + u256("1999999999999999999800002").rem(u256("1000000"))); + assert(u256("512003840009600008") == u256("800002").pow(u256("3"))); + assert(u256("512003840009600008").neg() == + u256_max_value().sub(u256("512003840009600007"))); + return 0; +} diff --git a/demo/examples/src/wallet_connect.cc b/demo/examples/src/wallet_connect.cc new file mode 100644 index 00000000..506644ba --- /dev/null +++ b/demo/examples/src/wallet_connect.cc @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace com::crypto::game_sdk; + +// convert byte array to hex string +rust::String bytes_to_hex_string(rust::Vec bytes) { + std::stringstream ret; + ret << std::hex; + for (int i = 0; i < bytes.size(); i++) { + ret << std::setw(2) << std::setfill('0') << (int)bytes[i]; + } + return ret.str(); +} + +rust::String address_to_hex_string(::std::array<::std::uint8_t, 20> bytes) { + std::stringstream ret; + ret << std::hex; + for (int i = 0; i < 20; i++) { + ret << std::setw(2) << std::setfill('0') << (int)bytes[i]; + } + return ret.str(); +} + +// if session already exists, restore session +rust::Box make_new_client(std::string filename) { + + std::ifstream file(filename.c_str()); + if (file.is_open()) { + std::string sessioninfostring((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + rust::Box client = + walletconnect_restore_client(sessioninfostring); + return client; + } else { + rust::Box client = walletconnect_new_client( + "Defi WalletConnect example.", "http://localhost:8080/", + rust::Vec(), "Defi WalletConnect Web3 Example"); + std::cout << "qrcode= " << client->get_connection_string() << std::endl; + + return client; + } +} + +class UserWalletConnectCallback : public WalletConnectCallback { +public: + UserWalletConnectCallback() {} + virtual ~UserWalletConnectCallback() {} + void onConnected(const WalletConnectSessionInfo &sessioninfo) const; + void onDisconnected(const WalletConnectSessionInfo &sessioninfo) const; + void onConnecting(const WalletConnectSessionInfo &sessioninfo) const; + void onUpdated(const WalletConnectSessionInfo &sessioninfo) const; +}; +void print_session(const WalletConnectSessionInfo &sessioninfo) { + std::cout << "connected: " << sessioninfo.connected << std::endl; + std::cout << "chain_id: " << sessioninfo.chain_id << std::endl; + // iterate over accounts + for (auto &account : sessioninfo.accounts) { + std::cout << "account: " << account << std::endl; + } + std::cout << "bridge: " << sessioninfo.bridge << std::endl; + std::cout << "client_id: " << sessioninfo.client_id << std::endl; + std::cout << "client_meta: " << sessioninfo.client_meta << std::endl; + std::cout << "peer_id: " << sessioninfo.peer_id << std::endl; + std::cout << "peer_meta: " << sessioninfo.peer_meta << std::endl; + std::cout << "handshake_topic: " << sessioninfo.handshake_topic << std::endl; +} +void UserWalletConnectCallback::onConnected( + const WalletConnectSessionInfo &sessioninfo) const { + std::cout << "user c++ onConnected" << std::endl; + print_session(sessioninfo); +} +void UserWalletConnectCallback::onDisconnected( + const WalletConnectSessionInfo &sessioninfo) const { + std::cout << "user c++ onDisconnected" << std::endl; + print_session(sessioninfo); +} +void UserWalletConnectCallback::onConnecting( + const WalletConnectSessionInfo &sessioninfo) const { + std::cout << "user c++ onConnecting" << std::endl; + print_session(sessioninfo); + // this is testing purpose, comment this line for actual test + exit(0); +} +void UserWalletConnectCallback::onUpdated( + const WalletConnectSessionInfo &sessioninfo) const { + std::cout << "user c++ onUpdated" << std::endl; + print_session(sessioninfo); +} + +int main(int argc, char *argv[]) { + bool test_personal = false; + std::string filename = "sessioninfo.json"; + try { + rust::Box client = make_new_client(filename); + WalletConnectCallback *usercallbackraw = new UserWalletConnectCallback(); + std::unique_ptr usercallback(usercallbackraw); + client->setup_callback(std::move(usercallback)); + rust::String uri = client->print_uri(); + WalletConnectEnsureSessionResult result = client->ensure_session_blocking(); + + rust::String sessioninfo = client->save_client(); + { + std::ofstream outfile(filename); + outfile.write(sessioninfo.c_str(), sessioninfo.size()); + } + + assert(result.addresses.size() > 0); + + if (test_personal) { + /* message signing */ + rust::Vec sig1 = + client->sign_personal_blocking("hello", result.addresses[0].address); + std::cout << "signature=" << bytes_to_hex_string(sig1).c_str() + << std::endl; + std::cout << "signature length=" << sig1.size() << std::endl; + } else { + /* legacy eth sign */ + WalletConnectTxLegacy info; + info.to = rust::String( + std::string("0x") + + address_to_hex_string(result.addresses[0].address).c_str()); + info.gas = "21000"; // gas limit + info.gas_price = "10000"; // gas price + info.value = "100000000000000"; // 0.0001 eth + info.data = rust::Vec(); + info.nonce = "1"; + rust::Vec sig1 = client->sign_legacy_transaction_blocking( + info, result.addresses[0].address); + + std::cout << "signature=" << bytes_to_hex_string(sig1).c_str() + << std::endl; + std::cout << "signature length=" << sig1.size() << std::endl; + } + + } catch (const rust::Error e) { + std::cout << "wallet connect error=" << e.what() << std::endl; + } + + return 0; +} diff --git a/integration_test.sh b/integration_test.sh new file mode 100755 index 00000000..5637224f --- /dev/null +++ b/integration_test.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Please notice: some env, for example, CRONOSCAN_API_KEY, PAY_API_KEY, and PAY_WEBSOCKET_PORT +# will be loaded in test.yml +# +# Or you can edit `demo/.env` then run `source demo/.env` to load them + +# Set up `CPP_EXAMPLE_PATH` for cpp integration test +export CPP_EXAMPLE_PATH='$(pwd)/demo/bin/demostatic' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +export CPP_EXAMPLE_PATH='$(pwd)/demo/build/examples/chainmain_bank_send' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +export CPP_EXAMPLE_PATH='$(pwd)/demo/build/examples/chainmain_nft' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +export CPP_EXAMPLE_PATH='$(pwd)/demo/build/examples/uint' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +export CPP_EXAMPLE_PATH='$(pwd)/demo/build/examples/eth' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +export CPP_EXAMPLE_PATH='$(pwd)/demo/build/examples/eth_login' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +export CPP_EXAMPLE_PATH='$(pwd)/demo/build/examples/erc20' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +export CPP_EXAMPLE_PATH='$(pwd)/demo/build/examples/erc721' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +export CPP_EXAMPLE_PATH='$(pwd)/demo/build/examples/erc1155' && \ +nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests + +$(pwd)/demo/build/examples/get_erc20_transfer_history_blocking +$(pwd)/demo/build/examples/get_erc721_transfer_history_blocking +$(pwd)/demo/build/examples/get_tokens_blocking +$(pwd)/demo/build/examples/get_token_transfers_blocking +$(pwd)/demo/build/examples/create_payment +$(pwd)/demo/build/examples/wallet_connect