├── play-cpp-sdk ├── .cargo │ └── config ├── README.md ├── src │ └── lib.rs ├── Cargo.toml └── LICENSE ├── rust-toolchain ├── .github ├── CODEOWNERS ├── dependabot.yml ├── workflows │ ├── clang-format-check.yml │ ├── audit.yml │ ├── android-build.yml │ ├── semgrep.yml │ ├── ios-build.yml │ ├── mac-build.yml │ ├── macarm64-build.yml │ ├── linux-libstdc++-build.yml │ ├── linux-libc++-build.yml │ ├── test.yml │ ├── codeql-analysis.yml │ ├── win-build.yml │ └── ci.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── PULL_REQUEST_TEMPLATE.md └── actions │ └── android │ └── action.yml ├── .clang-format ├── demo ├── .clang-format ├── examples │ ├── src │ │ ├── .clang-format │ │ ├── get_token_holders.cc │ │ ├── new_wallet.cc │ │ ├── restore_wallet.cc │ │ ├── get_tokens_blocking.cc │ │ ├── get_token_transfers_blocking.cc │ │ ├── uint.cc │ │ ├── eth_login.cc │ │ ├── eth.cc │ │ ├── erc20.cc │ │ ├── chainmain_bank_send.cc │ │ ├── get_erc20_transfer_history_blocking.cc │ │ ├── get_erc721_transfer_history_blocking.cc │ │ ├── create_payment.cc │ │ ├── get_wallet.cc │ │ ├── erc721.cc │ │ ├── erc1155.cc │ │ └── chainmain_nft.cc │ └── CMakeLists.txt ├── .flake8 ├── extra.h ├── pre_build.bat ├── package.json ├── .env ├── CMakeSettings.json ├── main.cc ├── CMakeLists.txt ├── demo.sln ├── sdk │ └── CMakeLists.txt ├── server.js └── Makefile ├── extra-cpp-bindings ├── README.md ├── src │ ├── error.rs │ ├── pay.cc │ └── walletconnectcallback.cc ├── LICENSE ├── build.rs ├── Cargo.toml └── include │ ├── pay.h │ └── walletconnectcallback.h ├── windows_install.bat ├── install.sh ├── Cargo.toml ├── wallet-connect ├── src │ ├── v2 │ │ ├── mod.rs │ │ ├── crypto.rs │ │ └── session.rs │ ├── crypto.rs │ ├── protocol.rs │ ├── lib.rs │ ├── hex.rs │ ├── protocol │ │ ├── topic.rs │ │ ├── message.rs │ │ └── rpc.rs │ ├── serialization.rs │ ├── crypto │ │ ├── key.rs │ │ └── aead.rs │ ├── client │ │ ├── options.rs │ │ └── session.rs │ └── uri.rs ├── LICENSE ├── README.md ├── Cargo.toml └── examples │ └── web3.rs ├── .gitmodules ├── LICENSE ├── windows_build.bat ├── msys_build.sh ├── NOTICE ├── .gitignore ├── integration_test.sh ├── SECURITY.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CHANGELOG.md ├── README.md └── Makefile /play-cpp-sdk/.cargo/config: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | stable 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @cronos-labs/cronos-play 2 | -------------------------------------------------------------------------------- /play-cpp-sdk/README.md: -------------------------------------------------------------------------------- 1 | # play-cpp-sdk 2 | The play cpp sdk wrapper 3 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | SortIncludes: Never 2 | IndentWidth: 4 3 | BasedOnStyle: LLVM -------------------------------------------------------------------------------- /demo/.clang-format: -------------------------------------------------------------------------------- 1 | SortIncludes: Never 2 | IndentWidth: 4 3 | BasedOnStyle: LLVM -------------------------------------------------------------------------------- /demo/examples/src/.clang-format: -------------------------------------------------------------------------------- 1 | SortIncludes: Never 2 | IndentWidth: 4 3 | BasedOnStyle: LLVM -------------------------------------------------------------------------------- /play-cpp-sdk/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use defi_wallet_core_cpp::*; 2 | pub use extra_cpp_bindings::*; 3 | -------------------------------------------------------------------------------- /demo/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = E203 4 | exclude = .git,__pycache__,./third_party 5 | -------------------------------------------------------------------------------- /extra-cpp-bindings/README.md: -------------------------------------------------------------------------------- 1 | # extra-cpp-bindings 2 | Extra cpp bindings: etherscan/cronoscan, crypto.com pay, and wallet connect 3 | -------------------------------------------------------------------------------- /demo/extra.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_blackscout_cronoscan(); 4 | void test_wallet_connect(); 5 | void test_wallet_connect2(); 6 | -------------------------------------------------------------------------------- /demo/pre_build.bat: -------------------------------------------------------------------------------- 1 | git config --global core.symlinks true 2 | cd .. 3 | git submodule update --init --recursive 4 | cd demo 5 | python helper.py 6 | -------------------------------------------------------------------------------- /windows_install.bat: -------------------------------------------------------------------------------- 1 | if not exist "install" mkdir install 2 | Xcopy /E/I demo\sdk install\sdk 3 | copy LICENSE install\sdk 4 | copy CHANGELOG.md install\sdk 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | open-pull-requests-limit: 10 -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | PLATFORM=$(uname -s) 3 | 4 | mkdir -p install 5 | cp -r demo/sdk install 6 | cp ./LICENSE install/sdk 7 | cp ./CHANGELOG.md install/sdk 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = ["./defi-wallet-core-rs"] 3 | resolver = "2" 4 | members = [ 5 | "wallet-connect", 6 | "extra-cpp-bindings", 7 | "play-cpp-sdk", 8 | ] 9 | -------------------------------------------------------------------------------- /wallet-connect/src/v2/mod.rs: -------------------------------------------------------------------------------- 1 | mod client; 2 | mod core; 3 | mod crypto; 4 | mod protocol; 5 | mod session; 6 | 7 | pub use client::*; 8 | pub use protocol::*; 9 | pub use session::*; 10 | -------------------------------------------------------------------------------- /wallet-connect/src/crypto.rs: -------------------------------------------------------------------------------- 1 | /// AES-256-CBC and HMAC-SHA256: https://docs.walletconnect.com/tech-spec#cryptography 2 | mod aead; 3 | /// wrapper around the symmetric key 4 | mod key; 5 | 6 | pub use key::*; 7 | -------------------------------------------------------------------------------- /wallet-connect/src/protocol.rs: -------------------------------------------------------------------------------- 1 | /// the outer wrapper type in WalletConnect: https://docs.walletconnect.com/tech-spec#websocket-messages 2 | mod message; 3 | /// JSON-RPC related definitions 4 | mod rpc; 5 | /// the helpers for the SocketMessage's topic generation 6 | mod topic; 7 | 8 | pub use self::message::*; 9 | pub use self::rpc::*; 10 | pub use self::topic::*; 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "demo/third_party/json"] 2 | path = demo/third_party/json 3 | url = git@github.com:nlohmann/json.git 4 | [submodule "demo/third_party/easywsclient"] 5 | path = demo/third_party/easywsclient 6 | url = git@github.com:dhbaird/easywsclient.git 7 | [submodule "defi-wallet-core-rs"] 8 | path = defi-wallet-core-rs 9 | url = git@github.com:crypto-com/defi-wallet-core-rs.git 10 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "webhook server", 5 | "main": "server.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "start": "node server.js" 12 | }, 13 | "author": "crypto.com", 14 | "license": "ISC", 15 | "dependencies": { 16 | "ws": "^8.6.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /demo/.env: -------------------------------------------------------------------------------- 1 | # !!! Please notice !!! 2 | # This env file is only for testing purpose, please keep your api keys or secrets safe 3 | export CRONOSCAN_API_KEY="" 4 | export PAY_API_KEY="" 5 | export PAY_WEBSOCKET_PORT="4567" 6 | 7 | # !!! The following webhook related setting can only be used in webhook server!!! 8 | # Don't share the secret to the clients 9 | export PAY_WEBHOOK_SIGNATURE_SECRET="" 10 | export PAY_WEBHOOK_PORT="4567" 11 | 12 | source ../defi-wallet-core-rs/scripts/.env 13 | -------------------------------------------------------------------------------- /play-cpp-sdk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "play-cpp-sdk" 3 | version = "0.0.24-alpha" 4 | edition = "2021" 5 | license = "Apache-2.0" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | defi-wallet-core-cpp = { path = "../defi-wallet-core-rs/bindings/cpp/", version = "0.3.1"} 11 | extra-cpp-bindings = { path = "../extra-cpp-bindings/"} 12 | 13 | [lib] 14 | crate-type = ["staticlib", "cdylib"] 15 | -------------------------------------------------------------------------------- /extra-cpp-bindings/src/error.rs: -------------------------------------------------------------------------------- 1 | use super::pay::CryptoPayErrorObject; 2 | 3 | #[derive(Debug, thiserror::Error)] 4 | pub(crate) enum GameSdkError { 5 | #[error(transparent)] 6 | Reqwest(#[from] reqwest::Error), 7 | #[error(transparent)] 8 | Serde(#[from] serde_json::Error), 9 | #[error("Crypto Pay Error: {0:?}")] 10 | CryptoPayError(CryptoPayErrorObject), 11 | #[error(transparent)] 12 | Io(#[from] std::io::Error), 13 | #[error("Invalid wallet id")] 14 | InvalidWalletId, 15 | } 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022, Cronos Labs. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /play-cpp-sdk/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022, Cronos Labs. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /wallet-connect/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022, Cronos Labs. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /extra-cpp-bindings/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022, Cronos Labs. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /wallet-connect/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// the definitions related to WalletConnect 1.0 client implementation 2 | mod client; 3 | /// the cryptography helpers for WalletConnect 1.0 4 | mod crypto; 5 | /// small utilities for hexadecimal operations 6 | mod hex; 7 | /// the WalletConnect 1.0 relevant payload definitions: https://docs.walletconnect.com/tech-spec#events--payloads 8 | mod protocol; 9 | /// helpers for serde 10 | mod serialization; 11 | /// utilities for the connection URI: https://docs.walletconnect.com/tech-spec#requesting-connection 12 | mod uri; 13 | pub mod v2; 14 | pub use client::*; 15 | pub use protocol::*; 16 | -------------------------------------------------------------------------------- /demo/examples/src/get_token_holders.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace com::crypto::game_sdk; 5 | 6 | int main(int argc, char *argv[]) { 7 | rust::Vec token_holders = 8 | get_token_holders("https://blockscout.com/xdai/mainnet/api", 9 | "0xed1efc6efceaab9f6d609fec89c9e675bf1efb0a", 1, 100); 10 | for (const TokenHolderDetail &tx : token_holders) { 11 | std::cout << tx.address << " "; 12 | std::cout << tx.value << " " << std::endl; 13 | } 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /windows_build.bat: -------------------------------------------------------------------------------- 1 | git config --global core.symlinks true 2 | git submodule update --init --recursive 3 | cargo build --package play-cpp-sdk --release 4 | cd demo 5 | msbuild .\demo.sln -t:rebuild -property:Configuration=Release /p:Platform=x64 6 | cmake.exe ^ 7 | -B "out\build\x64-Release" ^ 8 | -G "Ninja" ^ 9 | -DCMAKE_BUILD_TYPE=Release ^ 10 | -DCMAKE_INSTALL_PREFIX:PATH="out\install\x64-Release" ^ 11 | -DCMAKE_C_COMPILER="cl.exe" ^ 12 | -DCMAKE_CXX_COMPILER="cl.exe" ^ 13 | -DCMAKE_MAKE_PROGRAM="ninja.exe" ^ 14 | . 15 | cd out\build\x64-Release 16 | ninja 17 | cd ..\..\..\.. 18 | -------------------------------------------------------------------------------- /demo/examples/src/new_wallet.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace org::defi_wallet_core; 5 | 6 | int main(int argc, char *argv[]) { 7 | rust::Box wallet = new_wallet("", MnemonicWordCount::TwentyFour); 8 | std::cout << wallet->get_default_address(CoinType::CronosMainnet) 9 | << std::endl; 10 | std::cout << wallet->get_address(CoinType::CronosMainnet, 0) << std::endl; 11 | std::cout << wallet->get_eth_address(0) << std::endl; 12 | rust::Box private_key = wallet->get_key("m/44'/60/0'/0/0"); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/clang-format-check.yml: -------------------------------------------------------------------------------- 1 | name: Clang-format Check 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - README.md 9 | tags: 10 | - "v*.*.*" 11 | merge_group: 12 | pull_request: 13 | paths-ignore: 14 | - README.md 15 | 16 | jobs: 17 | formatting-check: 18 | name: Formatting Check 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: c++ format check 23 | uses: jidicula/clang-format-action@v4.9.0 24 | with: 25 | clang-format-version: '13' 26 | check-path: '.' 27 | fallback-style: 'LLVM' # optional -------------------------------------------------------------------------------- /msys_build.sh: -------------------------------------------------------------------------------- 1 | # use rust like this 2 | # pacman -S --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-rust 3 | # msvc rust is not compatible with msys2 4 | 5 | # bring all source 6 | git config --global core.symlinks true 7 | git submodule update --init --recursive 8 | 9 | # fix for msys2 10 | sed -i 's/typedef __int8 int8_t;/\/\/ typedef __int8 int8_t;/' ./demo/third_party/easywsclient/easywsclient.cpp 11 | 12 | # prepare 13 | cargo build --release 14 | 15 | # copy library 16 | cd ./demo 17 | python ./helper.py 18 | cd .. 19 | 20 | # compile 21 | mkdir -p ./demo/build 22 | cd ./demo/build 23 | cmake -G "MSYS Makefiles" .. 24 | make 25 | cd ../.. 26 | echo "OK" 27 | 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /extra-cpp-bindings/build.rs: -------------------------------------------------------------------------------- 1 | use cxx_build::CFG; 2 | 3 | const BRIDGES: &[&str] = &["src/lib.rs"]; 4 | 5 | fn main() { 6 | CFG.doxygen = true; 7 | cxx_build::bridges(BRIDGES) 8 | .file("src/pay.cc") 9 | .flag_if_supported("-std=c++14") 10 | .file("src/walletconnectcallback.cc") 11 | .compile("game_sdk_bindings"); 12 | 13 | for bridge in BRIDGES { 14 | println!("cargo:rerun-if-changed={bridge}"); 15 | } 16 | 17 | println!("cargo:rerun-if-changed=src/pay.cc"); 18 | println!("cargo:rerun-if-changed=include/pay.h"); 19 | println!("cargo:rerun-if-changed=src/walletconnectcallback.cc"); 20 | println!("cargo:rerun-if-changed=include/walletconnectcallback.h"); 21 | } 22 | -------------------------------------------------------------------------------- /demo/examples/src/restore_wallet.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace org::defi_wallet_core; 5 | 6 | int main(int argc, char *argv[]) { 7 | rust::Box wallet = restore_wallet( 8 | "shed crumble dismiss loyal latin million oblige gesture " 9 | "shrug still oxygen custom remove ribbon disorder palace " 10 | "addict again blanket sad flock consider obey popular", 11 | ""); 12 | std::cout << wallet->get_default_address(CoinType::CronosMainnet) 13 | << std::endl; 14 | std::cout << wallet->get_address(CoinType::CronosMainnet, 0) << std::endl; 15 | std::cout << wallet->get_eth_address(0) << std::endl; 16 | rust::Box private_key = wallet->get_key("m/44'/60/0'/0/0"); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /demo/examples/src/get_tokens_blocking.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace com::crypto::game_sdk; 5 | 6 | int main(int argc, char *argv[]) { 7 | // Blockscout examples 8 | rust::Vec tokens_txs = 9 | get_tokens_blocking("https://blockscout.com/xdai/mainnet/api", 10 | "0x652d53227d7013f3FbBeA542443Dc2eeF05719De"); 11 | for (const RawTokenResult &tx : tokens_txs) { 12 | std::cout << tx.balance << " "; 13 | std::cout << tx.contract_address << " "; 14 | std::cout << tx.decimals << " "; 15 | std::cout << tx.id << " "; 16 | std::cout << tx.name << " "; 17 | std::cout << tx.symbol << " "; 18 | std::cout << tx.token_type << std::endl; 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /demo/examples/src/get_token_transfers_blocking.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace com::crypto::game_sdk; 5 | 6 | int main(int argc, char *argv[]) { 7 | rust::Vec token_transfer_txs = get_token_transfers_blocking( 8 | "https://cronos.org/explorer/testnet3/api", 9 | "0x841a15D12aEc9c6039FD132c2FbFF112eD355700", "", 10 | QueryOption::ByAddress); 11 | for (const RawTxDetail &tx : token_transfer_txs) { 12 | std::cout << tx.hash << " "; 13 | std::cout << tx.to_address << " "; 14 | std::cout << tx.from_address << " "; 15 | std::cout << tx.value << " "; 16 | std::cout << tx.block_no << " "; 17 | std::cout << tx.timestamp << " "; 18 | std::cout << tx.contract_address << " " << std::endl; 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /demo/CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64-Debug", 5 | "generator": "Ninja", 6 | "configurationType": "Debug", 7 | "inheritEnvironments": [ "msvc_x64_x64" ], 8 | "buildRoot": "${projectDir}\\out\\build\\${name}", 9 | "installRoot": "${projectDir}\\out\\install\\${name}", 10 | "cmakeCommandArgs": "", 11 | "buildCommandArgs": "", 12 | "ctestCommandArgs": "" 13 | }, 14 | { 15 | "name": "x64-Release", 16 | "generator": "Ninja", 17 | "configurationType": "RelWithDebInfo", 18 | "buildRoot": "${projectDir}\\out\\build\\${name}", 19 | "installRoot": "${projectDir}\\out\\install\\${name}", 20 | "cmakeCommandArgs": "", 21 | "buildCommandArgs": "", 22 | "ctestCommandArgs": "", 23 | "inheritEnvironments": [ "msvc_x64_x64" ] 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security Audit 2 | on: 3 | pull_request: 4 | paths: 5 | - Cargo.lock 6 | merge_group: 7 | push: 8 | branches: 9 | - main 10 | paths: 11 | - Cargo.lock 12 | schedule: 13 | - cron: '0 0 * * *' 14 | 15 | jobs: 16 | security_audit: 17 | name: Security Audit 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | with: 22 | submodules: recursive 23 | - uses: dtolnay/rust-toolchain@stable 24 | - name: Install cargo audit 25 | run: cargo install cargo-audit 26 | # RUSTSEC-2021-0145: `atty` transitive dependency, only informational for Windows (not exploitable in practice) 27 | # RUSTSEC-2023-0033: fixed until https://github.com/near/borsh-rs/issues/19 28 | - run: cargo audit --deny warnings --ignore RUSTSEC-2021-0145 --ignore RUSTSEC-2023-0033 29 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Cronos Play C++ SDK 2 | Copyright 2022, Cronos Labs. 3 | 4 | This project contains portions of code derived from the following libraries: 5 | 6 | * WalletConnect Rust Client 7 | * Copyright: Copyright (c) 2020 Nicholas Rodrigues Lordello 8 | * License: Apache License 2.0 9 | * Repository: https://github.com/nlordell/walletconnect-rs 10 | 11 | * cross-websocket 12 | * Copyright: Copyright (c) 2021 HIHAHEHO Studio 13 | * License: Apache License 2.0 14 | * Repository: https://github.com/Hihaheho/Desk/tree/main/crates/libs/cross-websocket 15 | 16 | The sample demo code bundles the following libraries: 17 | 18 | * JSON for Modern C++ 19 | * Copyright: Copyright (c) 2013-2022 Niels Lohmann 20 | * License: MIT 21 | * Repository: https://github.com/nlohmann/json 22 | 23 | * easywsclient 24 | * Copyright: Copyright (c) 2012, 2013 David Baird 25 | * License: MIT 26 | * Repository: https://github.com/dhbaird/easywsclient 27 | -------------------------------------------------------------------------------- /.github/workflows/android-build.yml: -------------------------------------------------------------------------------- 1 | name: Android Build CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - README.md 9 | tags: 10 | - "v*.*.*" 11 | merge_group: 12 | pull_request: 13 | paths-ignore: 14 | - README.md 15 | jobs: 16 | build-android: 17 | runs-on: macos-11 18 | strategy: 19 | matrix: 20 | # 21.4.7075529 is needed for Unreal Engine 4.26 21 | ndk_version: [25.1.8937393, 23.0.7599858] 22 | # TODO: is x86_64-linux-android necessary to test on CI? 23 | target: [armv7-linux-androideabi, aarch64-linux-android, x86_64-linux-android] 24 | steps: 25 | - uses: actions/checkout@v3 26 | with: 27 | submodules: recursive 28 | - uses: dtolnay/rust-toolchain@stable 29 | - uses: ./.github/actions/android 30 | with: 31 | ndk_version: ${{ matrix.ndk_version }} 32 | target: ${{ matrix.target }} 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. -------------------------------------------------------------------------------- /demo/examples/src/uint.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace org::defi_wallet_core; 5 | 6 | int main(int argc, char *argv[]) { 7 | assert(u256("15") == u256("15", 10)); 8 | assert(u256("15") == u256("0xf", 16)); 9 | assert(u256("1000") == u256("100").add(u256("900"))); 10 | assert(u256("999999999999999999999999300") == 11 | u256("1000000000000000000000000000").sub(u256("700"))); 12 | assert(u256("199999999999999999980000200") == 13 | u256("99999999999999999990000100").mul(u256("2"))); 14 | assert(u256("1999999999999999999800002") == 15 | u256("199999999999999999980000200").div(u256("100"))); 16 | assert(u256("800002") == 17 | u256("1999999999999999999800002").rem(u256("1000000"))); 18 | assert(u256("512003840009600008") == u256("800002").pow(u256("3"))); 19 | assert(u256("512003840009600008").neg() == 20 | u256_max_value().sub(u256("512003840009600007"))); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /extra-cpp-bindings/src/pay.cc: -------------------------------------------------------------------------------- 1 | #include "extra-cpp-bindings/include/pay.h" 2 | #include "extra-cpp-bindings/src/lib.rs.h" 3 | 4 | #include 5 | #include 6 | 7 | namespace com { 8 | namespace crypto { 9 | namespace game_sdk { 10 | 11 | OptionalArguments::OptionalArguments() : onchain_allowed{true}, expired_at{0} {} 12 | 13 | rust::Str OptionalArguments::get_description() const { return description; } 14 | rust::Str OptionalArguments::get_metadata() const { return metadata; } 15 | rust::Str OptionalArguments::get_order_id() const { return order_id; } 16 | rust::Str OptionalArguments::get_return_url() const { return return_url; } 17 | rust::Str OptionalArguments::get_cancel_url() const { return cancel_url; } 18 | rust::Str OptionalArguments::get_sub_merchant_id() const { 19 | return sub_merchant_id; 20 | } 21 | bool OptionalArguments::get_onchain_allowed() const { return onchain_allowed; } 22 | uint64_t OptionalArguments::get_expired_at() const { return expired_at; } 23 | 24 | } // namespace game_sdk 25 | } // namespace crypto 26 | } // namespace com 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | .vscode/ 9 | 10 | # MSVC Windows builds of rustc generate these, which store debugging information 11 | *.pdb 12 | *.swp 13 | demo/demo/demo.vcxproj.user 14 | demo/demo/x64/ 15 | demo/out/ 16 | demo/demostatic/x64/ 17 | demo/.vs 18 | demo/bin/ 19 | demo/*.h 20 | demo/*.cc 21 | demo/*.txt 22 | demo/include/ 23 | demo/lib 24 | demo/build/ 25 | demo/sdk/ 26 | demo/cppexample 27 | demo/cppexamplestatic 28 | demo/sessioninfo.json 29 | wallet-connect/sessioninfo.json 30 | demo/easywsclient.o 31 | 32 | docs 33 | demo/bin/ 34 | demo/build/ 35 | demo/chainmain.cc 36 | demo/chainmain.h 37 | demo/cronos.cc 38 | demo/cronos.h 39 | demo/sdk 40 | 41 | install 42 | 43 | wallet-connect/qrcode.png 44 | 45 | wallet-connect/session.bin 46 | 47 | defi-wallet-core-rs 48 | 49 | demo/third_party/easywsclient 50 | 51 | demo/third_party/json 52 | 53 | wallet-connect/yarn.lock 54 | 55 | wallet-connect/node_modules/ 56 | 57 | .DS_Store 58 | 59 | sessioninfo2.json 60 | -------------------------------------------------------------------------------- /wallet-connect/src/hex.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use ethers::utils::{hex, hex::FromHexError}; 4 | 5 | /// encode the data as a hexadecimal string (lowercase) 6 | pub fn encode(data: impl AsRef<[u8]>) -> String { 7 | hex::encode(data.as_ref()) 8 | } 9 | 10 | /// decode a hexadecimal string into a provided buffer 11 | pub fn decode_mut( 12 | bytes: impl AsRef<[u8]>, 13 | mut buffer: impl AsMut<[u8]>, 14 | ) -> Result<(), FromHexError> { 15 | hex::decode_to_slice(bytes.as_ref(), buffer.as_mut()) 16 | } 17 | 18 | /// decode a hexadecimal string into a new byte vector 19 | pub fn decode(bytes: impl AsRef<[u8]>) -> Result, FromHexError> { 20 | hex::decode(bytes.as_ref()) 21 | } 22 | 23 | #[cfg(test)] 24 | mod test { 25 | use super::*; 26 | #[test] 27 | fn test_hex_encode() { 28 | let hex = format!("0x{}", hex::encode("Hello World")); 29 | assert_eq!(hex, "0x48656c6c6f20576f726c64"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /demo/main.cc: -------------------------------------------------------------------------------- 1 | #include "chainmain.h" 2 | #include "cronos.h" 3 | #include "extra.h" 4 | #include "sdk/include/defi-wallet-core-cpp/src/lib.rs.h" 5 | #include "sdk/include/defi-wallet-core-cpp/src/nft.rs.h" 6 | #include "sdk/include/extra-cpp-bindings/src/lib.rs.h" 7 | #include "sdk/include/rust/cxx.h" 8 | #include "third_party/easywsclient/easywsclient.hpp" 9 | #include "third_party/json/single_include/nlohmann/json.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int main(int argc, char *argv[]) { 20 | try { 21 | chainmain_process(); // chain-main 22 | test_chainmain_nft(); // chainmain nft tests 23 | test_login(); // decentralized login 24 | cronos_process(); // cronos 25 | test_cronos_testnet(); // cronos testnet 26 | test_interval(); 27 | test_blackscout_cronoscan(); 28 | test_wallet_connect(); 29 | } catch (const std::exception &e) { 30 | // Use `Assertion failed`, the same as `assert` function 31 | std::cout << "Assertion failed: " << e.what() << std::endl; 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | name: Semgrep 2 | on: 3 | # Scan changed files in PRs, block on new issues only (existing issues ignored) 4 | pull_request: {} 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - .github/workflows/semgrep.yml 10 | merge_group: 11 | schedule: 12 | - cron: '0 0 * * 0' 13 | jobs: 14 | # Update from: https://semgrep.dev/docs/semgrep-ci/sample-ci-configs/#github-actions 15 | semgrep: 16 | name: Scan 17 | runs-on: ubuntu-latest 18 | container: 19 | image: returntocorp/semgrep 20 | if: (github.actor != 'dependabot[bot]') 21 | steps: 22 | # Fetch project source with GitHub Actions Checkout. 23 | - uses: actions/checkout@v3 24 | with: 25 | submodules: true 26 | # Run the "semgrep ci" command on the command line of the docker image. 27 | - run: semgrep ci 28 | env: 29 | # Add the rules that Semgrep uses by setting the SEMGREP_RULES environment variable. 30 | SEMGREP_RULES: p/c # more at semgrep.dev/explore 31 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} 32 | # Uncomment SEMGREP_TIMEOUT to set this job's timeout (in seconds): 33 | # Default timeout is 1800 seconds (30 minutes). 34 | # Set to 0 to disable the timeout. 35 | # SEMGREP_TIMEOUT: 300 36 | -------------------------------------------------------------------------------- /extra-cpp-bindings/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "extra-cpp-bindings" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "Apache-2.0" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | [lib] 9 | crate-type = ["staticlib", "rlib", "cdylib"] 10 | 11 | [dependencies] 12 | anyhow = "1" 13 | cxx = "1" 14 | ethers = { version = "2.0", features = ["rustls"] } 15 | ethers-addressbook = { version = "2.0"} 16 | ethers-contract = { version = "2.0" } 17 | ethers-core = { version = "2.0" } 18 | ethers-etherscan = { version = "2.0" } 19 | ethers-middleware = { version = "2.0" } 20 | ethers-providers = { version = "2.0"} 21 | ethers-signers = { version = "2.0" } 22 | ethers-solc = { version = "2.0"} 23 | 24 | eyre = "0.6" 25 | reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] } 26 | serde = "1" 27 | serde_json = { version = "1", features = ["arbitrary_precision"] } 28 | thiserror = "1" 29 | tokio = { version = "1", features = ["rt-multi-thread"] } 30 | defi-wallet-connect= { path="../wallet-connect" } 31 | url = { version = "2", features = ["serde"] } 32 | hex="0.4.3" 33 | qrcodegen= "1.8" 34 | defi-wallet-core-cpp= { path="../defi-wallet-core-rs/bindings/cpp"} 35 | defi-wallet-core-common= { path="../defi-wallet-core-rs/common"} 36 | 37 | [build-dependencies] 38 | cxx-build = "1" 39 | 40 | 41 | [dev-dependencies] 42 | sha2 = "0.10" 43 | hex-literal="0.3" 44 | uuid = "1" 45 | -------------------------------------------------------------------------------- /wallet-connect/README.md: -------------------------------------------------------------------------------- 1 | # wallet-connect 2 | This crate contains the WalletConnect 1.0 client implementation the could be used by dApps in integrations. 3 | 4 | ## WalletConnect 1.0 5 | For protocol details, see the technical specification: https://docs.walletconnect.com/tech-spec 6 | 7 | ## Usage 8 | See "examples/web3.rs". The WalletConnect client implements the [ethers middleware](https://docs.rs/ethers/latest/ethers/providers/struct.Provider.html), 9 | so one can call the Web3 JSON-RPC API methods: https://docs.walletconnect.com/json-rpc-api-methods/ethereum 10 | after the client is linked with the external wallet. 11 | 12 | You can use https://test.walletconnect.org/ for testing (not for production). 13 | 14 | ## Implementation 15 | The implementation code is largely based off the unfinished WalletConnect Rust Client: https://github.com/nlordell/walletconnect-rs 16 | The following major changes were made: 17 | - The websocket implementation (originally `ws`) was replaced with `tokio-tungstenite` for better portability and compatibility with the async ecosystem. 18 | - The cryptographic implementation (originally using `openssl`) was replaced with the [RustCrypto](https://github.com/RustCrypto) implementations in pure Rust 19 | (given they are used elsewhere in the codebase as well as in major dependencies). 20 | - The Ethereum transport implementation (originally using `web3`) was replaced with the `ethers` which is used elsewhere in the codebase. The extensibility of `ethers` allowed more Web3 methods to be reused. -------------------------------------------------------------------------------- /.github/workflows/ios-build.yml: -------------------------------------------------------------------------------- 1 | name: IOS Build CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - README.md 9 | tags: 10 | - "v*.*.*" 11 | merge_group: 12 | pull_request: 13 | paths-ignore: 14 | - README.md 15 | jobs: 16 | build-ios: 17 | runs-on: macos-11 18 | steps: 19 | - uses: actions/checkout@v3 20 | with: 21 | submodules: recursive 22 | - name: Build play-cpp-sdk library 23 | shell: bash 24 | run: make aarch64-apple-ios 25 | - name: Pack binaries and bindings 26 | shell: bash 27 | run: | 28 | PLATFORM="aarch64-apple-ios" 29 | BUILD_TYPE="tarball" 30 | mkdir -p install 31 | cp -r demo/sdk install 32 | cp ./LICENSE install/sdk 33 | cp ./CHANGELOG.md install/sdk 34 | cd install 35 | tar zcvf ../play_cpp_sdk_${PLATFORM}.tar.gz * 36 | cd .. 37 | shasum -a 256 *.tar.gz > "checksums-$PLATFORM.txt" 38 | echo "release_file=play_cpp_sdk_$PLATFORM.tar.gz" >> $GITHUB_ENV 39 | echo "checksum_file=checksums-$PLATFORM.txt" >> $GITHUB_ENV 40 | cat $GITHUB_ENV 41 | - name: Upload binaries and bindings to Release 42 | uses: softprops/action-gh-release@v1 43 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') 44 | with: 45 | draft: true 46 | files: | 47 | ${{ env.release_file }} 48 | ${{ env.checksum_file }} 49 | -------------------------------------------------------------------------------- /.github/workflows/mac-build.yml: -------------------------------------------------------------------------------- 1 | name: Mac Build CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - README.md 9 | tags: 10 | - "v*.*.*" 11 | merge_group: 12 | pull_request: 13 | paths-ignore: 14 | - README.md 15 | 16 | jobs: 17 | mac-build: 18 | runs-on: macos-11 19 | env: 20 | MACOSX_DEPLOYMENT_TARGET: 10.15 21 | steps: 22 | - uses: actions/checkout@v3 23 | with: 24 | submodules: recursive 25 | - name: Build play-cpp-sdk library 26 | run: make 27 | - name: Pack binaries and bindings 28 | run: | 29 | PLATFORM="$(uname -s)_x86_64" 30 | BUILD_TYPE="tarball" 31 | mkdir -p install 32 | cp -r demo/sdk install 33 | cp ./LICENSE install/sdk 34 | cp ./CHANGELOG.md install/sdk 35 | cd install 36 | tar zcvf ../play_cpp_sdk_${PLATFORM}.tar.gz * 37 | cd .. 38 | shasum -a 256 *.tar.gz > "checksums-$PLATFORM.txt" 39 | echo "release_file=play_cpp_sdk_$PLATFORM.tar.gz" >> $GITHUB_ENV 40 | echo "checksum_file=checksums-$PLATFORM.txt" >> $GITHUB_ENV 41 | cat $GITHUB_ENV 42 | - name: Upload binaries and bindings to Release 43 | uses: softprops/action-gh-release@v1 44 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') 45 | with: 46 | draft: true 47 | files: | 48 | ${{ env.release_file }} 49 | ${{ env.checksum_file }} 50 | -------------------------------------------------------------------------------- /.github/workflows/macarm64-build.yml: -------------------------------------------------------------------------------- 1 | name: Mac Arm64 Build CI 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - main 7 | paths-ignore: 8 | - README.md 9 | tags: 10 | - "v*.*.*" 11 | merge_group: 12 | pull_request: 13 | paths-ignore: 14 | - README.md 15 | 16 | jobs: 17 | mac-build: 18 | runs-on: macos-12 19 | env: 20 | MACOSX_DEPLOYMENT_TARGET: 10.15 21 | USE_ARM64: true 22 | steps: 23 | - uses: actions/checkout@v3 24 | with: 25 | submodules: recursive 26 | - name: Build play-cpp-sdk library 27 | run: make 28 | - name: Pack binaries and bindings 29 | run: | 30 | PLATFORM="$(uname -s)_arm64" 31 | BUILD_TYPE="tarball" 32 | mkdir -p install 33 | cp -r demo/sdk install 34 | cp ./LICENSE install/sdk 35 | cp ./CHANGELOG.md install/sdk 36 | cd install 37 | tar zcvf ../play_cpp_sdk_${PLATFORM}.tar.gz * 38 | cd .. 39 | shasum -a 256 *.tar.gz > "checksums-$PLATFORM.txt" 40 | echo "release_file=play_cpp_sdk_$PLATFORM.tar.gz" >> $GITHUB_ENV 41 | echo "checksum_file=checksums-$PLATFORM.txt" >> $GITHUB_ENV 42 | cat $GITHUB_ENV 43 | - name: Upload binaries and bindings to Release 44 | uses: softprops/action-gh-release@v1 45 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') 46 | with: 47 | draft: true 48 | files: | 49 | ${{ env.release_file }} 50 | ${{ env.checksum_file }} -------------------------------------------------------------------------------- /extra-cpp-bindings/src/walletconnectcallback.cc: -------------------------------------------------------------------------------- 1 | #include "extra-cpp-bindings/include/walletconnectcallback.h" 2 | #include "extra-cpp-bindings/src/lib.rs.h" 3 | #include 4 | #include 5 | 6 | namespace com { 7 | namespace crypto { 8 | namespace game_sdk { 9 | 10 | std::unique_ptr new_walletconnect_sessioninfo() { 11 | return std::make_unique(); 12 | } 13 | 14 | void WalletConnectSessionInfo::set_connected(bool myconnected) { 15 | connected = myconnected; 16 | } 17 | 18 | void WalletConnectSessionInfo::set_chainid(rust::String mychainid) { 19 | chain_id = mychainid; 20 | } 21 | 22 | void WalletConnectSessionInfo::set_accounts( 23 | rust::Vec myaccounts) { 24 | accounts = myaccounts; 25 | } 26 | 27 | void WalletConnectSessionInfo::set_bridge(rust::String mybridge) { 28 | bridge = mybridge; 29 | } 30 | 31 | void WalletConnectSessionInfo::set_key(rust::String mykey) { key = mykey; } 32 | 33 | void WalletConnectSessionInfo::set_clientid(rust::String myclient_id) { 34 | client_id = myclient_id; 35 | } 36 | 37 | void WalletConnectSessionInfo::set_clientmeta(rust::String myclient_meta) { 38 | client_meta = myclient_meta; 39 | } 40 | 41 | void WalletConnectSessionInfo::set_peerid(rust::String mypeer_id) { 42 | peer_id = mypeer_id; 43 | } 44 | 45 | void WalletConnectSessionInfo::set_peermeta(rust::String mypeer_meta) { 46 | peer_meta = mypeer_meta; 47 | } 48 | 49 | void WalletConnectSessionInfo::set_handshaketopic( 50 | rust::String myhandshake_topic) { 51 | handshake_topic = myhandshake_topic; 52 | } 53 | 54 | } // namespace game_sdk 55 | } // namespace crypto 56 | } // namespace com 57 | -------------------------------------------------------------------------------- /.github/workflows/linux-libstdc++-build.yml: -------------------------------------------------------------------------------- 1 | name: Linux (libstdc++) Build CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths-ignore: 7 | - README.md 8 | tags: 9 | - "v*.*.*" 10 | merge_group: 11 | pull_request: 12 | paths-ignore: 13 | - README.md 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | with: 21 | submodules: recursive 22 | 23 | - name: Build play-cpp-sdk library 24 | run: cargo build --package play-cpp-sdk --release 25 | 26 | - name: Build demo project 27 | working-directory: demo 28 | run: make CXX=g++ 29 | 30 | - name: Pack binaries and bindings 31 | run: | 32 | PLATFORM="$(uname -s)_x86_64" 33 | BUILD_TYPE="tarball" 34 | mkdir -p install 35 | cp -r demo/sdk install 36 | cp ./LICENSE install/sdk 37 | cp ./CHANGELOG.md install/sdk 38 | cd install 39 | tar zcvf ../play_cpp_sdk_libstdc++_${PLATFORM}.tar.gz * 40 | cd .. 41 | sha256sum *.tar.gz > "checksums-libstdc++_$PLATFORM.txt" 42 | echo "release_file=play_cpp_sdk_libstdc++_$PLATFORM.tar.gz" >> $GITHUB_ENV 43 | echo "checksum_file=checksums-libstdc++_$PLATFORM.txt" >> $GITHUB_ENV 44 | cat $GITHUB_ENV 45 | 46 | - name: Upload binaries and bindings to Release 47 | uses: softprops/action-gh-release@v1 48 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') 49 | with: 50 | draft: true 51 | files: | 52 | ${{ env.release_file }} 53 | ${{ env.checksum_file }} 54 | -------------------------------------------------------------------------------- /wallet-connect/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "defi-wallet-connect" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "Apache-2.0" 6 | 7 | [dependencies] 8 | aes = "0.8" 9 | anyhow = "1" 10 | bincode= "1" 11 | async-trait = { version = "0.1", default-features = false } 12 | base64 = "0.21" 13 | chacha20poly1305 = "0.10" 14 | cbc = { version = "0.1", features = ["alloc"] } 15 | dashmap = "5" 16 | ethers = { version = "2", features = ["rustls"] } 17 | eyre = "0.6" 18 | futures = "0.3" 19 | hkdf = "0.12" 20 | hmac = "0.12" 21 | open = "4" 22 | qrcodegen = "1" 23 | rand = "0.8" 24 | relay_client = { git = "https://github.com/leejw51crypto/WalletConnectRust", branch = "0.10.0", default-features = false, features = ["rustls"]} 25 | relay_rpc = { git = "https://github.com/leejw51crypto/WalletConnectRust", branch = "0.10.0"} 26 | secrecy = "0.8" 27 | serde = "1" 28 | serde_json = "1" 29 | serde_with = "2" 30 | sha2 = "0.10" 31 | subtle = "2" 32 | thiserror = "1" 33 | url = { version = "2", features = ["serde"] } 34 | x25519-dalek = "1" 35 | zeroize = "1" 36 | hex = "0.4" 37 | qrcode = "0.12" 38 | image = "0.23" 39 | 40 | [dev-dependencies] 41 | quickcheck = "1" 42 | quickcheck_macros = "1" 43 | 44 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 45 | tokio-tungstenite = { version = "0.20.1", features = ["rustls-tls-webpki-roots"] } 46 | tokio = { version = "1", features = ["rt", "macros"] } 47 | uuid = { version = "1.3", features = ["serde", "v4"] } 48 | 49 | [target.'cfg(target_arch = "wasm32")'.dependencies] 50 | uuid = { version = "1.3", features = ["serde", "v4", "wasm-bindgen"] } 51 | ws_stream_wasm = { version = "0.7" } 52 | 53 | [[example]] 54 | name = "web3" 55 | 56 | [[example]] 57 | name = "web3_v2" 58 | -------------------------------------------------------------------------------- /.github/workflows/linux-libc++-build.yml: -------------------------------------------------------------------------------- 1 | name: Linux (libc++) Build CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths-ignore: 7 | - README.md 8 | tags: 9 | - "v*.*.*" 10 | merge_group: 11 | pull_request: 12 | paths-ignore: 13 | - README.md 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-20.04 18 | steps: 19 | - uses: actions/checkout@v3 20 | with: 21 | submodules: recursive 22 | 23 | - name: Build play-cpp-sdk library 24 | run: CXX=clang++-10 CXXFLAGS="-std=c++14 -stdlib=libc++" cargo build --package play-cpp-sdk --release 25 | 26 | - name: Build demo project 27 | working-directory: demo 28 | run: make CXX=clang++-10 29 | - name: Pack binaries and bindings 30 | run: | 31 | PLATFORM="$(uname -s)_x86_64" 32 | BUILD_TYPE="tarball" 33 | mkdir -p install 34 | cp -r demo/sdk install 35 | cp ./LICENSE install/sdk 36 | cp ./CHANGELOG.md install/sdk 37 | cd install 38 | tar zcvf ../play_cpp_sdk_libc++_${PLATFORM}.tar.gz * 39 | cd .. 40 | sha256sum *.tar.gz > "checksums-libc++_$PLATFORM.txt" 41 | echo "release_file=play_cpp_sdk_libc++_$PLATFORM.tar.gz" >> $GITHUB_ENV 42 | echo "checksum_file=checksums-libc++_$PLATFORM.txt" >> $GITHUB_ENV 43 | cat $GITHUB_ENV 44 | 45 | - name: Upload binaries and bindings to Release 46 | uses: softprops/action-gh-release@v1 47 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') 48 | with: 49 | draft: true 50 | files: | 51 | ${{ env.release_file }} 52 | ${{ env.checksum_file }} 53 | -------------------------------------------------------------------------------- /demo/examples/src/eth_login.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace org::defi_wallet_core; 6 | 7 | int main(int argc, char *argv[]) { 8 | // no \n in end of string 9 | std::string info = 10 | "service.org wants you to sign in with your Ethereum account:\n" 11 | "0xD09F7C8C4529CB5D387AA17E33D707C529A6F694\n" 12 | "\n" 13 | "I accept the ServiceOrg Terms of Service: https://service.org/tos\n" 14 | "\n" 15 | "URI: https://service.org/login\n" 16 | "Version: 1\n" 17 | "Chain ID: 1\n" 18 | "Nonce: 32891756\n" 19 | "Issued At: 2021-09-30T16:25:24Z\n" 20 | "Resources:\n" 21 | "- " 22 | "ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/\n" 23 | "- https://example.com/my-web2-claim.json"; 24 | rust::Box logininfo = new_logininfo(info); 25 | 26 | rust::Box signer1_wallet = restore_wallet( 27 | "shed crumble dismiss loyal latin million oblige gesture " 28 | "shrug still oxygen custom remove ribbon disorder palace " 29 | "addict again blanket sad flock consider obey popular", 30 | ""); 31 | rust::Box signer1_privatekey = 32 | signer1_wallet->get_key("m/44'/60'/0'/0/0"); 33 | 34 | rust::String default_address = 35 | signer1_wallet->get_default_address(CoinType::CronosMainnet); 36 | rust::Vec signature = 37 | logininfo->sign_logininfo(*signer1_privatekey); 38 | assert(signature.size() == 65); 39 | rust::Slice slice{signature.data(), signature.size()}; 40 | logininfo->verify_logininfo(slice); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 👮🏻👮🏻👮🏻 !!!! REFERENCE THE PROBLEM YOUR ARE SOLVING IN THE PR TITLE AND DESCRIBE YOUR SOLUTION HERE !!!! DO NOT FORGET !!!! 👮🏻👮🏻👮🏻 2 | 3 | 4 | # PR Checklist: 5 | 6 | - [ ] Have you read the [CONTRIBUTING.md](https://github.com/crypto-com/play-cpp-sdk/blob/main/CONTRIBUTING.md)? 7 | - [ ] Does your PR follow the [C4 patch requirements](https://rfc.zeromq.org/spec:42/C4/#23-patch-requirements)? 8 | - [ ] Have you rebased your work on top of the latest main? 9 | - [ ] Have you checked your code compiles? (`cargo build`) 10 | - [ ] Have you included tests for any non-trivial functionality? 11 | - [ ] Have you checked your code passes the unit tests? (`cargo test`) 12 | - [ ] Have you checked your code formatting is correct? (`cargo fmt -- --check --color=auto`) 13 | - [ ] Have you checked your basic code style is fine? (`cargo clippy`) 14 | - [ ] If you added any dependencies, have you checked they do not contain any known vulnerabilities? (`cargo audit`) 15 | - [ ] If your changes affect public APIs, does your PR follow the [C4 evolution of public contracts](https://rfc.zeromq.org/spec:42/C4/#26-evolution-of-public-contracts)? 16 | - [ ] If your code changes public APIs, have you incremented the crate version numbers and documented your changes in the [CHANGELOG.md](https://github.com/crypto-com/play-cpp-sdk/blob/main/CHANGELOG.md)? 17 | - [ ] If you are contributing for the first time, please read the agreement in [CONTRIBUTING.md](https://github.com/crypto-com/play-cpp-sdk/blob/main/CONTRIBUTING.md) now and add a comment to this pull request stating that your PR is in accordance with the [Developer's Certificate of Origin](https://github.com/crypto-com/play-cpp-sdk/blob/main/CONTRIBUTING.md#developer-certificate-of-origin). 18 | 19 | Thank you for your code, it's appreciated! :) 20 | -------------------------------------------------------------------------------- /.github/actions/android/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Android Build CI' 2 | description: 'Build play-cpp-sdk for android' 3 | inputs: 4 | ndk_version: 5 | description: 'Set this to your ndk version' 6 | required: true 7 | default: 21.4.7075529 8 | target: 9 | description: 'Set this to your target' 10 | required: true 11 | default: aarch64-linux-android 12 | runs: 13 | using: "composite" 14 | steps: 15 | - name: Install Android NDK 16 | shell: bash 17 | env: 18 | NDK_VERSION: ${{ inputs.ndk_version }} 19 | run: | 20 | ANDROID_HOME=$HOME/Library/Android/sdk 21 | SDKMANAGER=$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager 22 | echo y | $SDKMANAGER "ndk;$NDK_VERSION" 23 | - name: Build play-cpp-sdk library 24 | shell: bash 25 | env: 26 | TARGET: ${{ inputs.target }} 27 | NDK_VERSION: ${{ inputs.ndk_version }} 28 | run: make ${{ inputs.target }} 29 | - name: Pack binaries and bindings 30 | shell: bash 31 | run: | 32 | PLATFORM="${{ inputs.target }}-${{ inputs.ndk_version }}" 33 | BUILD_TYPE="tarball" 34 | mkdir -p install 35 | cp -r demo/sdk install 36 | cp ./LICENSE install/sdk 37 | cp ./CHANGELOG.md install/sdk 38 | cd install 39 | tar zcvf ../play_cpp_sdk_${PLATFORM}.tar.gz * 40 | cd .. 41 | shasum -a 256 *.tar.gz > "checksums-$PLATFORM.txt" 42 | echo "release_file=play_cpp_sdk_$PLATFORM.tar.gz" >> $GITHUB_ENV 43 | echo "checksum_file=checksums-$PLATFORM.txt" >> $GITHUB_ENV 44 | cat $GITHUB_ENV 45 | - name: Upload binaries and bindings to Release 46 | uses: softprops/action-gh-release@v1 47 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') 48 | with: 49 | draft: true 50 | files: | 51 | ${{ env.release_file }} 52 | ${{ env.checksum_file }} 53 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: integration tests 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - release/** 7 | paths-ignore: 8 | - README.md 9 | tags: 10 | - "*" 11 | merge_group: 12 | pull_request: 13 | paths-ignore: 14 | - README.md 15 | 16 | jobs: 17 | integration_tests: 18 | runs-on: ubuntu-20.04 19 | env: 20 | WASM_BINDGEN_TEST_TIMEOUT: 60 21 | steps: 22 | - uses: actions/checkout@v3 23 | with: 24 | submodules: recursive 25 | - uses: cachix/install-nix-action@v19 26 | with: 27 | # pin to nix-2.13 to workaround compability issue of 2.14, 28 | # see: https://github.com/cachix/install-nix-action/issues/161 29 | install_url: https://releases.nixos.org/nix/nix-2.13.3/install 30 | - uses: cachix/cachix-action@v10 31 | with: 32 | name: cronos 33 | extraPullNames: dapp 34 | # github don't pass secrets for pull request from fork repos, 35 | # in that case the push is disabled naturally. 36 | signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}" 37 | - name: 'Tar debug files' 38 | if: failure() 39 | run: tar cfz debug_files.tar.gz -C /tmp/pytest-of-runner . 40 | - uses: actions/upload-artifact@v2 41 | if: failure() 42 | with: 43 | name: debug-files 44 | path: debug_files.tar.gz 45 | if-no-files-found: ignore 46 | 47 | - name: Build play-cpp-sdk library 48 | run: CXX=clang++-10 CXXFLAGS=-stdlib=libc++ cargo build --package play-cpp-sdk --release 49 | 50 | - name: Build demo project 51 | working-directory: demo 52 | run: make CXX=clang++-10 53 | 54 | - name: Run cpp tests 55 | env: 56 | CRONOSCAN_API_KEY: ${{ secrets.CRONOSCAN_API_KEY }} 57 | PAY_API_KEY: ${{ secrets.PAY_API_KEY }} 58 | PAY_WEBSOCKET_PORT: "4567" 59 | run: ./integration_test.sh 60 | -------------------------------------------------------------------------------- /extra-cpp-bindings/include/pay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "rust/cxx.h" 3 | #include 4 | #include 5 | 6 | namespace com { 7 | namespace crypto { 8 | namespace game_sdk { 9 | 10 | /// optional arguments for creating a payment on Crypto.com Pay 11 | struct OptionalArguments { 12 | /// An arbitrary string attached to the object. 13 | rust::String description; 14 | /// Set of key-value pairs that you can attach to an object. This can be 15 | /// useful for storing additional information about the object in a 16 | /// structured format. 17 | rust::String metadata; 18 | /// Merchant provided order ID for this payment. 19 | rust::String order_id; 20 | /// The URL for payment page to redirect back to when the payment becomes 21 | /// succeeded. It is required for redirection flow. 22 | rust::String return_url; 23 | /// The URL for payment page to redirect to when the payment is failed or 24 | /// cancelled. 25 | rust::String cancel_url; 26 | /// ID of the sub-merchant associated with this payment. It is required for 27 | /// merchant acquirers. 28 | rust::String sub_merchant_id; 29 | /// Whether to allow the customer to pay by Other Cryptocurrency Wallets for 30 | /// this payment. If not specified, the setting in merchant account will be 31 | /// used. 32 | bool onchain_allowed; 33 | /// Time at which the payment expires. Measured in seconds since the Unix 34 | /// epoch. If 0, it will expire after the default period(10 minutes). 35 | uint64_t expired_at; 36 | 37 | OptionalArguments(); 38 | rust::Str get_description() const; 39 | rust::Str get_metadata() const; 40 | rust::Str get_order_id() const; 41 | rust::Str get_return_url() const; 42 | rust::Str get_cancel_url() const; 43 | rust::Str get_sub_merchant_id() const; 44 | bool get_onchain_allowed() const; 45 | uint64_t get_expired_at() const; 46 | }; 47 | 48 | } // namespace game_sdk 49 | } // namespace crypto 50 | } // namespace com 51 | -------------------------------------------------------------------------------- /wallet-connect/src/protocol/topic.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use serde::{Deserialize, Serialize}; 4 | use std::fmt::{self, Display, Formatter}; 5 | use std::str::FromStr; 6 | use uuid::{self, Uuid}; 7 | 8 | /// The topic to identify peers or handshakes in socket messages 9 | #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 10 | #[serde(transparent)] 11 | pub struct Topic(String); 12 | 13 | impl Topic { 14 | /// generate a new random topic 15 | pub fn new() -> Self { 16 | Topic(Uuid::new_v4().to_string()) 17 | } 18 | 19 | /// generate a topic with all zeroes 20 | pub fn zero() -> Self { 21 | Topic(Uuid::nil().to_string()) 22 | } 23 | } 24 | 25 | impl Default for Topic { 26 | fn default() -> Self { 27 | Topic::zero() 28 | } 29 | } 30 | 31 | impl Display for Topic { 32 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 33 | self.0.fmt(f) 34 | } 35 | } 36 | 37 | impl FromStr for Topic { 38 | type Err = uuid::Error; 39 | 40 | fn from_str(s: &str) -> Result { 41 | Uuid::from_str(s)?; 42 | Ok(Topic(s.into())) 43 | } 44 | } 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | use super::*; 49 | use serde_json::json; 50 | 51 | #[test] 52 | fn new_topic_is_random() { 53 | assert_ne!(Topic::new(), Topic::new()); 54 | } 55 | 56 | #[test] 57 | fn zero_topic() { 58 | assert_eq!( 59 | json!(Topic::zero()), 60 | json!("00000000-0000-0000-0000-000000000000") 61 | ); 62 | } 63 | 64 | #[test] 65 | fn topic_serialization() { 66 | let topic = Topic::new(); 67 | let serialized = serde_json::to_string(&topic).unwrap(); 68 | let deserialized = serde_json::from_str(&serialized).unwrap(); 69 | assert_eq!(topic, deserialized); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "Code Scanning - Action" 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | merge_group: 9 | schedule: 10 | # ┌───────────── minute (0 - 59) 11 | # │ ┌───────────── hour (0 - 23) 12 | # │ │ ┌───────────── day of the month (1 - 31) 13 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) 14 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) 15 | # │ │ │ │ │ 16 | # │ │ │ │ │ 17 | # │ │ │ │ │ 18 | # * * * * * 19 | - cron: '0 0 * * 0' 20 | 21 | jobs: 22 | CodeQL-Build: 23 | # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest 24 | runs-on: ubuntu-latest 25 | 26 | permissions: 27 | # required for all workflows 28 | security-events: write 29 | 30 | # only required for workflows in private repositories 31 | actions: read 32 | contents: read 33 | 34 | steps: 35 | - name: Checkout repository 36 | uses: actions/checkout@v3 37 | with: 38 | submodules: true 39 | # Initializes the CodeQL tools for scanning. 40 | - name: Initialize CodeQL 41 | uses: github/codeql-action/init@v2 42 | with: 43 | languages: cpp 44 | 45 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 46 | # If this step fails, then you should remove it and run the build manually (see below). 47 | - name: Autobuild 48 | uses: github/codeql-action/autobuild@v2 49 | 50 | # ℹ️ Command-line programs to run using the OS shell. 51 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 52 | 53 | # ✏️ If the Autobuild fails above, remove it and uncomment the following 54 | # three lines and modify them (or add more) to build your code if your 55 | # project uses a compiled language 56 | 57 | #- run: | 58 | # make bootstrap 59 | # make release 60 | 61 | - name: Perform CodeQL Analysis 62 | uses: github/codeql-action/analyze@v2 -------------------------------------------------------------------------------- /wallet-connect/src/serialization.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use crate::hex; 4 | use serde::de::{DeserializeOwned, Error as _}; 5 | use serde::ser::Error as _; 6 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 7 | use std::borrow::Cow; 8 | 9 | /// Helpers for serializing strings and empty values 10 | /// TODO: could this be replaced by some serde annotations or crate? 11 | pub mod jsonstring { 12 | use super::*; 13 | 14 | pub fn serialize(value: &Option, serializer: S) -> Result 15 | where 16 | T: Serialize, 17 | S: Serializer, 18 | { 19 | let json = match value { 20 | None => Cow::from(""), 21 | Some(value) => serde_json::to_string(value) 22 | .map_err(S::Error::custom)? 23 | .into(), 24 | }; 25 | serializer.serialize_str(&json) 26 | } 27 | 28 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result, D::Error> 29 | where 30 | T: DeserializeOwned, 31 | D: Deserializer<'de>, 32 | { 33 | let json = Cow::<'de, str>::deserialize(deserializer)?; 34 | if !json.is_empty() { 35 | let value = serde_json::from_str(&json).map_err(D::Error::custom)?; 36 | Ok(Some(value)) 37 | } else { 38 | Ok(None) 39 | } 40 | } 41 | } 42 | 43 | /// Helpers for serializing byte slices as hexadecimal strings 44 | pub mod hexstring { 45 | use super::*; 46 | 47 | pub fn serialize(bytes: &[u8], serializer: S) -> Result 48 | where 49 | S: Serializer, 50 | { 51 | serializer.serialize_str(&hex::encode(bytes)) 52 | } 53 | 54 | pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> 55 | where 56 | D: Deserializer<'de>, 57 | { 58 | let string = Cow::<'de, str>::deserialize(deserializer)?; 59 | let bytes = hex::decode(&*string).map_err(D::Error::custom)?; 60 | Ok(bytes) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /demo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(CMAKE_CXX_STANDARD 14) 3 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 4 | set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE) 5 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") 6 | if (APPLE) 7 | set(CMAKE_CXX_FLAGS "-framework Security -framework CoreFoundation -framework SystemConfiguration") 8 | endif() 9 | 10 | project(demo VERSION 1.0) 11 | 12 | # Run pre_build.bat in configuration step 13 | if (WIN32) 14 | execute_process( 15 | COMMAND cmd /c ${CMAKE_CURRENT_SOURCE_DIR}/pre_build.bat 16 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 17 | ) 18 | endif() 19 | 20 | # Add subdirectory sdk in configuration step 21 | add_subdirectory(sdk) 22 | 23 | # add static demo 24 | add_executable(demostatic main.cc chainmain.cc cronos.cc extra.cc third_party/easywsclient/easywsclient.cpp) 25 | if (WIN32 AND MSYS) 26 | target_link_libraries(demostatic PUBLIC ${PLAY_CPP_SDK_LIB} Ncrypt userenv ntdll Secur32 crypt32 ws2_32 ntdll) 27 | endif() 28 | if (WIN32 AND NOT MSYS) 29 | target_link_libraries(demostatic PUBLIC ${PLAY_CPP_SDK_LIB} Ncrypt userenv ntdll Secur32 crypt32) 30 | endif() 31 | if (APPLE) 32 | target_link_libraries(demostatic PUBLIC ${PLAY_CPP_SDK_LIB}) 33 | endif() 34 | if (UNIX AND NOT APPLE) 35 | target_link_libraries(demostatic PUBLIC ${PLAY_CPP_SDK_LIB} pthread dl rt) 36 | endif() 37 | 38 | # add dynamic demo 39 | add_executable(demo main.cc chainmain.cc cronos.cc extra.cc third_party/easywsclient/easywsclient.cpp) 40 | if (WIN32 AND MSYS) 41 | target_link_libraries(demo PUBLIC ${PLAY_CPP_SDK_LIB} Ncrypt userenv ntdll Secur32 crypt32 ws2_32 ntdll) 42 | endif() 43 | if (WIN32 AND NOT MSYS) 44 | target_link_libraries(demo PUBLIC play_cpp_sdk) 45 | # Copy dll 46 | add_custom_command(TARGET demo 47 | POST_BUILD 48 | COMMAND ${CMAKE_COMMAND} -E copy ${PLAY_CPP_SDK_DLL} ${demo_BINARY_DIR} 49 | ) 50 | endif() 51 | if (APPLE) 52 | # link library play_cpp_sdk built from subdirectory 53 | target_link_libraries(demo PUBLIC play_cpp_sdk) 54 | endif() 55 | if (UNIX AND NOT APPLE) 56 | # link library play_cpp_sdk built from subdirectory 57 | target_link_libraries(demo PUBLIC play_cpp_sdk) 58 | endif() 59 | 60 | add_subdirectory(examples) 61 | -------------------------------------------------------------------------------- /integration_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Please notice: some env, for example, CRONOSCAN_API_KEY, PAY_API_KEY, and PAY_WEBSOCKET_PORT 3 | # will be loaded in test.yml 4 | # 5 | # Or you can edit `demo/.env` then run `source demo/.env` to load them 6 | 7 | # Set up `CPP_EXAMPLE_PATH` for cpp integration test 8 | PWD=$(pwd) 9 | export CPP_EXAMPLE_PATH=$PWD/demo/bin/demostatic 10 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 11 | 12 | export CPP_EXAMPLE_PATH=$PWD/demo/build/examples/chainmain_bank_send 13 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 14 | 15 | export CPP_EXAMPLE_PATH=$PWD/demo/build/examples/chainmain_nft 16 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 17 | 18 | export CPP_EXAMPLE_PATH=$PWD/demo/build/examples/uint 19 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 20 | 21 | export CPP_EXAMPLE_PATH=$PWD/demo/build/examples/eth 22 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 23 | 24 | export CPP_EXAMPLE_PATH=$PWD/demo/build/examples/eth_login 25 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 26 | 27 | export CPP_EXAMPLE_PATH=$PWD/demo/build/examples/erc20 28 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 29 | 30 | export CPP_EXAMPLE_PATH=$PWD/demo/build/examples/erc721 31 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 32 | 33 | export CPP_EXAMPLE_PATH=$PWD/demo/build/examples/erc1155 34 | nix-shell defi-wallet-core-rs/integration_tests/shell.nix --run defi-wallet-core-rs/scripts/python-tests 35 | 36 | $PWD/demo/build/examples/get_erc20_transfer_history_blocking 37 | $PWD/demo/build/examples/get_erc721_transfer_history_blocking 38 | $PWD/demo/build/examples/get_tokens_blocking 39 | $PWD/demo/build/examples/get_token_transfers_blocking 40 | $PWD/demo/build/examples/create_payment 41 | $PWD/demo/build/examples/wallet_connect 42 | $PWD/demo/build/examples/new_wallet 43 | $PWD/demo/build/examples/restore_wallet 44 | -------------------------------------------------------------------------------- /demo/demo.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31727.386 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo", "demo/demo.vcxproj", "{AD00F0ED-39E3-4901-A157-01D91C702A18}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demostatic", "demostatic/demostatic.vcxproj", "{EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {AD00F0ED-39E3-4901-A157-01D91C702A18}.Debug|x64.ActiveCfg = Debug|x64 19 | {AD00F0ED-39E3-4901-A157-01D91C702A18}.Debug|x64.Build.0 = Debug|x64 20 | {AD00F0ED-39E3-4901-A157-01D91C702A18}.Debug|x86.ActiveCfg = Debug|Win32 21 | {AD00F0ED-39E3-4901-A157-01D91C702A18}.Debug|x86.Build.0 = Debug|Win32 22 | {AD00F0ED-39E3-4901-A157-01D91C702A18}.Release|x64.ActiveCfg = Release|x64 23 | {AD00F0ED-39E3-4901-A157-01D91C702A18}.Release|x64.Build.0 = Release|x64 24 | {AD00F0ED-39E3-4901-A157-01D91C702A18}.Release|x86.ActiveCfg = Release|Win32 25 | {AD00F0ED-39E3-4901-A157-01D91C702A18}.Release|x86.Build.0 = Release|Win32 26 | {EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}.Debug|x64.ActiveCfg = Debug|x64 27 | {EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}.Debug|x64.Build.0 = Debug|x64 28 | {EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}.Debug|x86.ActiveCfg = Debug|Win32 29 | {EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}.Debug|x86.Build.0 = Debug|Win32 30 | {EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}.Release|x64.ActiveCfg = Release|x64 31 | {EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}.Release|x64.Build.0 = Release|x64 32 | {EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}.Release|x86.ActiveCfg = Release|Win32 33 | {EA4A9CC2-B88E-42FD-8310-883EF4B92DB0}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {0663C9B8-E4D4-455D-924F-2DA56427BC9F} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Coordinated Vulnerability Disclosure Policy 2 | We ask security researchers to keep vulnerabilities and communications around vulnerability submissions private and confidential until a patch is developed to protect the people using Crypto.com’s protocols. In addition to this, we ask that you: 3 | 4 | - Allow us a reasonable amount of time to correct or address security vulnerabilities. 5 | - Avoid exploiting any vulnerabilities that you discover. 6 | - Demonstrate good faith by not disrupting or degrading Crypto.com’s data or services. 7 | 8 | ## Vulnerability Disclosure Process 9 | Once we receive a vulnerability report, Crypto.com will take these steps to address it: 10 | 11 | 1. Crypto.com will confirm receipt of the vulnerability report within 5 business days. The timing of our response may depend on when a report is submitted. As our daily operations are distributed in time zones across the globe, response times may vary. If you have not received a response to a vulnerability report from us within 5 business days, we encourage you to follow up with us again for a response. 12 | 2. Crypto.com will investigate and validate the security issue submitted to us as quickly as we can, usually within 10 business days of receipt. Submitting a thorough report with clear steps to recreate the vulnerability and/or a proof-of-concept will move the process along in a timely manner. 13 | 3. Crypto.com will acknowledge the bug, and make the necessary code changes to patch it. Some issues may require more time than others to patch, but we will strive to patch each vulnerability as quickly as our resources and development process allow. 14 | 4. Crypto.com will publicly release the security patch for the vulnerability, and acknowledge the security fix in the release notes once the issue has been resolved. Public release notes can reference to the person or people who reported the vulnerability, unless they wish to stay anonymous. 15 | 16 | ## Contact Us 17 | If you find a security issue, you can report it on the [Crypto.com HackerOne Bug Bounty Program](https://hackerone.com/crypto) or you can contact our team directly at [oss@crypto.com](mailto:oss@crypto.com). 18 | To communicate sensitive information, you can use the latest key in the 19 | [cryptocom's Keybase account](https://keybase.io/cryptocom/pgp_keys.asc) or use its [chat functionality](https://keybase.io/cryptocom/chat). -------------------------------------------------------------------------------- /demo/examples/src/eth.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace org::defi_wallet_core; 7 | 8 | int main(int argc, char *argv[]) { 9 | rust::Box signer1_wallet = restore_wallet( 10 | "shed crumble dismiss loyal latin million oblige gesture " 11 | "shrug still oxygen custom remove ribbon disorder palace " 12 | "addict again blanket sad flock consider obey popular", 13 | ""); 14 | rust::String signer1_address = signer1_wallet->get_eth_address(0); 15 | rust::Box signer1_privatekey = 16 | signer1_wallet->get_key("m/44'/60'/0'/0/0"); 17 | 18 | rust::Box signer2_wallet = 19 | restore_wallet("night renew tonight dinner shaft scheme domain oppose " 20 | "echo summer broccoli agent face guitar surface belt " 21 | "veteran siren poem alcohol menu custom crunch index", 22 | ""); 23 | rust::String signer2_address = signer2_wallet->get_eth_address(0); 24 | rust::Box signer2_privatekey = 25 | signer2_wallet->get_key("m/44'/60'/0'/0/0"); 26 | 27 | rust::String cronosrpc = "http://127.0.0.1:26651"; 28 | 29 | // build transaction information 30 | EthTxInfoRaw eth_tx_info = new_eth_tx_info(); 31 | eth_tx_info.to_address = signer2_address; 32 | eth_tx_info.nonce = get_eth_nonce(signer1_address, cronosrpc); 33 | eth_tx_info.amount = "1"; 34 | eth_tx_info.amount_unit = EthAmount::EthDecimal; 35 | 36 | // build signed transaction 37 | rust::Vec signedtx = 38 | build_eth_signed_tx(eth_tx_info, 777, true, *signer1_privatekey); 39 | U256 balance = get_eth_balance(signer1_address, cronosrpc); 40 | std::cout << "address=" << signer1_address 41 | << " balance=" << balance.to_string() << std::endl; 42 | 43 | // broadcast signed transaction 44 | rust::String status = 45 | broadcast_eth_signed_raw_tx(signedtx, cronosrpc, 1000).status; 46 | assert(status == "1"); 47 | 48 | balance = get_eth_balance(signer1_address, cronosrpc); 49 | std::cout << "address=" << signer1_address 50 | << " balance=" << balance.to_string() << std::endl; 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /demo/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # add examples 2 | include_directories(../sdk/include/) 3 | include_directories(../third_party/) 4 | 5 | add_executable(new_wallet src/new_wallet.cc) 6 | target_link_libraries(new_wallet PUBLIC play_cpp_sdk) 7 | 8 | add_executable(restore_wallet src/restore_wallet.cc) 9 | target_link_libraries(restore_wallet PUBLIC play_cpp_sdk) 10 | 11 | add_executable(chainmain_bank_send src/chainmain_bank_send.cc) 12 | target_link_libraries(chainmain_bank_send PUBLIC play_cpp_sdk) 13 | 14 | add_executable(chainmain_nft src/chainmain_nft.cc) 15 | target_link_libraries(chainmain_nft PUBLIC play_cpp_sdk) 16 | 17 | add_executable(uint src/uint.cc) 18 | target_link_libraries(uint PUBLIC play_cpp_sdk) 19 | 20 | add_executable(eth src/eth.cc) 21 | target_link_libraries(eth PUBLIC play_cpp_sdk) 22 | 23 | add_executable(eth_login src/eth_login.cc) 24 | target_link_libraries(eth_login PUBLIC play_cpp_sdk) 25 | 26 | add_executable(erc20 src/erc20.cc) 27 | target_link_libraries(erc20 PUBLIC play_cpp_sdk) 28 | 29 | add_executable(erc721 src/erc721.cc) 30 | target_link_libraries(erc721 PUBLIC play_cpp_sdk) 31 | 32 | add_executable(erc1155 src/erc1155.cc) 33 | target_link_libraries(erc1155 PUBLIC play_cpp_sdk) 34 | 35 | add_executable(get_erc20_transfer_history_blocking src/get_erc20_transfer_history_blocking.cc) 36 | target_link_libraries(get_erc20_transfer_history_blocking PUBLIC play_cpp_sdk) 37 | 38 | add_executable(get_erc721_transfer_history_blocking src/get_erc721_transfer_history_blocking.cc) 39 | target_link_libraries(get_erc721_transfer_history_blocking PUBLIC play_cpp_sdk) 40 | 41 | add_executable(get_tokens_blocking src/get_tokens_blocking.cc) 42 | target_link_libraries(get_tokens_blocking PUBLIC play_cpp_sdk) 43 | 44 | add_executable(get_token_transfers_blocking src/get_token_transfers_blocking.cc) 45 | target_link_libraries(get_token_transfers_blocking PUBLIC play_cpp_sdk) 46 | 47 | add_executable(create_payment src/create_payment.cc ../third_party/easywsclient/easywsclient.cpp) 48 | target_link_libraries(create_payment PUBLIC play_cpp_sdk) 49 | 50 | add_executable(wallet_connect src/wallet_connect.cc) 51 | target_link_libraries(wallet_connect PUBLIC play_cpp_sdk) 52 | 53 | add_executable(get_token_holders src/get_token_holders.cc) 54 | target_link_libraries(get_token_holders PUBLIC play_cpp_sdk) 55 | 56 | add_executable(get_wallet src/get_wallet.cc) 57 | target_link_libraries(get_wallet PUBLIC play_cpp_sdk) 58 | -------------------------------------------------------------------------------- /extra-cpp-bindings/include/walletconnectcallback.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rust/cxx.h" 4 | #include 5 | namespace com { 6 | namespace crypto { 7 | namespace game_sdk { 8 | 9 | class WalletConnectSessionInfo { 10 | public: 11 | /// if the wallet approved the connection 12 | bool connected; 13 | /// hex-string(0x...), the accounts returned by the wallet 14 | rust::Vec accounts; 15 | /// u64, the chain id returned by the wallet 16 | rust::String chain_id; 17 | /// the bridge server URL 18 | rust::String bridge; 19 | /// the secret key used in encrypting wallet requests 20 | /// and decrypting wallet responses as per WalletConnect 1.0 21 | /// hex-string(0x...), 32 bytes 22 | rust::String key; 23 | /// this is the client's randomly generated ID 24 | rust::String client_id; 25 | /// json, the client metadata (that will be presented to the wallet in the 26 | /// initial request) 27 | rust::String client_meta; 28 | /// uuid, the wallet's ID 29 | rust::String peer_id; 30 | /// json, the wallet's metadata 31 | rust::String peer_meta; 32 | /// uuid, the one-time request ID 33 | rust::String handshake_topic; 34 | 35 | void set_connected(bool connected); 36 | void set_accounts(rust::Vec accounts); 37 | void set_chainid(rust::String chainid); 38 | void set_bridge(rust::String bridge); 39 | void set_key(rust::String key); 40 | void set_clientid(rust::String client_id); 41 | void set_clientmeta(rust::String client_meta); 42 | void set_peerid(rust::String client_id); 43 | void set_peermeta(rust::String client_meta); 44 | void set_handshaketopic(rust::String handshake_topic); 45 | }; 46 | std::unique_ptr new_walletconnect_sessioninfo(); 47 | 48 | class WalletConnectCallback { 49 | public: 50 | virtual ~WalletConnectCallback() {} // need virtual to prevent memory leak 51 | // need to pure virtual to prevent incorrect callback 52 | virtual void 53 | onConnected(const WalletConnectSessionInfo &sessioninfo) const = 0; 54 | virtual void 55 | onDisconnected(const WalletConnectSessionInfo &sessioninfo) const = 0; 56 | virtual void 57 | onConnecting(const WalletConnectSessionInfo &sessioninfo) const = 0; 58 | virtual void 59 | onUpdated(const WalletConnectSessionInfo &sessioninfo) const = 0; 60 | }; 61 | 62 | std::unique_ptr new_walletconnect_callback(); 63 | } // namespace game_sdk 64 | } // namespace crypto 65 | } // namespace com 66 | -------------------------------------------------------------------------------- /.github/workflows/win-build.yml: -------------------------------------------------------------------------------- 1 | name: Windows Build CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - README.md 9 | tags: 10 | - "v*.*.*" 11 | merge_group: 12 | pull_request: 13 | paths-ignore: 14 | - README.md 15 | 16 | jobs: 17 | build: 18 | runs-on: windows-2019 19 | steps: 20 | - uses: ilammy/msvc-dev-cmd@v1 21 | with: 22 | arch: x86_64 23 | toolset: 14.29 24 | - uses: actions/checkout@v3 25 | with: 26 | submodules: recursive 27 | - run: git config --global core.symlinks true 28 | 29 | - name: Add msbuild to PATH 30 | uses: microsoft/setup-msbuild@v1.1 31 | 32 | - name: Build play-cpp-sdk crate 33 | run: cargo build --package play-cpp-sdk --release 34 | 35 | - name: Set up Python 36 | uses: actions/setup-python@v3 37 | with: 38 | python-version: "3.8" 39 | 40 | - name: Build demo solution 41 | working-directory: demo 42 | run: msbuild .\demo.sln -t:rebuild -property:Configuration=Release /p:Platform=x64 43 | 44 | - name: Build demo with cmake 45 | working-directory: demo 46 | run: | 47 | cmake.exe ` 48 | -B "out\build\x64-Release" ` 49 | -G "Ninja" ` 50 | -DCMAKE_BUILD_TYPE=Release ` 51 | -DCMAKE_INSTALL_PREFIX:PATH="out\install\x64-Release" ` 52 | -DCMAKE_C_COMPILER="cl.exe" ` 53 | -DCMAKE_CXX_COMPILER="cl.exe" ` 54 | -DCMAKE_MAKE_PROGRAM="ninja.exe" ` 55 | . 56 | cd out\build\x64-Release 57 | ninja 58 | 59 | - name: Pack binaries and bindings 60 | shell: bash 61 | run: | 62 | PLATFORM="Windows_x86_64" 63 | mkdir -p install 64 | cp -r demo/sdk install 65 | cp ./LICENSE install/sdk 66 | cp ./CHANGELOG.md install/sdk 67 | cd install 68 | 7z a -tzip ../play_cpp_sdk_${PLATFORM}.zip * 69 | cd .. 70 | sha256sum *.zip > "checksums-$PLATFORM.txt" 71 | echo "release_file=play_cpp_sdk_$PLATFORM.zip" >> $GITHUB_ENV 72 | echo "checksum_file=checksums-$PLATFORM.txt" >> $GITHUB_ENV 73 | cat $GITHUB_ENV 74 | 75 | - name: Upload binaries and bindings to Release 76 | uses: softprops/action-gh-release@v1 77 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') 78 | with: 79 | draft: true 80 | files: | 81 | ${{ env.release_file }} 82 | ${{ env.checksum_file }} 83 | -------------------------------------------------------------------------------- /demo/sdk/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(CMAKE_CXX_STANDARD 14) 3 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 4 | 5 | project(play_cpp_sdk VERSION 0.0.1) 6 | 7 | # Find bindings source files 8 | file(GLOB_RECURSE DEFI_WALLET_CORE_CPP_BINDINGS include/defi-wallet-core-cpp/src/*.cc) 9 | file(GLOB_RECURSE EXTRA_CPP_BINDINGS include/extra-cpp-bindings/src/*.cc) 10 | file(GLOB PLAY_CPP_SDK_SROUCES include/*.cc) 11 | 12 | # Find the rust types binding library 13 | find_library(RUST_LIB cxxbridge1 REQUIRED PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 14 | 15 | # Find the prebuilt static and dynamic libraries 16 | if (WIN32 AND MSYS) 17 | find_library(PLAY_CPP_SDK_LIB libplay_cpp_sdk.a PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 18 | find_library(PLAY_CPP_SDK_DYLIB libplay_cpp_sdk.dll.a PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 19 | find_file(PLAY_CPP_SDK_DLL NAME play_cpp_sdk.dll PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 20 | # Add static library play_cpp_sdk built from bindings source files 21 | add_library(play_cpp_sdk STATIC ${DEFI_WALLET_CORE_CPP_BINDINGS} ${EXTRA_CPP_BINDINGS} ${PLAY_CPP_SDK_SROUCES}) 22 | target_link_libraries(play_cpp_sdk ${PLAY_CPP_SDK_LIB} Ncrypt userenv ntdll Secur32 crypt32 ws2_32 ntdll) 23 | endif() 24 | 25 | if (WIN32 AND NOT MSYS) 26 | find_library(PLAY_CPP_SDK_LIB play_cpp_sdk.lib PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 27 | find_library(PLAY_CPP_SDK_DYLIB play_cpp_sdk.dll.lib PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 28 | find_file(PLAY_CPP_SDK_DLL NAME play_cpp_sdk.dll PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 29 | # Add static library play_cpp_sdk built from bindings source files 30 | add_library(play_cpp_sdk STATIC ${DEFI_WALLET_CORE_CPP_BINDINGS} ${EXTRA_CPP_BINDINGS} ${PLAY_CPP_SDK_SROUCES}) 31 | target_link_libraries(play_cpp_sdk ${PLAY_CPP_SDK_LIB} Ncrypt userenv ntdll Secur32 crypt32 ws2_32 ntdll) 32 | endif() 33 | 34 | if (APPLE) 35 | find_library(PLAY_CPP_SDK_LIB libplay_cpp_sdk.a PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 36 | find_library(PLAY_CPP_SDK_DYLIB libplay_cpp_sdk.dylib PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 37 | # Add static library play_cpp_sdk built from bindings source files 38 | add_library(play_cpp_sdk STATIC ${DEFI_WALLET_CORE_CPP_BINDINGS} ${EXTRA_CPP_BINDINGS} ${PLAY_CPP_SDK_SROUCES}) 39 | target_link_libraries(play_cpp_sdk ${RUST_LIB} ${PLAY_CPP_SDK_DYLIB}) 40 | endif() 41 | 42 | if (UNIX AND NOT APPLE) 43 | find_library(PLAY_CPP_SDK_LIB libplay_cpp_sdk.a PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib) 44 | # Add dynamic library play_cpp_sdk built from bindings source files 45 | add_library(play_cpp_sdk SHARED ${DEFI_WALLET_CORE_CPP_BINDINGS} ${EXTRA_CPP_BINDINGS} ${PLAY_CPP_SDK_SROUCES}) 46 | target_link_libraries(play_cpp_sdk ${PLAY_CPP_SDK_LIB} pthread dl rt) 47 | endif() 48 | -------------------------------------------------------------------------------- /wallet-connect/src/crypto/key.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use super::aead::{self, OpenError}; 4 | use crate::hex; 5 | use crate::protocol::EncryptionPayload; 6 | use ethers::utils::hex::FromHexError; 7 | use rand::{rngs::OsRng, Rng}; 8 | use secrecy::{ExposeSecret, SecretString}; 9 | use serde::de::{self, Deserialize, Deserializer}; 10 | use serde::ser::{Serialize, Serializer}; 11 | use std::borrow::Cow; 12 | use std::fmt::{self, Debug, Formatter}; 13 | use std::str::FromStr; 14 | use zeroize::Zeroizing; 15 | 16 | /// A wrapper around the symmetric key 17 | #[derive(Clone, Eq, PartialEq)] 18 | pub struct Key(Zeroizing<[u8; 32]>); 19 | 20 | impl Key { 21 | /// generates a random key 22 | pub fn random() -> Self { 23 | let mut key = [0u8; 32]; 24 | OsRng.fill(&mut key); 25 | Key::from_raw(key) 26 | } 27 | 28 | /// converts a raw byte array to the wrapper 29 | pub fn from_raw(raw: [u8; 32]) -> Self { 30 | Key(raw.into()) 31 | } 32 | 33 | /// hexadecimal representation of the key 34 | pub fn display(&self) -> SecretString { 35 | let keyref: &[u8] = &*self.0; 36 | SecretString::new(hex::encode(keyref)) 37 | } 38 | 39 | /// gets a raw slice reference to the key 40 | pub fn as_ref(&self) -> &[u8] { 41 | self.0.as_ref() 42 | } 43 | 44 | /// encrypt using the key 45 | pub fn seal(&self, data: impl AsRef<[u8]>) -> EncryptionPayload { 46 | aead::seal(self.as_ref(), data.as_ref()) 47 | } 48 | 49 | /// decrypt using the key 50 | pub fn open(&self, payload: &EncryptionPayload) -> Result, OpenError> { 51 | aead::open(self.as_ref(), payload) 52 | } 53 | } 54 | 55 | impl FromStr for Key { 56 | type Err = FromHexError; 57 | 58 | fn from_str(s: &str) -> Result { 59 | let mut bytes = [0u8; 32]; 60 | hex::decode_mut(s, &mut bytes)?; 61 | Ok(Key::from_raw(bytes)) 62 | } 63 | } 64 | 65 | impl Debug for Key { 66 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 67 | f.write_str("Key(********)") 68 | } 69 | } 70 | 71 | impl Serialize for Key { 72 | fn serialize(&self, serializer: S) -> Result { 73 | serializer.serialize_str(self.display().expose_secret()) 74 | } 75 | } 76 | 77 | impl<'de> Deserialize<'de> for Key { 78 | fn deserialize>(deserializer: D) -> Result { 79 | let s = Cow::<'de, str>::deserialize(deserializer)?; 80 | Key::from_str(&s).map_err(de::Error::custom) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - README.md 9 | merge_group: 10 | pull_request: 11 | paths-ignore: 12 | - README.md 13 | 14 | env: 15 | CARGO_TERM_COLOR: always 16 | RUSTFLAGS: -Dwarnings 17 | 18 | jobs: 19 | check: 20 | name: cargo check 21 | runs-on: ubuntu-latest 22 | env: 23 | RUSTFLAGS: -A dead_code 24 | steps: 25 | - uses: actions/checkout@v3 26 | with: 27 | submodules: recursive 28 | - uses: dtolnay/rust-toolchain@stable 29 | - uses: actions/cache@v2 30 | with: 31 | path: | 32 | ~/.cargo/bin/ 33 | ~/.cargo/git/db/ 34 | target/ 35 | key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }} 36 | - run: cargo check 37 | test: 38 | name: cargo test 39 | runs-on: ubuntu-latest 40 | env: 41 | RUSTFLAGS: -A dead_code 42 | steps: 43 | - uses: actions/checkout@v3 44 | with: 45 | submodules: recursive 46 | - uses: dtolnay/rust-toolchain@stable 47 | with: 48 | components: llvm-tools-preview 49 | - uses: actions/cache@v2 50 | with: 51 | path: | 52 | ~/.cargo/bin/ 53 | ~/.cargo/git/db/ 54 | target/ 55 | key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }} 56 | - name: Run tests 57 | run: cargo test --all-features --all 58 | 59 | fmt: 60 | name: cargo fmt 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v3 64 | with: 65 | submodules: recursive 66 | - uses: dtolnay/rust-toolchain@stable 67 | with: 68 | components: rustfmt 69 | - uses: actions/cache@v2 70 | with: 71 | path: | 72 | ~/.cargo/bin/ 73 | ~/.cargo/git/db/ 74 | target/ 75 | key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }} 76 | - run: cargo fmt --all -- --check 77 | clippy: 78 | name: cargo clippy 79 | runs-on: ubuntu-latest 80 | env: 81 | RUSTFLAGS: -A dead_code 82 | steps: 83 | - uses: actions/checkout@v3 84 | with: 85 | submodules: recursive 86 | - uses: dtolnay/rust-toolchain@stable 87 | with: 88 | components: clippy 89 | - uses: actions/cache@v2 90 | with: 91 | path: | 92 | ~/.cargo/bin/ 93 | ~/.cargo/git/db/ 94 | target/ 95 | key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }} 96 | - name: Check with clippy 97 | run: cargo clippy --all --all-features -- -D warnings 98 | -------------------------------------------------------------------------------- /wallet-connect/src/protocol/message.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use super::Topic; 4 | use crate::serialization; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | /// the outer message type send to or received from the bridge server 8 | /// via websockets 9 | /// https://docs.walletconnect.com/tech-spec#websocket-messages 10 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 11 | pub struct SocketMessage { 12 | /// the topic of the message (UUID to denote the peer or handshake) 13 | pub topic: Topic, 14 | #[serde(rename = "type")] 15 | /// whether publishing or subscribing 16 | pub kind: SocketMessageKind, 17 | /// the encrypted payload (if any) 18 | #[serde(with = "serialization::jsonstring")] 19 | pub payload: Option, 20 | /// a new field present in bridge serve messages 21 | /// (or shall serde allow unknown fields?) 22 | #[serde(default)] 23 | pub silent: bool, 24 | } 25 | 26 | /// whether publishing or subscribing 27 | #[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 28 | #[serde(rename_all = "lowercase")] 29 | pub enum SocketMessageKind { 30 | /// Publish 31 | Pub, 32 | /// Subscribe 33 | Sub, 34 | } 35 | 36 | /// The encrypted payload -- the plaintext is usually a JSON-RPC request or response 37 | /// https://docs.walletconnect.com/tech-spec#cryptography 38 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 39 | pub struct EncryptionPayload { 40 | /// the encrypted payload 41 | #[serde(with = "serialization::hexstring")] 42 | pub data: Vec, 43 | /// HMAC-SHA256 of the encrypted payload and nonce 44 | #[serde(with = "serialization::hexstring")] 45 | pub hmac: Vec, 46 | /// nonce 47 | #[serde(with = "serialization::hexstring")] 48 | pub iv: Vec, 49 | } 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | use super::*; 54 | use serde_json::json; 55 | 56 | #[test] 57 | fn message_serialization() { 58 | let message = SocketMessage { 59 | topic: "de5682be-2a03-4b8e-866e-1e89dbca422b".parse().unwrap(), 60 | kind: SocketMessageKind::Pub, 61 | payload: Some(EncryptionPayload { 62 | data: vec![0x04, 0x2], 63 | hmac: vec![0x13, 0x37], 64 | iv: vec![0x00], 65 | }), 66 | silent: false, 67 | }; 68 | let json = json!({ 69 | "topic": "de5682be-2a03-4b8e-866e-1e89dbca422b", 70 | "type": "pub", 71 | "payload": "{\"data\":\"0402\",\"hmac\":\"1337\",\"iv\":\"00\"}", 72 | "silent": false, 73 | }); 74 | 75 | assert_eq!(serde_json::to_value(&message).unwrap(), json); 76 | assert_eq!( 77 | serde_json::from_value::(json).unwrap(), 78 | message 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /demo/examples/src/erc20.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace org::defi_wallet_core; 8 | 9 | int main(int argc, char *argv[]) { 10 | rust::Box signer1_wallet = restore_wallet( 11 | "shed crumble dismiss loyal latin million oblige gesture " 12 | "shrug still oxygen custom remove ribbon disorder palace " 13 | "addict again blanket sad flock consider obey popular", 14 | ""); 15 | rust::String signer1_address = signer1_wallet->get_eth_address(0); 16 | rust::Box signer1_privatekey = 17 | signer1_wallet->get_key("m/44'/60'/0'/0/0"); 18 | 19 | rust::Box signer2_wallet = 20 | restore_wallet("night renew tonight dinner shaft scheme domain oppose " 21 | "echo summer broccoli agent face guitar surface belt " 22 | "veteran siren poem alcohol menu custom crunch index", 23 | ""); 24 | rust::String signer2_address = signer2_wallet->get_eth_address(0); 25 | rust::Box signer2_privatekey = 26 | signer2_wallet->get_key("m/44'/60'/0'/0/0"); 27 | 28 | rust::Box validator1_wallet = restore_wallet( 29 | "visit craft resemble online window solution west chuckle " 30 | "music diesel vital settle comic tribe project blame bulb " 31 | "armed flower region sausage mercy arrive release", 32 | ""); 33 | rust::String validator1_address = validator1_wallet->get_eth_address(0); 34 | 35 | Erc20 erc20 = new_erc20("0x5003c1fcc043D2d81fF970266bf3fa6e8C5a1F3A", 36 | "http://127.0.0.1:26651", 777) 37 | .legacy(); 38 | assert(erc20.name() == "Gold"); 39 | assert(erc20.symbol() == "GLD"); 40 | assert(erc20.decimals() == 18); 41 | U256 erc20_total_supply = erc20.total_supply(); 42 | assert(erc20_total_supply == u256("100000000000000000000000000")); 43 | U256 erc20_balance = erc20.balance_of(signer1_address); 44 | assert(erc20_balance == erc20_total_supply); 45 | 46 | // transfer erc20 token from signer1 to signer2 47 | rust::String status = 48 | erc20.transfer(signer2_address, "100", *signer1_privatekey).status; 49 | assert(status == "1"); 50 | assert(erc20.balance_of(signer1_address) == erc20_balance.sub(u256("100"))); 51 | 52 | // signer1 approve singer2 allowance 53 | erc20.interval(3000).approve(signer2_address, "1000", *signer1_privatekey); 54 | rust::String allowance = erc20.allowance(signer1_address, signer2_address); 55 | assert(allowance == "1000"); 56 | 57 | // transfer from signer1 to validator1 using the allowance mechanism 58 | erc20.transfer_from(signer1_address, validator1_address, "100", 59 | *signer2_privatekey); 60 | allowance = erc20.allowance(signer1_address, signer2_address); 61 | assert(allowance == "900"); 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /wallet-connect/src/client/options.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use super::session::{Session, SessionInfo}; 4 | use crate::client::ClientChannelMessage; 5 | use crate::crypto::Key; 6 | use crate::protocol::{Metadata, Topic}; 7 | use crate::uri::Uri; 8 | use tokio::sync::mpsc::UnboundedSender; 9 | use url::Url; 10 | 11 | /// The provided WalletConnect connection information 12 | #[derive(Clone, Debug)] 13 | pub enum Connection { 14 | /// only the bridge server URL is provided 15 | /// (the full URI will need to be generated) 16 | Bridge(Url), 17 | /// the full URI is provided 18 | Uri(Uri), 19 | } 20 | 21 | impl Default for Connection { 22 | fn default() -> Self { 23 | Connection::Bridge(Url::parse("https://l.bridge.walletconnect.org").unwrap()) 24 | } 25 | } 26 | 27 | /// The WalletConnect 1.0 configuration 28 | #[derive(Clone, Debug)] 29 | pub struct Options { 30 | /// the client metadata (will be presented to the wallet) 31 | pub meta: Metadata, 32 | /// the provided connection information 33 | pub connection: Connection, 34 | /// the chain id (if None, retrived and decided by wallet, if Some, decided by the client) 35 | pub chain_id: Option, 36 | /// callback sender 37 | pub callback_channel: Option>, 38 | } 39 | 40 | impl Options { 41 | /// creates a new configuration with a default bridge server URL and chain id 42 | pub fn new(meta: Metadata, chain_id: Option) -> Self { 43 | Options { 44 | meta, 45 | connection: Connection::default(), 46 | chain_id, 47 | callback_channel: None, 48 | } 49 | } 50 | 51 | /// creates a new configuration with a provided URI 52 | pub fn with_uri(meta: Metadata, uri: Uri) -> Self { 53 | Options { 54 | meta, 55 | connection: Connection::Uri(uri), 56 | chain_id: None, 57 | callback_channel: None, 58 | } 59 | } 60 | 61 | /// creates a new session from the configuration 62 | pub fn create_session(self) -> Session { 63 | let client_meta = self.meta; 64 | let (handshake_topic, bridge, key) = match self.connection { 65 | Connection::Bridge(bridge) => (Topic::new(), bridge, Key::random()), 66 | Connection::Uri(uri) => uri.into_parts(), 67 | }; 68 | let chain_id = self.chain_id; 69 | 70 | Session { 71 | info: SessionInfo { 72 | connected: false, 73 | accounts: Vec::new(), 74 | chain_id, 75 | bridge, 76 | key, 77 | client_id: Topic::new(), 78 | client_meta, 79 | peer_id: None, 80 | peer_meta: None, 81 | handshake_topic, 82 | }, 83 | callback_channel: None, 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /demo/examples/src/chainmain_bank_send.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace org::defi_wallet_core; 8 | 9 | const uint64_t GAS_LIMIT = 5000000; 10 | const uint64_t FEE_AMOUNT = 25000000000; 11 | const uint32_t COIN_TYPE = 394; 12 | 13 | CosmosSDKTxInfoRaw 14 | build_txinfo() { // NOLINT(modernize-use-trailing-return-type) 15 | CosmosSDKTxInfoRaw ret; 16 | ret.account_number = 0; 17 | ret.sequence_number = 0; 18 | ret.gas_limit = GAS_LIMIT; 19 | ret.fee_amount = FEE_AMOUNT; 20 | ret.fee_denom = "basecro"; 21 | ret.timeout_height = 0; 22 | ret.memo_note = ""; 23 | ret.chain_id = "chainmain-1"; 24 | ret.coin_type = COIN_TYPE; 25 | ret.bech32hrp = "cro"; 26 | return ret; 27 | } 28 | 29 | int main(int argc, char *argv[]) { // NOLINT(modernize-use-trailing-return-type) 30 | CosmosSDKTxInfoRaw tx_info = build_txinfo(); 31 | rust::String from_address = "cro1u08u5dvtnpmlpdq333uj9tcj75yceggszxpnsy"; 32 | rust::String to_address = "cro1apdh4yc2lnpephevc6lmpvkyv6s5cjh652n6e4"; 33 | rust::String grpc = "http://127.0.0.1:26803"; 34 | rust::String servercosmos = "http://127.0.0.1:26804"; 35 | rust::String servertendermint = "http://127.0.0.1:26807"; 36 | rust::Box wallet = restore_wallet( 37 | "shed crumble dismiss loyal latin million oblige gesture " 38 | "shrug still oxygen custom remove ribbon disorder palace " 39 | "addict again blanket sad flock consider obey popular", 40 | ""); 41 | 42 | // check the original balance 43 | rust::String balance = query_account_balance(grpc, to_address, "basecro"); 44 | std::cout << "balance=" << balance << std::endl; 45 | 46 | // query account detils 47 | rust::String detailjson = query_account_details(servercosmos, from_address); 48 | std::cout << "detailjson=" << detailjson << std::endl; 49 | 50 | // update account_number and sequence_number after querying account details 51 | // info 52 | CosmosAccountInfoRaw detailinfo = 53 | query_account_details_info(servercosmos, from_address); 54 | tx_info.account_number = detailinfo.account_number; 55 | tx_info.sequence_number = detailinfo.sequence_number; 56 | 57 | // get the private key 58 | rust::Box privatekey = wallet->get_key("m/44'/394'/0'/0/0"); 59 | 60 | // transfer 1 basecro 61 | rust::Vec signedtx = get_single_bank_send_signed_tx( 62 | tx_info, *privatekey, to_address, 1, "basecro"); 63 | CosmosTransactionReceiptRaw resp = broadcast_tx(servertendermint, signedtx); 64 | std::cout << "tx_hash_hex: " << resp.tx_hash_hex << std::endl 65 | << "code: " << resp.code << std::endl 66 | << "log: " << resp.log << std::endl; 67 | 68 | // dealy and make sure the block is updated 69 | std::this_thread::sleep_for(std::chrono::seconds(3)); 70 | 71 | // check balance updated 72 | balance = query_account_balance(grpc, to_address, "basecro"); 73 | std::cout << "balance=" << balance << std::endl; 74 | } 75 | -------------------------------------------------------------------------------- /demo/examples/src/get_erc20_transfer_history_blocking.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace com::crypto::game_sdk; 5 | 6 | inline rust::String getEnv(rust::String key) { 7 | rust::String ret; 8 | if (getenv(key.c_str()) != nullptr) { 9 | ret = getenv(key.c_str()); 10 | } 11 | return ret; 12 | } 13 | 14 | // Read CronoScan api key in env 15 | const rust::String CRONOSCAN_API_KEY = getEnv("CRONOSCAN_API_KEY"); 16 | 17 | int main(int argc, char *argv[]) { 18 | if (CRONOSCAN_API_KEY == "") 19 | return -1; 20 | 21 | // Get a list of "CRC20 - Token Transfer Events" by Address 22 | // Returns up to a maximum of the last 10000 transactions only 23 | // https://cronoscan.com/tokentxns?a=0xa9b34a4b568e640d5e5d1e6e13101025e1262864 24 | rust::Vec erc20_txs = get_erc20_transfer_history_blocking( 25 | "0xa9b34a4b568e640d5e5d1e6e13101025e1262864", "", 26 | QueryOption::ByAddress, CRONOSCAN_API_KEY); 27 | 28 | for (const RawTxDetail &tx : erc20_txs) { 29 | std::cout << "hash: " << tx.hash << " "; 30 | std::cout << "to: " << tx.to_address << " "; 31 | std::cout << "from: " << tx.from_address << " "; 32 | std::cout << "value:" << tx.value << " "; 33 | std::cout << "block_no: " << tx.block_no << " "; 34 | std::cout << "timestamp: " << tx.timestamp << " "; 35 | std::cout << "contract: " << tx.contract_address << " " << std::endl; 36 | } 37 | 38 | std::cout << "A total of " << erc20_txs.size() << " transactions" 39 | << std::endl; 40 | 41 | // Get a list of "CRC20 - Token Transfer Events" by ByAddressAndContract 42 | // Returns up to a maximum of the last 10000 transactions only 43 | // https://cronoscan.com/token/0x2d03bece6747adc00e1a131bba1469c15fd11e03?a=0xa9b34a4b568e640d5e5d1e6e13101025e1262864 44 | erc20_txs = get_erc20_transfer_history_blocking( 45 | "0xa9b34a4b568e640d5e5d1e6e13101025e1262864", 46 | "0x2D03bECE6747ADC00E1a131BBA1469C15fD11e03", 47 | QueryOption::ByAddressAndContract, CRONOSCAN_API_KEY); 48 | 49 | for (const RawTxDetail &tx : erc20_txs) { 50 | std::cout << "hash: " << tx.hash << " "; 51 | std::cout << "to: " << tx.to_address << " "; 52 | std::cout << "from: " << tx.from_address << " "; 53 | std::cout << "value:" << tx.value << " "; 54 | std::cout << "block_no: " << tx.block_no << " "; 55 | std::cout << "timestamp: " << tx.timestamp << " "; 56 | std::cout << "contract: " << tx.contract_address << " " << std::endl; 57 | } 58 | std::cout << "A total of " << erc20_txs.size() << " transactions" 59 | << std::endl; 60 | 61 | // Get a list of "CRC20 - Token Transfer Events" by ByContract 62 | // Returns up to a maximum of the last 10000 transactions only 63 | erc20_txs = get_erc20_transfer_history_blocking( 64 | "", "0x66e428c3f67a68878562e79A0234c1F83c208770", 65 | QueryOption::ByContract, CRONOSCAN_API_KEY); 66 | 67 | std::cout << "A total of " << erc20_txs.size() << " transactions" 68 | << std::endl; 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /demo/examples/src/get_erc721_transfer_history_blocking.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace com::crypto::game_sdk; 5 | 6 | inline rust::String getEnv(rust::String key) { 7 | rust::String ret; 8 | if (getenv(key.c_str()) != nullptr) { 9 | ret = getenv(key.c_str()); 10 | } 11 | return ret; 12 | } 13 | 14 | // Read CronoScan api key in env 15 | const rust::String CRONOSCAN_API_KEY = getEnv("CRONOSCAN_API_KEY"); 16 | 17 | int main(int argc, char *argv[]) { 18 | if (CRONOSCAN_API_KEY == "") 19 | return -1; 20 | 21 | // Get a list of "ERC721 - Token Transfer Events" by Address 22 | // Returns up to a maximum of the last 10000 transactions only 23 | // https://cronoscan.com/tokentxns-nft?a=0x668f126b87936df4f9a98f18c44eb73868fffea0 24 | rust::Vec erc721_txs = get_erc721_transfer_history_blocking( 25 | "0x668f126b87936df4f9a98f18c44eb73868fffea0", "", 26 | QueryOption::ByAddress, CRONOSCAN_API_KEY); 27 | for (const RawTxDetail &tx : erc721_txs) { 28 | std::cout << "hash: " << tx.hash << " "; 29 | std::cout << "to: " << tx.to_address << " "; 30 | std::cout << "from: " << tx.from_address << " "; 31 | std::cout << "TokenID:" << tx.value << " "; 32 | std::cout << "block_no: " << tx.block_no << " "; 33 | std::cout << "timestamp: " << tx.timestamp << " "; 34 | std::cout << "contract: " << tx.contract_address << " " << std::endl; 35 | } 36 | 37 | std::cout << "A total of " << erc721_txs.size() << " transactions" 38 | << std::endl; 39 | 40 | // Get a list of "ERC721 - Token Transfer Events" ByAddressAndContract 41 | // Returns up to a maximum of the last 10000 transactions only 42 | // https://cronoscan.com/token/0x562f021423d75a1636db5be1c4d99bc005ccebfe?a=0x668f126b87936df4f9a98f18c44eb73868fffea0 43 | erc721_txs = get_erc721_transfer_history_blocking( 44 | "0x668f126b87936df4f9a98f18c44eb73868fffea0", 45 | "0x562F021423D75A1636DB5bE1C4D99Bc005ccebFe", 46 | QueryOption::ByAddressAndContract, CRONOSCAN_API_KEY); 47 | for (const RawTxDetail &tx : erc721_txs) { 48 | std::cout << "hash: " << tx.hash << " "; 49 | std::cout << "to: " << tx.to_address << " "; 50 | std::cout << "from: " << tx.from_address << " "; 51 | std::cout << "TokenID:" << tx.value << " "; 52 | std::cout << "block_no: " << tx.block_no << " "; 53 | std::cout << "timestamp: " << tx.timestamp << " "; 54 | std::cout << "contract: " << tx.contract_address << " " << std::endl; 55 | } 56 | 57 | std::cout << "A total of " << erc721_txs.size() << " transactions" 58 | << std::endl; 59 | 60 | // Get a list of "ERC721 - Token Transfer Events" ByContract 61 | // Returns up to a maximum of the last 10000 transactions only 62 | // https://cronoscan.com/token/0x18b73d1f9e2d97057dec3f8d6ea9e30fcadb54d7 63 | erc721_txs = get_erc721_transfer_history_blocking( 64 | "", "0x18b73D1f9e2d97057deC3f8D6ea9e30FCADB54D7", 65 | QueryOption::ByContract, CRONOSCAN_API_KEY); 66 | for (const RawTxDetail &tx : erc721_txs) { 67 | std::cout << "hash: " << tx.hash << " "; 68 | std::cout << "to: " << tx.to_address << " "; 69 | std::cout << "from: " << tx.from_address << " "; 70 | std::cout << "TokenID:" << tx.value << " "; 71 | std::cout << "block_no: " << tx.block_no << " "; 72 | std::cout << "timestamp: " << tx.timestamp << " "; 73 | std::cout << "contract: " << tx.contract_address << " " << std::endl; 74 | } 75 | 76 | std::cout << "A total of " << erc721_txs.size() << " transactions" 77 | << std::endl; 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /demo/examples/src/create_payment.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace com::crypto::game_sdk; 9 | using namespace nlohmann; 10 | 11 | void websocket_client_thread(std::atomic &stop_thread, rust::String &id); 12 | 13 | inline rust::String getEnv(rust::String key) { 14 | rust::String ret; 15 | if (getenv(key.c_str()) != nullptr) { 16 | ret = getenv(key.c_str()); 17 | } 18 | return ret; 19 | } 20 | 21 | // Read pay api key in env 22 | const rust::String PAY_API_KEY = getEnv("PAY_API_KEY"); 23 | // Read websocket port in env 24 | const rust::String PAY_WEBSOCKET_PORT = getEnv("PAY_WEBSOCKET_PORT"); 25 | 26 | int main(int argc, char *argv[]) { 27 | if (PAY_API_KEY == "") 28 | return -1; 29 | 30 | std::atomic stop_thread_1{false}; 31 | rust::String id = ""; 32 | std::thread t1(websocket_client_thread, std::ref(stop_thread_1), 33 | std::ref(id)); 34 | 35 | OptionalArguments opiton_args; 36 | opiton_args.description = "Crypto.com Tee (Unisex)"; 37 | CryptoComPaymentResponse resp = 38 | create_payment(PAY_API_KEY, "2500", "USD", opiton_args); 39 | std::cout << "create payment:" << resp.id << " "; 40 | std::cout << resp.main_app_qr_code << " "; 41 | std::cout << resp.onchain_deposit_address << " "; 42 | std::cout << resp.base_amount << " "; 43 | std::cout << resp.currency << " "; 44 | std::cout << resp.expiration << " "; 45 | std::cout << resp.status << std::endl; 46 | 47 | std::this_thread::sleep_for(std::chrono::milliseconds(3000)); 48 | stop_thread_1 = true; // force stopping websocket thread after timeout 49 | id = resp.id; // pass the id to the thread 50 | t1.join(); // pauses until t1 finishes 51 | 52 | return 0; 53 | } 54 | 55 | // A simple websocket client thread 56 | void websocket_client_thread(std::atomic &stop_thread, rust::String &id) { 57 | using easywsclient::WebSocket; 58 | rust::String r_port = PAY_WEBSOCKET_PORT; 59 | std::string port = r_port.c_str(); 60 | std::unique_ptr ws( 61 | WebSocket::from_url("ws://127.0.0.1:" + port)); 62 | if (ws == nullptr) 63 | return; 64 | while (ws->getReadyState() != WebSocket::CLOSED) { 65 | WebSocket::pointer wsp = 66 | &*ws; // <-- because a unique_ptr cannot be copied into a lambda 67 | ws->poll(); 68 | ws->dispatch([wsp](std::string msg) { 69 | // std::cout << "Receive webhook event: " << msg << std::endl; 70 | try { 71 | auto message = json::parse(msg); 72 | assert(message.at("type") == "payment.created"); 73 | rust::String id = message.at("data").at("object").at("id"); 74 | CryptoComPaymentResponse resp = get_payment(PAY_API_KEY, id); 75 | std::cout << "get payment: " << resp.id << " "; 76 | std::cout << resp.main_app_qr_code << " "; 77 | std::cout << resp.onchain_deposit_address << " "; 78 | std::cout << resp.base_amount << " "; 79 | std::cout << resp.currency << " "; 80 | std::cout << resp.expiration << " "; 81 | std::cout << resp.status << std::endl; 82 | wsp->close(); 83 | } catch (const nlohmann::detail::parse_error &e) { 84 | std::cout << e.what() << std::endl; 85 | wsp->close(); 86 | } 87 | }); 88 | if (stop_thread) { 89 | return; 90 | } 91 | } 92 | std::cout << "websocket client thread ends" << std::endl; 93 | } 94 | -------------------------------------------------------------------------------- /demo/examples/src/get_wallet.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // nolint is not effective, it's compiler error, ignore 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace com::crypto::game_sdk; 11 | 12 | int main(int argc, char *argv[]) { 13 | 14 | // empty path, cache is false 15 | // Fetch new listings without saving to local file 16 | rust::Vec wallet_entries = get_all_wallets(false, ""); 17 | 18 | // non-empty path, cache is false 19 | // Fetch new listings and save to local file 20 | wallet_entries = get_all_wallets(false, "wallets.json"); 21 | 22 | // empty path, cache is true 23 | // Load the hardcoded listings 24 | wallet_entries = get_all_wallets(true, ""); 25 | 26 | // non-empty path, cache is true 27 | // Load the listings from a local file 28 | wallet_entries = get_all_wallets(true, "wallets.json"); 29 | 30 | wallet_entries = filter_wallets(true, "", Platform::Mobile); 31 | assert(wallet_entries.size() == 164); 32 | std::cout << "Total mobile Wallets: " << wallet_entries.size() << std::endl; 33 | for (const WalletEntry &entry : wallet_entries) { 34 | std::cout << "Mobile | "; 35 | std::cout << entry.id << " | "; 36 | std::cout << entry.name << " | "; 37 | // std::cout << entry.image_url.sm << " "; 38 | // std::cout << entry.image_url.md << " "; 39 | // std::cout << entry.image_url.lg << " "; 40 | std::cout << entry.mobile_native_link << " | "; 41 | std::cout << entry.mobile_universal_link << " " << std::endl; 42 | } 43 | 44 | wallet_entries = filter_wallets(true, "", Platform::Desktop); 45 | assert(wallet_entries.size() == 20); 46 | for (const WalletEntry &entry : wallet_entries) { 47 | std::cout << "Desktop | "; 48 | std::cout << entry.id << " | "; 49 | std::cout << entry.name << " | "; 50 | // std::cout << entry.image_url.sm << " "; 51 | // std::cout << entry.image_url.md << " "; 52 | // std::cout << entry.image_url.lg << " "; 53 | std::cout << entry.desktop_native_link << " | "; 54 | std::cout << entry.desktop_universal_link << " " << std::endl; 55 | } 56 | 57 | auto id = 58 | "f2436c67184f158d1beda5df53298ee84abfc367581e4505134b5bcf5f46697d"; 59 | assert(check_wallet(true, "", id, Platform::Mobile) == true); 60 | assert(check_wallet(true, "", id, Platform::Desktop) == true); 61 | WalletEntry wallet = get_wallet(true, "", id); 62 | assert(wallet.name == "Crypto.com | DeFi Wallet"); 63 | assert(wallet.mobile_native_link == "cryptowallet:"); 64 | assert(wallet.mobile_universal_link == "https://wallet.crypto.com"); 65 | assert(wallet.desktop_native_link == "cryptowallet:"); 66 | assert(wallet.desktop_universal_link == ""); 67 | 68 | id = "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96"; 69 | assert(check_wallet(true, "", id, Platform::Mobile) == true); 70 | assert(check_wallet(true, "", id, Platform::Desktop) == false); 71 | wallet = get_wallet(true, "", id); 72 | assert(wallet.name == "MetaMask"); 73 | assert(wallet.mobile_native_link == "metamask:"); 74 | assert(wallet.mobile_universal_link == "https://metamask.app.link"); 75 | assert(wallet.desktop_native_link == ""); 76 | assert(wallet.desktop_universal_link == ""); 77 | 78 | id = "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0"; 79 | assert(check_wallet(true, "", id, Platform::Mobile) == true); 80 | assert(check_wallet(true, "", id, Platform::Desktop) == false); 81 | wallet = get_wallet(true, "", id); 82 | assert(wallet.name == "Trust Wallet"); 83 | assert(wallet.mobile_native_link == "trust:"); 84 | assert(wallet.mobile_universal_link == "https://link.trustwallet.com"); 85 | assert(wallet.desktop_native_link == ""); 86 | assert(wallet.desktop_universal_link == ""); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /wallet-connect/src/v2/crypto.rs: -------------------------------------------------------------------------------- 1 | use base64::{engine::general_purpose, Engine as _}; 2 | use chacha20poly1305::{ 3 | aead::{Aead, KeyInit, OsRng}, 4 | AeadCore, ChaCha20Poly1305, Nonce, 5 | }; 6 | use hkdf::Hkdf; 7 | use relay_rpc::domain::Topic; 8 | use sha2::{Digest, Sha256}; 9 | use x25519_dalek::{PublicKey, StaticSecret}; 10 | use zeroize::Zeroize; 11 | 12 | use crate::{crypto::Key, hex}; 13 | 14 | /// After the session proposal response, we obtain the wallet's public key 15 | /// and derive a new topic and symmetric key for the pairing topic 16 | pub fn derive_symkey_topic(responder_public_key: &str, secret: &Key) -> Option<(Topic, Key)> { 17 | let mut secret_buf = [0u8; 32]; 18 | secret_buf.copy_from_slice(secret.as_ref()); 19 | let mut client_secret = StaticSecret::from(secret_buf); 20 | match hex::decode(responder_public_key) { 21 | Ok(pk) if pk.len() == 32 => { 22 | let mut pk_b = [0u8; 32]; 23 | pk_b.copy_from_slice(&pk); 24 | let responder_public = PublicKey::from(pk_b); 25 | let shared_secret = client_secret.diffie_hellman(&responder_public); 26 | let hkdf = Hkdf::::new(None, shared_secret.as_bytes()); 27 | let mut sym_key = [0u8; 32]; 28 | 29 | hkdf.expand(&[], &mut sym_key).expect("expand sym key"); 30 | 31 | let hashed = Sha256::digest(&sym_key[..]); 32 | let new_topic = Topic::from(hex::encode(hashed)); 33 | secret_buf.zeroize(); 34 | client_secret.zeroize(); 35 | Some((new_topic, Key::from_raw(sym_key))) 36 | } 37 | _ => { 38 | secret_buf.zeroize(); 39 | client_secret.zeroize(); 40 | None 41 | } 42 | } 43 | } 44 | 45 | /// Encrypt using ChaCha20Poly1305 and encode using base64 46 | /// The first byte is a version byte, the next 12 bytes are the nonce 47 | /// (see https://docs.walletconnect.com/2.0/specs/clients/core/crypto/crypto-envelopes#type-0-envelope) 48 | pub fn encrypt_and_encode(key: &Key, data: &[u8]) -> String { 49 | let cipher = ChaCha20Poly1305::new_from_slice(key.as_ref()).expect("correct key"); 50 | let nonce = ChaCha20Poly1305::generate_nonce(OsRng {}); 51 | let ciphertext = cipher.encrypt(&nonce, data).expect("encryption"); 52 | let mut buf = vec![0]; 53 | buf.extend_from_slice(&nonce); 54 | buf.extend_from_slice(&ciphertext); 55 | general_purpose::STANDARD.encode(buf) 56 | } 57 | 58 | /// Decode using base64 and decrypt using ChaCha20Poly1305 59 | /// The first byte is a version byte, the next 12 bytes are the nonce 60 | /// (see https://docs.walletconnect.com/2.0/specs/clients/core/crypto/crypto-envelopes#type-0-envelope) 61 | pub fn decode_decrypt(key: &Key, data: &str) -> Result, ()> { 62 | let decoded = general_purpose::STANDARD.decode(data).map_err(|_| ())?; 63 | let cipher = ChaCha20Poly1305::new_from_slice(key.as_ref()).expect("correct key"); 64 | let nonce = Nonce::clone_from_slice(&decoded[1..13]); 65 | cipher.decrypt(&nonce, &decoded[13..]).map_err(|_| ()) 66 | } 67 | 68 | #[cfg(test)] 69 | mod test { 70 | use quickcheck_macros::quickcheck; 71 | 72 | use crate::crypto::Key; 73 | 74 | use super::{decode_decrypt, derive_symkey_topic, encrypt_and_encode}; 75 | 76 | #[test] 77 | pub fn test_derive_topic() { 78 | const TOPIC: &str = "f22533e8a398c465569c04c14b853c86b63ad94ffa916861eb138819c8be475f"; 79 | let dapp_secret: [u8; 32] = [ 80 | 200, 220, 234, 171, 234, 100, 13, 117, 72, 152, 79, 140, 112, 46, 98, 203, 46, 82, 181, 81 | 132, 149, 158, 189, 217, 78, 224, 11, 145, 159, 235, 198, 115, 82 | ]; 83 | let key = Key::from_raw(dapp_secret); 84 | let Some((topic, _)) = derive_symkey_topic(TOPIC, &key) else { 85 | panic!("can't derive topic") 86 | }; 87 | assert_eq!( 88 | topic.as_ref(), 89 | "1630ba5249b23659ee3d7e5f5561b784710bc50a0ef50869c774c831b68452d0" 90 | ); 91 | } 92 | 93 | #[quickcheck] 94 | fn encode_decode_encrypt_decrypt(data: Vec) -> bool { 95 | let key = Key::random(); 96 | data == decode_decrypt(&key, &encrypt_and_encode(&key, &data)).unwrap() 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /wallet-connect/src/uri.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use crate::crypto::Key; 4 | use crate::protocol::Topic; 5 | use qrcodegen::{QrCode, QrCodeEcc}; 6 | use thiserror::Error; 7 | use url::Url; 8 | 9 | /// The WalletConnect 1.0 connection information that's to be passed to the wallets 10 | #[derive(Clone, Debug, Eq, PartialEq)] 11 | pub struct Uri { 12 | handshake_topic: Topic, 13 | version: u64, 14 | bridge: Url, 15 | key: Key, 16 | url: Url, 17 | } 18 | 19 | const VERSION: u64 = 1; 20 | 21 | /// use as_url().as_str().to_string() for qrcode generation 22 | /// Prints the given QrCode object to the console. 23 | fn print_qr(qr: &QrCode) { 24 | let border: i32 = 1; 25 | for y in -border..qr.size() + border { 26 | for x in -border..qr.size() + border { 27 | let c = if qr.get_module(x, y) { 28 | "\x1b[40m \x1b[0m" 29 | } else { 30 | "\x1b[47m \x1b[0m" 31 | }; 32 | print!("{c}"); 33 | } 34 | println!(); 35 | } 36 | println!(); 37 | } 38 | 39 | impl Uri { 40 | /// prints the URI + its QR code representation in a console 41 | pub fn print_qr_uri(&self) { 42 | println!("session uri: {}", self.url); 43 | if let Ok(qr) = QrCode::encode_text(self.url.as_str(), QrCodeEcc::Medium) { 44 | print_qr(&qr); 45 | } else { 46 | eprintln!("failed to encode URI as a QR code"); 47 | } 48 | } 49 | 50 | /// parse the given URI from a string 51 | pub fn parse(uri: impl AsRef) -> Result { 52 | let url = Url::parse(uri.as_ref())?; 53 | if url.scheme() != "wc" { 54 | return Err(InvalidSessionUri); 55 | } 56 | 57 | let mut path = url.path().splitn(2, '@'); 58 | let handshake_topic = path.next().ok_or(InvalidSessionUri)?.parse()?; 59 | let version = path.next().ok_or(InvalidSessionUri)?.parse()?; 60 | if version != VERSION { 61 | return Err(InvalidSessionUri); 62 | } 63 | 64 | let mut bridge: Option = None; 65 | let mut key: Option = None; 66 | for (name, value) in url.query_pairs() { 67 | match &*name { 68 | "bridge" => bridge = Some(value.parse()?), 69 | "key" => key = Some(value.parse()?), 70 | _ => return Err(InvalidSessionUri), 71 | } 72 | } 73 | 74 | Ok(Uri { 75 | handshake_topic, 76 | version, 77 | bridge: bridge.ok_or(InvalidSessionUri)?, 78 | key: key.ok_or(InvalidSessionUri)?, 79 | url, 80 | }) 81 | } 82 | 83 | /// the topic used in the initial session request 84 | pub fn handshake_topic(&self) -> &Topic { 85 | &self.handshake_topic 86 | } 87 | 88 | /// version -- 1 for 1.0 89 | pub fn version(&self) -> u64 { 90 | self.version 91 | } 92 | 93 | /// the bridge server URL 94 | pub fn bridge(&self) -> &Url { 95 | &self.bridge 96 | } 97 | 98 | /// the symmetric key used to encrypt the requests/responses 99 | /// between the client and wallet 100 | pub fn key(&self) -> &Key { 101 | &self.key 102 | } 103 | 104 | /// returns the handshake topic, the bridge server URL, and the key 105 | pub fn into_parts(self) -> (Topic, Url, Key) { 106 | (self.handshake_topic, self.bridge, self.key) 107 | } 108 | 109 | /// returns the full URI as a URL string 110 | pub fn as_url(&self) -> &Url { 111 | &self.url 112 | } 113 | } 114 | 115 | /// The error type for invalid session URIs 116 | #[derive(Clone, Copy, Debug, Eq, Error, PartialEq)] 117 | #[error("session URI is invalid")] 118 | pub struct InvalidSessionUri; 119 | 120 | macro_rules! impl_invalid_session_uri_from { 121 | ($err:ty) => { 122 | impl From<$err> for InvalidSessionUri { 123 | fn from(_: $err) -> Self { 124 | InvalidSessionUri 125 | } 126 | } 127 | }; 128 | } 129 | 130 | impl_invalid_session_uri_from!(ethers::utils::hex::FromHexError); 131 | impl_invalid_session_uri_from!(std::num::ParseIntError); 132 | impl_invalid_session_uri_from!(url::ParseError); 133 | impl_invalid_session_uri_from!(uuid::Error); 134 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Conduct 4 | ### Contact: https://airtable.com/shrCt6wWy87WrEXr8 5 | 6 | * We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. 7 | 8 | * On communication channels, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. 9 | 10 | * Please be kind and courteous. There’s no need to be mean or rude. 11 | 12 | * Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. 13 | 14 | * Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. 15 | 16 | * We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behavior that excludes people in socially marginalized groups. 17 | 18 | * Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the communication channel admins or the email mentioned above immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back. 19 | 20 | * Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome. 21 | 22 | 23 | ---- 24 | 25 | 26 | ## Moderation 27 | These are the policies for upholding our community’s standards of conduct. If you feel that a thread needs moderation, please contact the above mentioned person. 28 | 29 | 1. Remarks that violate the Crypto.com standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) 30 | 31 | 2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. 32 | 33 | 3. Moderators will first respond to such remarks with a warning. 34 | 35 | 4. If the warning is unheeded, the user will be “kicked,” i.e., kicked out of the communication channel to cool off. 36 | 37 | 5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. 38 | 39 | 6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. 40 | 41 | 7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, in private. Complaints about bans in-channel are not allowed. 42 | 43 | 8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. 44 | 45 | In the Crypto.com developer community we strive to go the extra step to look out for each other. Don’t just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they’re off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. 46 | 47 | And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could’ve communicated better — remember that it’s your responsibility to make your fellow Crypto.com developer community members comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. 48 | 49 | The enforcement policies listed above apply to all official Crypto.com venues. For other projects adopting the Crypto.com Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion. 50 | 51 | * Adapted from the the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html), the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](http://contributor-covenant.org/version/1/3/0/). -------------------------------------------------------------------------------- /demo/server.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const ws = require('ws'); 3 | const http = require('http'); 4 | const EventEmitter = require("events"); 5 | 6 | // The local test port exposed by ngrok 7 | const webhook_port = process.env.PAY_WEBHOOK_PORT; 8 | const host = '127.0.0.1'; 9 | // You can subscribe to the events by going to your Merchant Dashboard and add a new webhook 10 | // subscription. Retrieve your endpoint’s Signature Secret from your Merchant Dashboard's 11 | // Webhooks settings 12 | // Webhook `SIGNATURE SECRET` of one of the `PAYLOAD URL`s 13 | const SIGNATURE_SECRET = process.env.PAY_WEBHOOK_SIGNATURE_SECRET; 14 | // tolerance between the current timestamp and the received timestamp in seconds 15 | const timestamp_tolerance = 2; 16 | 17 | // create a http server 18 | const server = http.createServer(http_request_listener); 19 | // create a ws server by sharing a http server 20 | const wss = new ws.WebSocketServer({ server }); 21 | // create an event emitter 22 | const eventEmitter = new EventEmitter(); 23 | 24 | function http_request_listener(request, response) { 25 | let pay_signature = request.headers['pay-signature']; 26 | if (pay_signature != undefined && pay_signature.split(',').length > 1) { 27 | console.log(request.headers); 28 | let pay_signature_array = pay_signature.split(','); 29 | 30 | let timestamp = ''; 31 | let signatures = []; 32 | 33 | // The Pay-Signature header contains a timestamp and one or more signatures. The timestamp 34 | // is prefixed by t=, and each signature is prefixed by a scheme. Schemes start with v1. 35 | // 36 | // To prevent downgrade attacks, you should ignore all schemes that are not v1. 37 | for (ele of pay_signature_array) { 38 | let ele_array = ele.split('='); 39 | if (ele_array.length == 2) { 40 | if (ele_array[0] == 't') { 41 | timestamp = ele_array[1]; 42 | } else if (ele_array[0] == 'v1') { 43 | signatures.push(ele_array[1]); 44 | } 45 | } 46 | } 47 | 48 | if (timestamp == '' || signatures.length == 0) { 49 | eventEmitter.emit('error', 'Invalid pay signture'); 50 | } else if (request.method == 'POST') { 51 | var body = ''; 52 | request.on('data', function (data) { 53 | body += data; 54 | }); 55 | request.on('end', function () { 56 | console.log(body); 57 | // Compute an HMAC with the SHA256 hash function. Use the endpoint’s Signature Secret 58 | // as the key, and use the aforesaid concatenated string as the message. 59 | const hash = crypto.createHmac('sha256', SIGNATURE_SECRET) 60 | .update(`${timestamp}.${body}`) 61 | .digest(); 62 | 63 | // TODO In this example, we only compare one signature: suppose only one signature in 64 | // `pay-signature`. 65 | const sig = Buffer.from(signatures[0], 'hex'); 66 | 67 | // To protect against timing attacks, use a constant-time string comparison to compare 68 | // the expected signature to each of the received signatures. 69 | if (crypto.timingSafeEqual(hash, sig)) { 70 | let current_timestamp = Math.floor(new Date().getTime() / 1000); 71 | let timestamp_difference = current_timestamp - timestamp; 72 | // Additionally, you may compute the difference between the current timestamp and the 73 | // received timestamp, then decide if the difference is within your tolerance. 74 | if (timestamp_difference <= timestamp_tolerance) { 75 | response.writeHead(200, { 'Content-Type': 'text/html' }); 76 | response.end('post received'); 77 | console.log("Valid webhook request"); 78 | eventEmitter.emit('event', body); 79 | } else { 80 | eventEmitter.emit('error', `Expired webhook request: ${timestamp_difference} > ${timestamp_tolerance}`); 81 | } 82 | } else { 83 | eventEmitter.emit('error', 'Invalid Signture'); 84 | } 85 | }); 86 | }; 87 | 88 | } else { 89 | eventEmitter.emit('error', 'Invalid webhook request: no pay-signature in header'); 90 | } 91 | } 92 | 93 | let websocket = null; 94 | // handle the websocket client connection (e.g. from c++ client) 95 | wss.on('connection', function wss_connection_listener(ws, req) { 96 | console.log(`Client ws://${req.socket.remoteAddress}:${req.socket.remotePort} connected`); 97 | // get ws after detecting connenction event 98 | websocket = ws; 99 | websocket.on('message', function message(data) { 100 | console.log('received: %s', data); 101 | }); 102 | 103 | }); 104 | 105 | eventEmitter.on('event', function status(data) { 106 | if (websocket) { 107 | websocket.send(`${data}`); 108 | } 109 | }); 110 | 111 | eventEmitter.on('error', function status(msg) { 112 | console.error(msg); 113 | if (websocket) { 114 | websocket.send(`error: ${msg}`); 115 | } 116 | }); 117 | 118 | server.listen(webhook_port, host); 119 | console.log(`Listening at http://${host}:${webhook_port}`); 120 | -------------------------------------------------------------------------------- /demo/examples/src/erc721.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace org::defi_wallet_core; 8 | 9 | int main(int argc, char *argv[]) { 10 | rust::Box signer1_wallet = restore_wallet( 11 | "shed crumble dismiss loyal latin million oblige gesture " 12 | "shrug still oxygen custom remove ribbon disorder palace " 13 | "addict again blanket sad flock consider obey popular", 14 | ""); 15 | rust::String signer1_address = signer1_wallet->get_eth_address(0); 16 | rust::Box signer1_privatekey = 17 | signer1_wallet->get_key("m/44'/60'/0'/0/0"); 18 | 19 | rust::Box signer2_wallet = 20 | restore_wallet("night renew tonight dinner shaft scheme domain oppose " 21 | "echo summer broccoli agent face guitar surface belt " 22 | "veteran siren poem alcohol menu custom crunch index", 23 | ""); 24 | rust::String signer2_address = signer2_wallet->get_eth_address(0); 25 | rust::Box signer2_privatekey = 26 | signer2_wallet->get_key("m/44'/60'/0'/0/0"); 27 | 28 | rust::Box validator1_wallet = restore_wallet( 29 | "visit craft resemble online window solution west chuckle " 30 | "music diesel vital settle comic tribe project blame bulb " 31 | "armed flower region sausage mercy arrive release", 32 | ""); 33 | rust::String validator1_address = validator1_wallet->get_eth_address(0); 34 | rust::Box validator1_privatekey = 35 | validator1_wallet->get_key("m/44'/60'/0'/0/0"); 36 | 37 | Erc721 erc721 = new_erc721("0x2305f3980715c9D247455504080b41072De38aB9", 38 | "http://127.0.0.1:26651", 777) 39 | .legacy(); 40 | assert(erc721.name() == "GameItem"); 41 | assert(erc721.symbol() == "ITM"); 42 | assert(erc721.token_uri("1") == "https://game.example/item-id-8u5h2m.json"); 43 | // cout << "Total Supply of ERC721=" << erc721.total_supply() << endl; // 44 | // the contract must support IERC721Enumerable 45 | assert(erc721.owner_of("1") == signer1_address); 46 | assert(erc721.balance_of(signer1_address) == u256("1")); 47 | 48 | // transfer erc721 from signer1 to signer2 49 | rust::String status = erc721 50 | .transfer_from(signer1_address, signer2_address, 51 | "1", *signer1_privatekey) 52 | .status; 53 | assert(status == "1"); 54 | assert(erc721.balance_of(signer1_address) == u256("0")); 55 | assert(erc721.owner_of("1") == signer2_address); 56 | 57 | // safe transfer erc721 from signer2 to signer1 58 | status = erc721 59 | .safe_transfer_from(signer2_address, signer1_address, "1", 60 | *signer2_privatekey) 61 | .status; 62 | assert(status == "1"); 63 | assert(erc721.balance_of(signer1_address) == u256("1")); 64 | assert(erc721.owner_of("1") == signer1_address); 65 | 66 | assert(erc721.balance_of(signer1_address) == u256("1")); 67 | assert(erc721.get_approved("1") == 68 | "0x0000000000000000000000000000000000000000"); 69 | // toggle set_approval_for_all 70 | assert(erc721.is_approved_for_all(signer1_address, signer2_address) == 0); 71 | erc721.set_approval_for_all(signer2_address, true, *signer1_privatekey); 72 | assert(erc721.is_approved_for_all(signer1_address, signer2_address) == 1); 73 | erc721.set_approval_for_all(signer2_address, false, *signer1_privatekey); 74 | assert(erc721.is_approved_for_all(signer1_address, signer2_address) == 0); 75 | 76 | // signer1 approve singer2 to transfer erc721 77 | erc721.approve(signer2_address, "1", *signer1_privatekey); 78 | assert(erc721.get_approved("1") == signer2_address); 79 | 80 | // safe transfer erc721 from signer1 to validator1 81 | status = erc721 82 | .safe_transfer_from(signer1_address, validator1_address, "1", 83 | *signer2_privatekey) 84 | .status; 85 | assert(status == "1"); 86 | assert(erc721.balance_of(validator1_address) == u256("1")); 87 | assert(erc721.owner_of("1") == validator1_address); 88 | 89 | // validator1 set_approval_for_all for singer2 to transfer all assets 90 | assert(erc721.is_approved_for_all(validator1_address, signer2_address) == 91 | 0); 92 | erc721.set_approval_for_all(signer2_address, true, *validator1_privatekey); 93 | assert(erc721.is_approved_for_all(validator1_address, signer2_address) == 94 | 1); 95 | // safe transfer erc721 from validator1 to signer1 96 | status = erc721 97 | .safe_transfer_from(validator1_address, signer1_address, "1", 98 | *signer2_privatekey) 99 | .status; 100 | assert(status == "1"); 101 | assert(erc721.balance_of(signer1_address) == u256("1")); 102 | assert(erc721.owner_of("1") == signer1_address); 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /demo/Makefile: -------------------------------------------------------------------------------- 1 | # Compile with g++: make CXX=g++ 2 | # Compile with clang++: make CXX=clang++ 3 | # Compile with default compiler: make 4 | UNAME := $(shell uname) 5 | sdk_dir = ./sdk 6 | 7 | GCC_CXXFLAGS = 8 | CLANG_CXXFLAGS = -stdlib=libc++ 9 | DEFAULT_CXXFLAGS = 10 | 11 | ifeq ($(CXX),g++) 12 | CXXFLAGS += $(GCC_CXXFLAGS) 13 | else ifneq (,$(findstring clang,$(CXX))) 14 | CXXFLAGS += $(CLANG_CXXFLAGS) 15 | else 16 | CXXFLAGS += $(DEFAULT_CXXFLAGS) 17 | endif 18 | 19 | ifeq ($(shell uname -m), x86_64) 20 | ifeq ($(UNAME), Darwin) 21 | ifeq ($(USE_ARM64),true) 22 | CXX = clang++ -target arm64-apple-darwin # for arm64, we only use clang++ 23 | TARGET_DIR = ../target/aarch64-apple-darwin/release 24 | else 25 | CXX = arch -x86_64 clang++ # for intel, we only use clang++ 26 | TARGET_DIR = ../target/release 27 | endif 28 | else 29 | TARGET_DIR = ../target/release 30 | endif 31 | else 32 | ifeq ($(shell uname -m), arm64) 33 | ifeq ($(UNAME), Darwin) 34 | ifeq ($(USE_ARM64),true) 35 | CXX = clang++ # for arm64, we only use clang++ 36 | TARGET_DIR = ../target/release 37 | else 38 | CXX = arch -x86_64 clang++ # for intel, we only use clang++ 39 | TARGET_DIR = ../target/x86_64-apple-darwin/release 40 | endif 41 | endif 42 | else 43 | TARGET_DIR = ../target/release 44 | endif 45 | endif 46 | 47 | ifeq ($(UNAME), Darwin) 48 | FLAGS=$(CXXFLAGS) -framework Security -framework CoreFoundation -framework SystemConfiguration 49 | endif 50 | 51 | ifeq ($(UNAME), Linux) 52 | FLAGS=$(CXXFLAGS) -lpthread -ldl -lrt 53 | endif 54 | 55 | all: clean clone build 56 | build: prepare static dynamic cmake 57 | run: run_static run_dynamic run_examples 58 | 59 | # TARGET is specified in ../Makefile 60 | # for example, 61 | # Run `make aarch64-linux-android`, `TARGET` is `aarch64-linux-android` 62 | android_build: TARGET_DIR=../target/$(TARGET)/release 63 | android_build: prepare 64 | 65 | ios_build: TARGET_DIR=../target/$(TARGET)/release 66 | ios_build: prepare 67 | 68 | clone: 69 | git submodule update --init --recursive 70 | 71 | prepare: 72 | python3 helper.py --target_dir $(TARGET_DIR) 73 | 74 | easywsclient.o: 75 | $(CXX) -c third_party/easywsclient/easywsclient.cpp $(CXXFLAGS) 76 | 77 | # wrapper of libplay_cpp_sdk.a 78 | libplay_cpp_sdk.so: 79 | ifeq ($(UNAME), Linux) 80 | $(CXX) -fPIC -shared -o $(sdk_dir)/lib/libplay_cpp_sdk.so \ 81 | $(sdk_dir)/include/*.cc \ 82 | $(sdk_dir)/include/extra-cpp-bindings/src/*.cc \ 83 | $(sdk_dir)/include/defi-wallet-core-cpp/src/*.cc \ 84 | $(sdk_dir)/lib/libcxxbridge1.a \ 85 | $(sdk_dir)/lib/libplay_cpp_sdk.a \ 86 | $(FLAGS) 87 | endif 88 | 89 | # add rpath to dylib 90 | libplay_cpp_sdk.dylib: 91 | ifeq ($(UNAME), Darwin) 92 | install_name_tool -id @rpath/libplay_cpp_sdk.dylib $(sdk_dir)/lib/libplay_cpp_sdk.dylib 93 | endif 94 | 95 | static: easywsclient.o 96 | mkdir -p bin 97 | ifeq ($(MSYSTEM), MINGW64) 98 | $(CXX) -o bin/demostatic \ 99 | easywsclient.o \ 100 | main.cc \ 101 | chainmain.cc \ 102 | cronos.cc \ 103 | extra.cc \ 104 | $(sdk_dir)/lib/libplay_cpp_sdk.a \ 105 | -lws2_32 -lntdll \ 106 | -lcrypt32 -lsecur32 -lbcrypt -luserenv -lncrypt \ 107 | -std=c++14 $(FLAGS) 108 | else 109 | $(CXX) -o bin/demostatic \ 110 | easywsclient.o \ 111 | main.cc \ 112 | chainmain.cc \ 113 | cronos.cc \ 114 | extra.cc \ 115 | $(sdk_dir)/lib/libplay_cpp_sdk.a \ 116 | -std=c++14 $(FLAGS) 117 | endif 118 | 119 | dynamic: easywsclient.o libplay_cpp_sdk.so libplay_cpp_sdk.dylib 120 | mkdir -p bin 121 | ifeq ($(UNAME), Linux) 122 | $(CXX) -o bin/demo \ 123 | easywsclient.o \ 124 | main.cc \ 125 | chainmain.cc \ 126 | cronos.cc \ 127 | extra.cc \ 128 | $(sdk_dir)/lib/libplay_cpp_sdk.so \ 129 | -std=c++14 $(FLAGS) 130 | endif 131 | ifeq ($(UNAME), Darwin) 132 | $(CXX) -o bin/demo \ 133 | easywsclient.o \ 134 | main.cc \ 135 | chainmain.cc \ 136 | cronos.cc \ 137 | extra.cc \ 138 | $(sdk_dir)/include/*.cc \ 139 | $(sdk_dir)/include/extra-cpp-bindings/src/*.cc \ 140 | $(sdk_dir)/include/defi-wallet-core-cpp/src/*.cc \ 141 | $(sdk_dir)/lib/libcxxbridge1.a \ 142 | $(sdk_dir)/lib/libplay_cpp_sdk.dylib \ 143 | -rpath $(sdk_dir)/lib \ 144 | -std=c++14 $(FLAGS) 145 | endif 146 | 147 | cmake: 148 | # if mac and arm64 do nothing 149 | ifeq ($(USE_ARM64),true) 150 | echo "skip cmake" 151 | else 152 | mkdir -p build 153 | cd build && CXX="$(CXX)" CXXFLAGS=$(CXXFLAGS) cmake .. && make 154 | endif 155 | run_static: 156 | . ./.env && ./bin/demostatic && ./build/demostatic 157 | 158 | run_dynamic: 159 | . ./.env && export LD_LIBRARY_PATH=$(PWD)/lib && ./bin/demo && ./build/demo 160 | 161 | run_examples: 162 | ./build/examples/new_wallet 163 | ./build/examples/restore_wallet 164 | # . .env && ./build/examples/get_erc20_transfer_history_blocking 165 | # . .env && ./build/examples/get_erc721_transfer_history_blocking 166 | ./build/examples/get_tokens_blocking 167 | ./build/examples/get_token_transfers_blocking 168 | ./build/examples/get_token_transfers_blocking 169 | ./build/examples/wallet_connect 170 | ./build/examples/unit 171 | ./build/examples/get_wallet 172 | 173 | clean: 174 | rm -rf easywsclient.o bin build 175 | 176 | # clean-artifacts can not be run if user uses prebuilt binaries and bindings 177 | clean-artifacts: 178 | rm -rf $(sdk_dir)/lib 179 | rm -rf $(sdk_dir)/include 180 | -------------------------------------------------------------------------------- /wallet-connect/src/crypto/aead.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use crate::protocol::EncryptionPayload; 4 | use aes::{ 5 | cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, InvalidLength, KeyIvInit}, 6 | Aes256, 7 | }; 8 | use hmac::{Hmac, Mac}; 9 | use rand::{rngs::OsRng, Rng}; 10 | use sha2::Sha256; 11 | use subtle::ConstantTimeEq; 12 | use thiserror::Error; 13 | 14 | type HmacSha256 = Hmac; 15 | type Aes256CbcEnc = cbc::Encryptor; 16 | type Aes256CbcDec = cbc::Decryptor; 17 | 18 | fn hmac_sha256(key: &[u8], iv: &[u8], data: &[u8]) -> Vec { 19 | let mut mac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size"); 20 | mac.update(data); 21 | mac.update(iv); 22 | let result = mac.finalize(); 23 | 24 | let code_bytes = result.into_bytes(); 25 | code_bytes.to_vec() 26 | } 27 | 28 | fn generate_iv() -> Vec { 29 | let mut iv = vec![0; 16]; 30 | OsRng.fill(&mut iv[..]); 31 | iv 32 | } 33 | 34 | /// Encrypts the given data with the given key and a randomly generated nonce, 35 | /// and computes HMAC-SHA256 of the encrypted data and the nonce. 36 | /// The cryptographic choices are due to WalletConnect 1.0: https://docs.walletconnect.com/tech-spec#cryptography 37 | pub fn seal(key: &[u8], plaintext: &[u8]) -> EncryptionPayload { 38 | let iv = generate_iv(); 39 | // FIXME: return result or document assumption that a valid key length is passed? 40 | let cipher = Aes256CbcEnc::new_from_slices(key, &iv).unwrap(); 41 | let data = cipher.encrypt_padded_vec_mut::(plaintext); 42 | let hmac = hmac_sha256(key, &iv, &data); 43 | EncryptionPayload { data, iv, hmac } 44 | } 45 | 46 | /// Checks HMAC and if valid, decrypts the data with the given key. 47 | /// The cryptographic choices are due to WalletConnect 1.0: https://docs.walletconnect.com/tech-spec#cryptography 48 | pub fn open(key: &[u8], payload: &EncryptionPayload) -> Result, OpenError> { 49 | let hmac = hmac_sha256(key, &payload.iv, &payload.data); 50 | if hmac.ct_eq(&payload.hmac).unwrap_u8() == 0 { 51 | return Err(OpenError::Verify); 52 | } 53 | let cipher = Aes256CbcDec::new_from_slices(key, &payload.iv)?; 54 | let plaintext = cipher 55 | .decrypt_padded_vec_mut::(&payload.data) 56 | .map_err(|_| OpenError::DecryptionError)?; 57 | Ok(plaintext) 58 | } 59 | 60 | /// Errors that can occur when opening a sealed payload. 61 | #[derive(Debug, Error)] 62 | pub enum OpenError { 63 | #[error("invalid key length: {0}")] 64 | InvalidEncryption(#[from] InvalidLength), 65 | #[error("decryption error")] 66 | DecryptionError, 67 | #[error("unable to verify integrity of payload")] 68 | Verify, 69 | } 70 | 71 | #[cfg(test)] 72 | mod tests { 73 | use super::*; 74 | use crate::crypto::Key; 75 | use crate::hex; 76 | use std::str; 77 | 78 | #[test] 79 | fn roundtrip() { 80 | let message = "walletconnect-rs"; 81 | let key = Key::random(); 82 | 83 | let payload = seal(key.as_ref(), message.as_bytes()); 84 | let plaintext = open(key.as_ref(), &payload).unwrap(); 85 | 86 | assert_eq!(str::from_utf8(&plaintext).unwrap(), message); 87 | } 88 | 89 | #[test] 90 | fn open_payload() { 91 | // Test vector retrieved by inspecting a WalletConnect session with 92 | // https://example.walletconnect.org 93 | 94 | let key = hex::decode("26075c07b19284e193101d7f27d7f96aa1802645663110a47c5c3bd3da580cae") 95 | .unwrap(); 96 | let payload = EncryptionPayload { 97 | data: hex::decode( 98 | "61e66ba15a7cd452fe14a47ab47a0b49b5deb8bffb9b24c736539600a808a107\ 99 | 98b573ca1c8353e585d95866cd1f2756fef5b0ea334fca5a8f877322712e0b97\ 100 | 33b75400c199212c741bf973c11d3b797f5fb0f413db8a939cfddc4bf8dc96dd\ 101 | 62c01237c8e7038c93f8dbd7d14d22ea82b568cc45fadb3face32350847985cb\ 102 | 57a3e70cb520fe987544084ae125d7913de81c3e7e6e88039ef40cc4b19be1a7\ 103 | 90b6c5509d0822acb7f2bc6d83de528c8f787e29906c5f7ec50d7a8f7b36796f\ 104 | a3b44edc3538ca6ac039cd17714c50f63b6b9788d3860195e094e571a2a5dba9\ 105 | b74c8065c04aad11bce2545eb19bd94ad0ee261195b8fa0a738442983d6415a8\ 106 | 81d5d8cd69c07088eb4d979082762c429a3a7ac7d84a4eec84a5144a8675a0e4\ 107 | 094dc1fbc243def3edb2fd15196aa19bce82bedd955126992ff7d952a735a889", 108 | ) 109 | .unwrap(), 110 | hmac: hex::decode("1ff024bb7234f3b514b0e0ee130d81f1a367ec09fc2cf191ab52ed07e1f8bbe9") 111 | .unwrap(), 112 | iv: hex::decode("019dc30e6463c2c1acd165310d686553").unwrap(), 113 | }; 114 | let message = r#"{"id":1580823313241457,"jsonrpc":"2.0","method":"wc_sessionRequest","params":[{"peerId":"e8526892-8e47-42e4-9ea3-20c0b164bb83","peerMeta":{"description":"","url":"https://example.walletconnect.org","icons":["https://example.walletconnect.org/favicon.ico"],"name":"WalletConnect Example"},"chainId":null}]}"#; 115 | 116 | let plaintext = open(&key, &payload).unwrap(); 117 | assert_eq!(str::from_utf8(&plaintext).unwrap(), message); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for your interest in contributing to Cronos Play C++ SDK! Good places to start are this document and the materials linked in README. If you have any questions, feel free to ask on [GitHub Discussions](https://github.com/crypto-com/play-cpp-sdk/discussions/landing). 4 | 5 | 6 | ## Code of Conduct 7 | 8 | All contributors are expected to follow our [Code of Conduct](CODE_OF_CONDUCT.md). 9 | 10 | ## Feature requests and bug reports 11 | 12 | Feature requests and bug reports should be posted as [Github issues](issues/new). 13 | In an issue, please describe what you did, what you expected, and what happened instead. 14 | 15 | If you think that you have identified an issue with Cronos Play C++ SDK that might compromise 16 | its users' security, please do not open a public issue on GitHub. Instead, 17 | we ask you to refer to [security policy](SECURITY.md). 18 | 19 | ## Working on issues 20 | There are several ways to identify an area where you can contribute to Cronos Play C++ SDK: 21 | 22 | * You can reach out by sending a message in the developer community communication channel, either with a specific contribution in mind or in general by saying "I want to help!". 23 | * Occasionally, some issues on Github may be labelled with `help wanted` or `good first issue` tags. 24 | 25 | We use the variation of the "fork and pull" model where contributors push changes to their personal fork and create pull requests to bring those changes into the source repository. 26 | Changes in pull requests should satisfy "Patch Requirements" described in [The Collective Code Construction Contract (C4)](https://rfc.zeromq.org/spec:42/C4/#23-patch-requirements). The code should follow [Rust Style Guide](https://github.com/rust-lang/rfcs/tree/master/style-guide). Many of the code style rules are captured by [rustfmt](https://github.com/rust-lang/rustfmt), so please make sure to use `cargo fmt` before every commit (e.g. by configuring your editor to do it for you upon saving a file). The code comments should follow [Rust API Documentation guidelines and conventions](https://rust-lang-nursery.github.io/api-guidelines/documentation.html). 27 | 28 | Once you identified an issue to work on, this is the summary of your basic steps: 29 | 30 | * Fork Cronos Play C++ SDK's repository under your Github account. 31 | 32 | * Clone your fork locally on your machine. 33 | 34 | * Post a comment in the issue to say that you are working on it, so that other people do not work on the same issue. 35 | 36 | * Create a local branch on your machine by `git checkout -b branch_name`. 37 | 38 | * Commit your changes to your own fork -- see [C4 Patch Requirements](https://rfc.zeromq.org/spec:42/C4/#23-patch-requirements) for guidelines. 39 | 40 | * Include tests that cover all non-trivial code. 41 | 42 | * Check you are working on the latest version on main in Cronos Play C++ SDK's official repository. If not, please pull Cronos Play C++ SDK's official repository's main (upstream) into your fork's main branch, and rebase your committed changes or replay your stashed changes in your branch over the latest changes in the upstream version. 43 | 44 | * Run all tests locally and make sure they pass. 45 | 46 | * If your changes are of interest to other developers, please make corresponding changes in the official documentation and the changelog. 47 | 48 | * Push your changes to your fork's branch and open the pull request to Cronos Play C++ SDK's repository main branch. 49 | 50 | * In the pull request, complete its checklist, add a clear description of the problem your changes solve, and add the following statement to confirm that your contribution is your own original work: "I hereby certify that my contribution is in accordance with the Developer Certificate of Origin (https://developercertificate.org/)." 51 | 52 | * The reviewer will either accept and merge your pull request, or leave comments requesting changes via the Github PR interface (you should then make changes by pushing directly to your existing PR branch). 53 | 54 | ### Developer Certificate of Origin 55 | All contributions to this project are subject to the terms of the Developer Certificate of Origin, available [here](https://developercertificate.org/) and reproduced below: 56 | 57 | ``` 58 | Developer Certificate of Origin 59 | Version 1.1 60 | 61 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 62 | 1 Letterman Drive 63 | Suite D4700 64 | San Francisco, CA, 94129 65 | 66 | Everyone is permitted to copy and distribute verbatim copies of this 67 | license document, but changing it is not allowed. 68 | 69 | Developer's Certificate of Origin 1.1 70 | 71 | By making a contribution to this project, I certify that: 72 | 73 | (a) The contribution was created in whole or in part by me and I 74 | have the right to submit it under the open source license 75 | indicated in the file; or 76 | 77 | (b) The contribution is based upon previous work that, to the best 78 | of my knowledge, is covered under an appropriate open source 79 | license and I have the right under that license to submit that 80 | work with modifications, whether created in whole or in part 81 | by me, under the same open source license (unless I am 82 | permitted to submit under a different license), as indicated 83 | in the file; or 84 | 85 | (c) The contribution was provided directly to me by some other 86 | person who certified (a), (b) or (c) and I have not modified 87 | it. 88 | 89 | (d) I understand and agree that this project and the contribution 90 | are public and that a record of the contribution (including all 91 | personal information I submit with it, including my sign-off) is 92 | maintained indefinitely and may be redistributed consistent with 93 | this project or the open source license(s) involved. 94 | ``` -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | ## [Unreleased] 3 | 4 | ## [v0.0.27-alpha] - 2004-5-22 5 | - fix c++ walletconnect example to use wc 2.0 6 | - add verification for sign_personal 7 | 8 | ## [v0.0.26-alpha] - 2024-4-24 9 | - fix null `data` field in wc 2.0 10 | 11 | ## [v0.0.25-alpha] - 2024-4-23 12 | - support defi-wallet 13 | 14 | ## [v0.0.24-alpha] - 2023-12-4 15 | - fix walletconnect 2.0 send_tx 16 | - add from_address for walletconnect 2.0 sendtx 17 | 18 | ## [v0.0.23-alpha] - 2023-8-7 19 | - add mac universal binary (arm64 + x86_64) 20 | 21 | ## [v0.0.22-alpha] - 2023-7-26 22 | - fix Array in abi json encoding 23 | ## [v0.0.21-alpha] - 2023-6-12 24 | - release arm64 apple 25 | 26 | ## [v0.0.20-alpha] - 2023-5-16 27 | - Use defi-wallet-core-rs v0.3.6 28 | - Add get_eth_transaction_receipt_blocking 29 | - Add wait_for_transaction_receipt_blocking 30 | - get_block_number_blocking 31 | - Update walletconnect 2.0 support 32 | - Add session file 33 | - Add session updates/events 34 | - Use rustls-tls-webpki-roots 35 | 36 | ## [v0.0.19-alpha] - 2023-4-24 37 | - Upgrade ethers to 2.0 38 | - Add msys2 build support 39 | - Add general eip1559 functions for walletconnect 1.0 40 | - sign_transaction 41 | - send_transaction 42 | - Refactor ERC20/721/1155 contract functions to general functions for walletconnect 1.0 43 | - sign_contract_transaction 44 | - send_contract_transaction 45 | 46 | ## [v0.0.18-alpha] - 2023-3-30 47 | - Add eth_sendTransaction support for WalletConnect 1.0 48 | 49 | ## [v0.0.17-alpha] - 2023-3-24 50 | - Support WalletConnect 2.0 (incomplete) 51 | - Upgrade Rust to 1.68 52 | - Remove RUSTFLAGS and libgcc.a workaround for android r23+ 53 | - Upgrade r21 with r23a (23.0.7599858), set minimal sdk to 26 54 | 55 | ## [v0.0.16-alpha] - 2023-3-2 56 | - Update defi-wallet-core 57 | - Support android for secure secret storage option 58 | 59 | ## [v0.0.15-alpha] - 2022-1-19 60 | - Add secure secret storage option 61 | - Update Cronos Play Application Form link 62 | 63 | ## [v0.0.14-alpha] - 2022-12-15 64 | - Add chain-id for DynamicContract send 65 | 66 | ## [v0.0.13-alpha] - 2022-12-13 67 | - Limit walletconnect json rpc pending requests to 2 and timeout to 60 seconds 68 | - Revert to clang 10 for linux builds 69 | 70 | ## [v0.0.12-alpha] - 2022-12-7 71 | - Dynamic Contract C++ Bindings : Encode,Call,Send 72 | - Minting C++ Example : Encode,Send 73 | - Replace custom cxx-build with official cxx-build 74 | - Add walletconnect registry API support 75 | - Add app token for sepgrep CI 76 | - Fix Walletconnect request deadlock issue 77 | - Upgrade ethers to 1.0 78 | ## [v0.0.11-alpha] - 2022-11-14 79 | - Add IOS build 80 | - Update defi-wallet-core-cpp to v0.3.0 81 | 82 | ## [v0.0.10-alpha] - 2022-11-09 83 | - Change erc-20,erc-721,erc-1155 tx to eip-155 84 | - Convert message to hex before being sent for walletconnect personal_sign function 85 | - Added cpp-lint, semgrep and codeql analysis for C++ 86 | 87 | ## [v0.0.9-alpha] - 2022-11-01 88 | - Add optional field chain_id for walletconnect (In C++, 0 = None) 89 | - Add wallet connect with contract calls (modified client to be cloneable) 90 | 91 | ## [v0.0.8-alpha] - 2022-09-13 92 | - Add missing licenses 93 | - Fix QR code can not be detected error 94 | - Rename `setup_callback` as `setup_callback_blocking` 95 | 96 | ## [v0.0.7-alpha] - 2022-08-24 97 | - Add android builds 98 | 99 | ## [v0.0.6-alpha] - 2022-08-17 100 | - Add checksum for linux libc++ release 101 | - Add qrcode api 102 | 103 | ## [v0.0.5-alpha] - 2022-08-12 104 | - Support both g++ and clang 105 | - Add libc++ build for linux Unreal plugin 106 | 107 | ## [v0.0.4-alpha] - 2022-08-10 108 | Add get-backup-mnemonics, generate-mnemonics 109 | 110 | ## [v0.0.3-alpha] - 2022-08-01 111 | Mac release to support 10.15 112 | Fix unicode decode error on windows 11 113 | Update ethers and cxx-build 114 | 115 | ## [v0.0.2-alpha] - 2022-07-18 116 | ### Security Warning 117 | No security audits of this release have ever been performed yet. 118 | 119 | The project is still in development and is alpha quality. 120 | 121 | USE AT YOUR OWN RISK! 122 | 123 | ### Added 124 | - Add CMake support 125 | - Add `get_token_holders` function 126 | - Add examples 127 | 128 | ### Changed 129 | - Replace openssl with `rustls` 130 | - Improve dynamic build for mac (change to rapth using `install_name_tool`) and linux (build a 131 | dynamic library wrapper on a static library) 132 | - Replace the `cargo test` execution with `cargo llvm-cov` 133 | - Replace `grpc-web-client` with `tonic-web-wasm-client` 134 | 135 | ### Removed 136 | 137 | ## [v0.0.1-alpha] - 2022-06-21 138 | ### Security Warning 139 | No security audits of this release have ever been performed yet. 140 | 141 | The project is still in development and is alpha quality. 142 | 143 | USE AT YOUR OWN RISK! 144 | 145 | ### Added 146 | - Add `play-cpp-sdk` crate for building static or dynamic libraries and providing bindings 147 | (headers and sources) for c++ projects 148 | - Add [defi-wallet-core-rs](https://github.com/crypto-com/defi-wallet-core-rs) as submodule, 149 | and one of dependencies of `play-cpp-sdk` crate 150 | - Add `extra-cpp-bindings` as one of dependencies of `play-cpp-sdk` crate 151 | - Add Etherscan/Cronoscan function `get_transaction_history_blocking` for acquiring the 152 | transactions of a given address 153 | - Add Etherscan/Cronoscan function `get_erc20_transfer_history_blocking` for getting the 154 | ERC20 transfers of a given address of a given contract 155 | - Add Etherscan/Cronoscan function `get_erc721_transfer_history_blocking` for getting the 156 | ERC721 transfers of a given address of a given contract 157 | - Add BlockScout function `get_tokens_blocking` returning the list of all owned tokens 158 | - Add BlockScout function `get_token_transfers_blocking` returning all the token transfers 159 | - Add Crypto.com Pay functions `create_payment` and `get_payment` 160 | - Add WalletConnect support 161 | - Add wallet connect function `walletconnect_new_client` to create opaque pointer for wallet-connect 162 | - Add wallet connect function `setup_callback` to setup callbacks for wallet-connect events 163 | - Add wallet connect function `ensure_session_blocking` to ensure that wallet-connnect session is created or restored 164 | - Add wallet connect function `get_connection_string` to get string for qrcode generation 165 | - Add wallet connect function `sign_personal_blocking` to sign general message 166 | - Add wallet connect function `sign_legacy_transaction_blocking` to sign legacy transaction 167 | - Add a `demo` kick-starter project: link, build, and test the apis of the cpp sdk. 168 | -------------------------------------------------------------------------------- /wallet-connect/src/v2/session.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | crypto::derive_symkey_topic, 3 | protocol::{ 4 | Namespaces, OptionalNamespaces, Peer, Relay, RequiredNamespaces, WcSessionPropose, 5 | WcSessionProposeResponse, WcSessionSettle, WcSessionUpdate, 6 | }, 7 | Metadata, 8 | }; 9 | use crate::{crypto::Key, hex}; 10 | use relay_rpc::auth::AuthToken; 11 | use relay_rpc::auth::SerializedAuthToken; 12 | use relay_rpc::auth::{ed25519_dalek::Keypair, rand}; 13 | use relay_rpc::domain::AuthSubject; 14 | use relay_rpc::domain::Topic; 15 | use secrecy::ExposeSecret; 16 | use serde::{Deserialize, Serialize}; 17 | use tokio::time::Duration; 18 | use url::Url; 19 | use x25519_dalek::{PublicKey, StaticSecret}; 20 | use zeroize::Zeroize; 21 | 22 | /// The WalletConnect 2.0 session information 23 | #[derive(Deserialize, Serialize, Debug, Clone)] 24 | #[serde(rename_all = "camelCase")] 25 | pub struct SessionInfo { 26 | /// if the wallet approved the connection 27 | pub connected: bool, 28 | /// namespaces required by the client 29 | pub required_namespaces: RequiredNamespaces, 30 | /// the accounts, methods, and events returned by the wallet 31 | pub namespaces: Option, 32 | /// the relay server URL 33 | pub relay_server: Url, 34 | /// the project id for the walletconnect v2 35 | pub project_id: String, 36 | /// the secret key used in encrypting the session proposal request 37 | pub session_proposal_symkey: Key, 38 | /// this is the client's secret key for a pairing topic derivation 39 | pub client_secret_key: Key, 40 | /// the client metadata (that will be presented to the wallet in the initial request) 41 | pub client_meta: Peer, 42 | /// the topic derived from the wallet's public key 43 | /// and the secret key used in encrypting the paired session requests 44 | pub pairing_topic_symkey: Option<(Topic, Key)>, 45 | /// the wallet's metadata 46 | pub pairing_peer_meta: Option, 47 | /// the one-time request ID 48 | pub session_proposal_topic: Topic, 49 | /// jwt 50 | pub auth_jwt: SerializedAuthToken, 51 | } 52 | 53 | impl SessionInfo { 54 | /// Create a new session info. 55 | /// it will generate a new secret key for the session proposal, 56 | /// a new secret key for the pairing topic, 57 | /// a new topic for the session proposal 58 | /// and prepare the client/peer metadata from it 59 | /// and provided arguments. 60 | pub fn new( 61 | relay_server: Url, // wss://relay.walletconnect.com/ 62 | project_id: String, 63 | required_namespaces: RequiredNamespaces, 64 | metadata: Metadata, 65 | ) -> Self { 66 | let key = Keypair::generate(&mut rand::thread_rng()); 67 | 68 | let mut relay_address = relay_server.to_string(); 69 | // remove "/" 70 | relay_address.pop(); 71 | 72 | let auth_jwt = AuthToken::new(AuthSubject::generate()) 73 | .aud(relay_address.clone()) 74 | .ttl(Duration::from_secs(60 * 60)) 75 | .as_jwt(&key) 76 | .expect("jwt token"); 77 | 78 | let mut client_secret = StaticSecret::new(relay_rpc::auth::rand::thread_rng()); 79 | let client_public = PublicKey::from(&client_secret); 80 | let client_secret_key = Key::from_raw(client_secret.to_bytes()); 81 | client_secret.zeroize(); 82 | let session_proposal_symkey = Key::random(); 83 | 84 | let session_proposal_topic = Topic::generate(); 85 | let client_meta = Peer { 86 | public_key: hex::encode(client_public.as_bytes()), 87 | metadata, 88 | }; 89 | Self { 90 | connected: false, 91 | required_namespaces, 92 | namespaces: None, 93 | relay_server, 94 | project_id, 95 | session_proposal_symkey, 96 | client_secret_key, 97 | client_meta, 98 | pairing_topic_symkey: None, 99 | pairing_peer_meta: None, 100 | session_proposal_topic, 101 | auth_jwt, 102 | } 103 | } 104 | 105 | /// Return the URI for the initial session proposal request 106 | /// (usually displayed in a QR code or used via a deep link). 107 | /// ref: https://docs.walletconnect.com/2.0/specs/clients/core/pairing/pairing-uri 108 | /// 109 | /// FIXME: currently, it doesn't include the "required methods" 110 | /// such as &methods=[wc_sessionPropose],[wc_authRequest,wc_authBatchRequest] 111 | /// but it seems the test react wallet works without it 112 | pub fn uri(&self) -> String { 113 | // FIXME: methods 114 | format!( 115 | "wc:{}@2?symKey={}&relay-protocol=irn", 116 | self.session_proposal_topic, 117 | self.session_proposal_symkey.display().expose_secret() 118 | ) 119 | } 120 | 121 | /// Return the session proposal request payload 122 | pub fn session_proposal(&self) -> WcSessionPropose { 123 | WcSessionPropose { 124 | required_namespaces: self.required_namespaces.clone(), 125 | optional_namespaces: OptionalNamespaces {}, 126 | relays: vec![Relay { 127 | protocol: "irn".to_string(), 128 | }], 129 | proposer: self.client_meta.clone(), 130 | } 131 | } 132 | 133 | /// Update the session based on the session proposal response 134 | /// and return the topic for the pairing topic 135 | /// if the response is valid 136 | pub fn session_proposal_response( 137 | &mut self, 138 | propose_response: &WcSessionProposeResponse, 139 | ) -> Option { 140 | self.pairing_topic_symkey = derive_symkey_topic( 141 | &propose_response.responder_public_key, 142 | &self.client_secret_key, 143 | ); 144 | self.pairing_topic_symkey.as_ref().map(|(x, _)| x.clone()) 145 | } 146 | 147 | /// Update the session based on the session settle response 148 | pub fn session_settle(&mut self, settle: WcSessionSettle) { 149 | self.pairing_peer_meta = Some(settle.controller); 150 | self.namespaces = Some(settle.namespaces); 151 | } 152 | 153 | pub fn session_update(&mut self, info: WcSessionUpdate) { 154 | self.namespaces = Some(info.namespaces); 155 | } 156 | 157 | // FIXME: 7 days 158 | pub fn session_extend(&mut self) {} 159 | 160 | pub fn session_delete(&mut self) { 161 | self.connected = false; 162 | self.pairing_topic_symkey = None; 163 | self.pairing_peer_meta = None; 164 | self.namespaces = None; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /demo/examples/src/erc1155.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace org::defi_wallet_core; 8 | 9 | int main(int argc, char *argv[]) { 10 | rust::Box signer1_wallet = restore_wallet( 11 | "shed crumble dismiss loyal latin million oblige gesture " 12 | "shrug still oxygen custom remove ribbon disorder palace " 13 | "addict again blanket sad flock consider obey popular", 14 | ""); 15 | rust::String signer1_address = signer1_wallet->get_eth_address(0); 16 | rust::Box signer1_privatekey = 17 | signer1_wallet->get_key("m/44'/60'/0'/0/0"); 18 | 19 | rust::Box signer2_wallet = 20 | restore_wallet("night renew tonight dinner shaft scheme domain oppose " 21 | "echo summer broccoli agent face guitar surface belt " 22 | "veteran siren poem alcohol menu custom crunch index", 23 | ""); 24 | rust::String signer2_address = signer2_wallet->get_eth_address(0); 25 | rust::Box signer2_privatekey = 26 | signer2_wallet->get_key("m/44'/60'/0'/0/0"); 27 | 28 | rust::Box validator1_wallet = restore_wallet( 29 | "visit craft resemble online window solution west chuckle " 30 | "music diesel vital settle comic tribe project blame bulb " 31 | "armed flower region sausage mercy arrive release", 32 | ""); 33 | rust::String validator1_address = validator1_wallet->get_eth_address(0); 34 | rust::Box validator1_privatekey = 35 | validator1_wallet->get_key("m/44'/60'/0'/0/0"); 36 | 37 | Erc1155 erc1155 = new_erc1155("0x939D7350c54228e4958e05b65512C4a5BB6A2ACc", 38 | "http://127.0.0.1:26651", 777) 39 | .legacy(); 40 | // To be improved in the contract, now all uri are the same 41 | assert(erc1155.uri("0") == "https://game.example/api/item/{id}.json"); 42 | assert(erc1155.uri("1") == "https://game.example/api/item/{id}.json"); 43 | assert(erc1155.uri("2") == "https://game.example/api/item/{id}.json"); 44 | assert(erc1155.uri("3") == "https://game.example/api/item/{id}.json"); 45 | assert(erc1155.uri("4") == "https://game.example/api/item/{id}.json"); 46 | assert(erc1155.balance_of(signer1_address, "0") == 47 | u256("1000000000000000000")); 48 | assert(erc1155.balance_of(signer1_address, "1") == 49 | u256("1000000000000000000000000000")); 50 | assert(erc1155.balance_of(signer1_address, "2") == u256("1")); 51 | assert(erc1155.balance_of(signer1_address, "3") == u256("1000000000")); 52 | assert(erc1155.balance_of(signer1_address, "4") == u256("1000000000")); 53 | 54 | // safe transfer erc1155 from signer1 to signer2 55 | rust::Vec erc1155_data; 56 | rust::String status = 57 | erc1155.interval(3000) 58 | .safe_transfer_from(signer1_address, signer2_address, "0", "150", 59 | erc1155_data, *signer1_privatekey) 60 | .status; 61 | assert(status == "1"); 62 | assert(erc1155.balance_of(signer1_address, "0") == 63 | u256("999999999999999850")); 64 | 65 | // safe batch transfer erc1155 from signer1 to signer2 66 | rust::Vec token_ids, amounts; 67 | token_ids.push_back("1"); 68 | token_ids.push_back("2"); 69 | token_ids.push_back("3"); 70 | token_ids.push_back("4"); 71 | 72 | amounts.push_back("200"); 73 | amounts.push_back("1"); 74 | amounts.push_back("300"); 75 | amounts.push_back("400"); 76 | status = erc1155 77 | .safe_batch_transfer_from(signer1_address, signer2_address, 78 | token_ids, amounts, erc1155_data, 79 | *signer1_privatekey) 80 | .status; 81 | assert(status == "1"); 82 | assert(erc1155.balance_of(signer1_address, "1") == 83 | u256("999999999999999999999999800")); 84 | assert(erc1155.balance_of(signer1_address, "2") == u256("0")); 85 | assert(erc1155.balance_of(signer1_address, "3") == u256("999999700")); 86 | assert(erc1155.balance_of(signer1_address, "4") == u256("999999600")); 87 | 88 | // toggle set_approval_for_all 89 | assert(erc1155.is_approved_for_all(signer1_address, signer2_address) == 0); 90 | erc1155.set_approval_for_all(signer2_address, true, *signer1_privatekey); 91 | assert(erc1155.is_approved_for_all(signer1_address, signer2_address) == 1); 92 | erc1155.set_approval_for_all(signer2_address, false, *signer1_privatekey); 93 | assert(erc1155.is_approved_for_all(signer1_address, signer2_address) == 0); 94 | // set approval for signer2 95 | erc1155.set_approval_for_all(signer2_address, true, *signer1_privatekey); 96 | assert(erc1155.is_approved_for_all(signer1_address, signer2_address) == 1); 97 | token_ids.clear(); 98 | token_ids.push_back("1"); 99 | token_ids.push_back("3"); 100 | token_ids.push_back("4"); 101 | 102 | amounts.clear(); 103 | amounts.push_back("500"); 104 | amounts.push_back("600"); 105 | amounts.push_back("700"); 106 | // and safe batch transfer from signer1 to validator1 107 | status = erc1155 108 | .safe_batch_transfer_from(signer1_address, validator1_address, 109 | token_ids, amounts, erc1155_data, 110 | *signer2_privatekey) 111 | .status; 112 | assert(status == "1"); 113 | assert(erc1155.balance_of(signer1_address, "1") == 114 | u256("999999999999999999999999300")); 115 | assert(erc1155.balance_of(signer1_address, "2") == u256("0")); 116 | assert(erc1155.balance_of(signer1_address, "3") == u256("999999100")); 117 | assert(erc1155.balance_of(signer1_address, "4") == u256("999998900")); 118 | 119 | assert(erc1155.balance_of(signer2_address, "1") == u256("200")); 120 | assert(erc1155.balance_of(signer2_address, "2") == u256("1")); 121 | assert(erc1155.balance_of(signer2_address, "3") == u256("300")); 122 | assert(erc1155.balance_of(signer2_address, "4") == u256("400")); 123 | 124 | assert(erc1155.balance_of(validator1_address, "1") == u256("500")); 125 | assert(erc1155.balance_of(validator1_address, "2") == u256("0")); 126 | assert(erc1155.balance_of(validator1_address, "3") == u256("600")); 127 | assert(erc1155.balance_of(validator1_address, "4") == u256("700")); 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /wallet-connect/examples/web3.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | use defi_wallet_connect::session::SessionInfo; 4 | use defi_wallet_connect::{Client, Metadata, WCMiddleware}; 5 | use defi_wallet_connect::{ClientChannelMessage, ClientChannelMessageType}; 6 | use ethers::prelude::Middleware; 7 | use ethers::types::H160; 8 | use eyre::eyre; 9 | use std::fs::File; 10 | use std::io::prelude::*; 11 | use url::form_urlencoded; 12 | 13 | /// remove session.json to start new session 14 | const G_FILENAME: &str = "sessioninfo.json"; 15 | 16 | /// temporary session is stored to session.json 17 | async fn make_client() -> Result> { 18 | let filename = G_FILENAME; 19 | if let Ok(mut file) = File::open(filename) { 20 | let mut contents = String::new(); 21 | file.read_to_string(&mut contents)?; 22 | let session: SessionInfo = serde_json::from_str(&contents)?; 23 | let client = Client::restore(session).await?; 24 | println!("restored client"); 25 | Ok(client) 26 | } else { 27 | let client = Client::new( 28 | Metadata { 29 | description: "Defi WalletConnect example.".into(), 30 | url: "http://localhost:8080/".parse().expect("url"), 31 | icons: vec![], 32 | name: "Defi WalletConnect Web3 Example".into(), 33 | }, 34 | // Some(25), // cronos mainnet 35 | None, // up to wallet 36 | ) 37 | .await?; 38 | println!("created client"); 39 | Ok(client) 40 | } 41 | } 42 | 43 | fn write_session_to_file(info: &SessionInfo, filename: &str) -> eyre::Result<()> { 44 | let mut file = std::fs::File::create(filename)?; 45 | let buffer = serde_json::to_string(&info)?; 46 | // write buffer to file 47 | file.write_all(buffer.as_bytes())?; 48 | Ok(()) 49 | } 50 | 51 | async fn eth_sign(client: Client, address: Vec) -> Result<(), Box> { 52 | let middleware = WCMiddleware::new(client); 53 | // Note that `sign` on ethers middleware translate to `eth_sign` JSON-RPC method 54 | // which in Metamask docs is marked as "(insecure and unadvised to use)" 55 | // and some wallets may reject it 56 | let sig2 = middleware 57 | .sign("world".as_bytes().to_vec(), &address[0]) 58 | .await; 59 | match sig2 { 60 | Ok(value) => println!("sig2: {:?}", value), 61 | Err(_error) => println!("not erorr, eth_sign not supported in the wallet"), 62 | } 63 | Ok(()) 64 | } 65 | #[tokio::main] 66 | async fn main() -> Result<(), Box> { 67 | let filename = G_FILENAME; 68 | 69 | let mut client = make_client().await?; 70 | 71 | client 72 | .run_callback(Box::new( 73 | move |message: ClientChannelMessage| -> eyre::Result<()> { 74 | match message.state { 75 | ClientChannelMessageType::Connected => { 76 | println!("Connected"); 77 | if let Some(info) = message.session { 78 | println!("session info: {:?}", info); 79 | write_session_to_file(&info, filename) 80 | } else { 81 | Err(eyre!("no session info")) 82 | } 83 | } 84 | ClientChannelMessageType::Disconnected => { 85 | println!("Disconnected"); 86 | if let Some(info) = message.session { 87 | println!("session info: {:?}", info); 88 | std::fs::remove_file(filename)?; 89 | std::process::exit(0) 90 | } else { 91 | Err(eyre!("no session info")) 92 | } 93 | } 94 | ClientChannelMessageType::Connecting => { 95 | println!("Connecting"); 96 | if let Some(info) = &message.session { 97 | info.uri().print_qr_uri(); 98 | Ok(()) 99 | // write_session_to_file(info, filename) 100 | } else { 101 | Err(eyre!("no session info")) 102 | } 103 | } 104 | ClientChannelMessageType::Updated => { 105 | println!("Updated"); 106 | if let Some(info) = &message.session { 107 | write_session_to_file(info, filename) 108 | } else { 109 | Err(eyre!("no session info")) 110 | } 111 | } 112 | } 113 | }, 114 | )) 115 | .await?; 116 | 117 | // qrcode display 118 | let uri = client.get_connection_string().await?; 119 | println!("connection string = {}", uri); 120 | 121 | let encoded: String = form_urlencoded::Serializer::new(String::new()) 122 | .append_pair("uri", &uri) 123 | .finish(); 124 | 125 | println!("Crypto.com Wallet: cryptowallet://wc?{}", encoded); 126 | open::that(format!("cryptowallet://wc?{}", encoded))?; 127 | 128 | let (address, chain_id) = client.ensure_session().await?; 129 | println!("address: {:?}", address); 130 | println!("chain_id: {}", chain_id); 131 | 132 | let mut client1 = client.clone(); 133 | let address1 = address[0].clone(); 134 | tokio::spawn(async move { 135 | // personal_sign is signing with document 136 | let sig1 = client1.personal_sign("Hello Crypto", &address1).await; 137 | println!("sig1: {:?}", sig1); 138 | }); 139 | 140 | let mut client2 = client.clone(); 141 | let address2 = address[0].clone(); 142 | tokio::spawn(async move { 143 | // personal_sign is signing with document 144 | let sig1 = client2.personal_sign("Hello Dot", &address2).await; 145 | println!("sig1: {:?}", sig1); 146 | }); 147 | 148 | let mut client3 = client.clone(); 149 | let address3 = address[0].clone(); 150 | tokio::spawn(async move { 151 | // personal_sign is signing with document 152 | let sig1 = client3.personal_sign("Hello Com", &address3).await; 153 | println!("sig1: {:?}", sig1); 154 | }); 155 | 156 | // eth_sign is signing directly with hash of message 157 | // because it's not secure and not recommended to use it 158 | // metamask and etc. will reject it, so that is not an error 159 | let client4 = client.clone(); 160 | tokio::spawn(async move { 161 | // personal_sign is signing with document 162 | println!("Hello Crypto.com"); 163 | let sig1 = eth_sign(client4, address).await; 164 | println!("sig1: {:?}", sig1); 165 | }); 166 | loop {} 167 | } 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cronos Play C++ SDK 2 | 3 | This project includes the following crates: 4 | - `play-cpp-sdk`: the cpp sdk wrapper 5 | - `defi-wallet-core-rs`: a dependency of play-cpp-sdk 6 | - `extra-cpp-bindings`: a dependency of play-cpp-sdk 7 | - `wallet-connect`: wallet connect implementation 8 | 9 | ## Security Warning 10 | 11 | No security audits of this project have ever been performed yet. 12 | 13 | The project is still in development and is *alpha* quality. 14 | 15 | USE AT YOUR OWN RISK! 16 | 17 | # Requirements 18 | 1. python 3.8 or newer 19 | 2. rust 1.61 or newer 20 | 3. C++ 14 or newer 21 | 4. Optional: CMake 22 | 5. Optional: GNU make for mac and linux, ninja for windows 23 | 6. Optional: Visual Studio 2019 or newer for windows 24 | 25 | # Pre-built Download 26 | Please download the archive file based on your OS release: 27 | https://github.com/cronos-labs/play-cpp-sdk/releases 28 | 29 | - Visual Studio 2019 MSVC, x86_64, toolset 14.29 or newer: `play_cpp_sdk_Windows_x86_64.zip` 30 | - macOS 10.15 or newer: `play_cpp_sdk_Darwin_x86_64.tar.gz` 31 | - Ubuntu 20.04 or newer: `play_cpp_sdk_libstdc++_Linux_x86_64.tar.gz` or `play_cpp_sdk_libc++_Linux_x86_64.tar.gz` 32 | - Android: `play_cpp_sdk_$(TARGET)-$(NDK_VERSION).tar.gz` 33 | - IOS: `play_cpp_sdk_aarch64-apple-ios.tar.gz` 34 | 35 | ## Setup a demo project 36 | ### Windows 37 | #### Visual Studio Project 38 | Start with a C++ project with `.sln` and `.vcxproj` files: 39 | 1. Clone the current repository 40 | ``` sh 41 | git clone https://github.com/cronos-labs/play-cpp-sdk.git 42 | ``` 43 | 2. Unzip the archive file into `demo` folder, and replace the original `sdk` folder 44 | 3. Open `demo.sln` which includes two projects: `demo` (dynamic build) and `demostatic` (static 45 | build). If you use Visual Studio 2022, retarget project, and upgrade PlatformToolset to 46 | v143. 47 | 4. Select `Release` profile. 48 | 5. Right click `demo` or `demostatic` project, click `Build` or `Rebuild` to build the project 49 | 50 | #### CMake Project 51 | Build modern, cross-platform C++ apps that don't depend on `.sln` or `.vcxproj` files: 52 | 1. Open Visual Studio, then open a local folder in welcome window (or click `File` > `Open` > 53 | `Folder...` in the menu), locate the `demo` folder and open it 54 | 2. Select configuration `x64-Release` in the tool bar 55 | 3. Click `Build` > `Build All` or `Rebuild All` to build the project 56 | 57 | ### Mac 58 | 1. Clone the current repository 59 | ``` sh 60 | git clone https://github.com/cronos-labs/play-cpp-sdk.git 61 | ``` 62 | 2. Unzip the archive file into `demo` folder, and replace the original `sdk` folder 63 | 3. Under `demo` folder and build the `demo` project with g++, clang++ or default compiler 64 | ``` sh 65 | make CXX=g++ # Compile with g++ 66 | make CXX=clang++ # Compile with clang++ 67 | make # Compile with default compiler 68 | ``` 69 | 70 | ### Linux 71 | 1. Clone the current repository 72 | ``` sh 73 | git clone https://github.com/cronos-labs/play-cpp-sdk.git 74 | ``` 75 | 2. Unzip the archive file into `demo` folder, and replace the original `sdk` folder 76 | 3. Under `demo` folder and build the `demo` project with g++, clang++ or default compiler 77 | ``` sh 78 | make CXX=g++ # Compile with g++ 79 | make CXX=clang++ # Compile with clang++ 80 | make # Compile with default compiler 81 | ``` 82 | 83 | ## Setup a c++ 14 (or newer) project 84 | 1. Unzip the archive file into the root folder of your project, you should see a folder named `sdk` and its subdirectories/files. 85 | ``` 86 | - sdk 87 | - CMakeLists.txt 88 | - include: c++ source files and header files 89 | - lib: static and dynamic libraries 90 | - CHANGELOG.md 91 | - LICENSE 92 | ``` 93 | 94 | 2. Include the following headers and use the namespaces in your source codes based on your need 95 | ``` c++ 96 | #include "sdk/include/defi-wallet-core-cpp/src/contract.rs.h" // erc20, erc721, erc1155 supports 97 | #include "sdk/include/defi-wallet-core-cpp/src/lib.rs.h" // wallet, EIP4361, query, signing, broadcast etc, on crypto.org and cronos 98 | #include "sdk/include/defi-wallet-core-cpp/src/nft.rs.h" // crypto.org chain nft support 99 | #include "sdk/include/defi-wallet-core-cpp/src/uint.rs.h" // uint256 type support 100 | #include "sdk/include/defi-wallet-core-cpp/src/ethereum.rs.h" // dynamic contract support 101 | #include "sdk/include/extra-cpp-bindings/src/lib.rs.h" // etherscan/cronoscan, crypto.com pay, wallet connect support 102 | #include "sdk/include/rust/cxx.h" // the important data types, e.g., rust::String, rust::str, etc 103 | 104 | using namespace rust; 105 | using namespace org::defi_wallet_core; 106 | using namespace com::crypto::game_sdk; 107 | ``` 108 | 3. Link the `play_cpp_sdk` static or dynamic library, `cxxbridge1` static library, and sources 109 | (*.cc) into your build system (Visual Studio solution, CMake or Makefile). For more details, 110 | check out [Cronos Play Docs](https://github.com/crypto-org-chain/cronos-play-docs). 111 | 112 | # Build libraries and bindings from scratch 113 | If the Pre-built release does not support your platform, you can build the binaries and 114 | bindings on your own. 115 | 116 | ## Windows 117 | 1. Run `windows_build.bat` in x64 Native Tools Command Prompt for VS 2019. It will clone 118 | necessary submodules, build `play-cpp-sdk` crate, finally setup and build the demo project. 119 | 2. Clean `~/.cargo/git/checkouts` if cxx fails to build, then run `windows_build.bat` again. 120 | 3. Run `windows_install.bat`, libraries and bindings will be copied into a new created folder: 121 | `install` 122 | 123 | ### Notes about Visual Studio 2022 124 | 1. Open `demo.sln`. If you use Visual Studio 2022, retarget project, and upgrade 125 | PlatformToolset to `v143` before running `windows_build.bat` 126 | 127 | ## Mac 128 | 1. Run `make` 129 | 2. Run `make install`, libraries and bindings will be copied into a new created folder: `install` 130 | 131 | ### Linux 132 | 1. Run `make` 133 | 2. Run `make install`, libraries and bindings will be copied into a new created folder: `install` 134 | 135 | ### Android 136 | 1. Install android NDK (e.g. 23.0.7599858) via Android Studio 137 | 2. Run make for one of the following android targets on Mac or Linux 138 | ``` sh 139 | NDK_VERSION=23.0.7599858 make armv7-linux-androideabi 140 | NDK_VERSION=23.0.7599858 make aarch64-linux-android 141 | NDK_VERSION=23.0.7599858 make i686-linux-android 142 | NDK_VERSION=23.0.7599858 make x86_64-linux-android 143 | ``` 144 | 3. Run `make install`, libraries and bindings will be copied into a new created folder: `install` 145 | 146 | ### IOS 147 | 1. Run `make aarch64-apple-ios` 148 | 2. Run `make install`, libraries and bindings will be copied into a new created folder: `install` 149 | 150 | ### More information for Cronos Play 151 | If you are a game developer, please visit [Cronos Play](https://cronos.org/play) or fill this [Contact Form](https://airtable.com/shrCt6wWy87WrEXr8) for more information. 152 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Compile with g++: make CXX=g++ 2 | # Compile with clang++: make CXX=clang++ 3 | # Compile with default compiler: make 4 | UNAME := $(shell uname) 5 | 6 | GCC_CXXFLAGS = 7 | CLANG_CXXFLAGS = -stdlib=libc++ 8 | DEFAULT_CXXFLAGS = 9 | 10 | ifeq ($(CXX),g++) 11 | CXXFLAGS += $(GCC_CXXFLAGS) 12 | else ifneq (,$(findstring clang,$(CXX))) 13 | CXXFLAGS += $(CLANG_CXXFLAGS) 14 | else 15 | CXXFLAGS += $(DEFAULT_CXXFLAGS) 16 | endif 17 | 18 | # Comment out to set your ndk version 19 | # r23, for unreal 4.27 and 5.0 20 | # NDK_VERSION=23.0.7599858 21 | # r25, for unreal 5.1 22 | # NDK_VERSION=25.1.8937393 23 | # 24 | # or set NDK_VERSION on command line 25 | # NDK_VERSION=23.0.7599858 make armv7-linux-androideabi 26 | # NDK_VERSION=23.0.7599858 make aarch64-linux-android 27 | # NDK_VERSION=23.0.7599858 make i686-linux-android 28 | # NDK_VERSION=23.0.7599858 make x86_64-linux-android 29 | 30 | # The ndk requirement for unreal, please check 31 | # https://docs.unrealengine.com/4.27/en-US/SharingAndReleasing/Mobile/Android/AndroidSDKRequirements/ 32 | # https://docs.unrealengine.com/5.0/en-US/android-development-requirements-for-unreal-engine/ 33 | 34 | ifeq ($(UNAME), Darwin) 35 | # Please install NDK via Android Studio 36 | NDK_HOME=$(HOME)/Library/Android/sdk/ndk/$(NDK_VERSION) 37 | TOOLCHAIN=$(NDK_HOME)/toolchains/llvm/prebuilt/darwin-x86_64 38 | endif 39 | 40 | ifeq ($(UNAME), Linux) 41 | # Change NDK_HOME if necessary 42 | NDK_HOME=/usr/local/lib/android/sdk/ndk/$(NDK_VERSION) 43 | TOOLCHAIN=$(NDK_HOME)/toolchains/llvm/prebuilt/linux-x86_64 44 | endif 45 | 46 | # Set this to your minSdkVersion. 47 | API=26 48 | 49 | all: build_cpp 50 | 51 | clone: 52 | git submodule update --init --recursive 53 | 54 | build_play-cpp-sdk: clone 55 | ifeq ($(shell uname -m), x86_64) 56 | ifeq ($(UNAME), Darwin) 57 | cargo install cargo-lipo 58 | rustup target add aarch64-apple-darwin 59 | rustup target add x86_64-apple-darwin 60 | MACOSX_DEPLOYMENT_TARGET=10.15 CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) cargo build --package play-cpp-sdk --release --target aarch64-apple-darwin 61 | MACOSX_DEPLOYMENT_TARGET=10.15 CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) cargo build --package play-cpp-sdk --release 62 | lipo -create -output ./target/release/libplay_cpp_sdk_universal.a ./target/release/libplay_cpp_sdk.a ./target/aarch64-apple-darwin/release/libplay_cpp_sdk.a 63 | lipo -create -output ./target/aarch64-apple-darwin/release/libplay_cpp_sdk_universal.a ./target/release/libplay_cpp_sdk.a ./target/aarch64-apple-darwin/release/libplay_cpp_sdk.a 64 | endif 65 | ifeq ($(UNAME), Linux) 66 | CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) cargo build --package play-cpp-sdk --release 67 | endif 68 | else 69 | ifeq ($(shell uname -m), arm64) 70 | ifeq ($(UNAME), Darwin) 71 | cargo install cargo-lipo 72 | rustup target add aarch64-apple-darwin 73 | rustup target add x86_64-apple-darwin 74 | MACOSX_DEPLOYMENT_TARGET=10.15 CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) cargo build --package play-cpp-sdk --release 75 | MACOSX_DEPLOYMENT_TARGET=10.15 CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) cargo build --package play-cpp-sdk --release --target x86_64-apple-darwin 76 | lipo -create -output ./target/release/libplay_cpp_sdk_universal.a ./target/release/libplay_cpp_sdk.a ./target/x86_64-apple-darwin/release/libplay_cpp_sdk.a 77 | lipo -create -output ./target/x86_64-apple-darwin/release/libplay_cpp_sdk_universal.a ./target/release/libplay_cpp_sdk.a ./target/x86_64-apple-darwin/release/libplay_cpp_sdk.a 78 | endif 79 | else 80 | CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) cargo build --package play-cpp-sdk --release 81 | endif 82 | endif 83 | 84 | 85 | build_extra-cpp-bindings: 86 | CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) cargo build --package extra-cpp-bindings --release 87 | 88 | build_cpp: build_play-cpp-sdk 89 | MACOSX_DEPLOYMENT_TARGET=10.15 && cd demo && make build 90 | 91 | armv7-linux-androideabi: TARGET=armv7-linux-androideabi 92 | armv7-linux-androideabi: android_armv7 93 | cd demo && TARGET=$(TARGET) make android_build 94 | 95 | aarch64-linux-android: TARGET=aarch64-linux-android 96 | aarch64-linux-android: android_aarch64 97 | cd demo && TARGET=$(TARGET) make android_build 98 | 99 | i686-linux-android: TARGET=i686-linux-android 100 | i686-linux-android: android_i686 101 | cd demo && TARGET=$(TARGET) make android_build 102 | 103 | x86_64-linux-android: TARGET=x86_64-linux-android 104 | x86_64-linux-android: android_x86_64 105 | cd demo && TARGET=$(TARGET) make android_build 106 | 107 | aarch64-apple-ios: TARGET=aarch64-apple-ios 108 | aarch64-apple-ios: ios_aarch64 109 | cd demo && TARGET=$(TARGET) make ios_build 110 | 111 | android_armv7: 112 | rustup target add $(TARGET) 113 | TARGET_CC=$(TOOLCHAIN)/bin/armv7a-linux-androideabi$(API)-clang \ 114 | CXX=$(TOOLCHAIN)/bin/armv7a-linux-androideabi$(API)-clang++ \ 115 | TARGET_AR=$(TOOLCHAIN)/bin/llvm-ar \ 116 | CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=$(TOOLCHAIN)/bin/armv7a-linux-androideabi$(API)-clang \ 117 | cargo build --target=$(TARGET) --package play-cpp-sdk --release 118 | 119 | android_aarch64: 120 | rustup target add $(TARGET) 121 | TARGET_CC=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang \ 122 | CXX=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang++ \ 123 | TARGET_AR=$(TOOLCHAIN)/bin/llvm-ar \ 124 | CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang \ 125 | cargo build --target=$(TARGET) --package play-cpp-sdk --release 126 | 127 | android_i686: 128 | rustup target add $(TARGET) 129 | TARGET_CC=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang \ 130 | CXX=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang++ \ 131 | TARGET_AR=$(TOOLCHAIN)/bin/llvm-ar \ 132 | CARGO_TARGET_I686_LINUX_ANDROID_LINKER=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang \ 133 | cargo build --target=$(TARGET) --package play-cpp-sdk --release 134 | 135 | android_x86_64: 136 | rustup target add $(TARGET) 137 | TARGET_CC=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang \ 138 | CXX=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang++ \ 139 | TARGET_AR=$(TOOLCHAIN)/bin/llvm-ar \ 140 | CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=$(TOOLCHAIN)/bin/$(TARGET)$(API)-clang \ 141 | cargo build --target=$(TARGET) --package play-cpp-sdk --release 142 | 143 | ios_aarch64: 144 | rustup target add $(TARGET) 145 | cargo build --target=$(TARGET) --package play-cpp-sdk --release 146 | 147 | cpp: build_cpp 148 | # 1. In order to use crypto pay api, you need to Generate Keys in 149 | # https://merchant.crypto.com/developers/api_keys first 150 | # 151 | # 2. Copy the `Publishable Key` or `Secret Key` as `PAY_API_KEY`'s value in `.env` 152 | # cd demo && git submodule update --init --recursive && make build 153 | cd demo && make run 154 | 155 | cpp-ci-tests: build_cpp 156 | ./integration_test.sh 157 | 158 | webhook: 159 | # 1. Install ngrok for crypto pay api testing: https://ngrok.com/download 160 | # 161 | # 2. Run `ngrok http 4567` in a seperate terminal first, then add the `payload url` into 162 | # https://merchant.crypto.com/developers/webhooks 163 | # 164 | # 3. Find the `SIGNATURE SECRET` in merchant dashboard, and copy it as 165 | # `PAY_WEBHOOK_SIGNATURE_SECRET`'s value in `.env` 166 | cd demo && . ./.env && npm install && node server.js 167 | 168 | install: 169 | . ./install.sh 170 | 171 | uninstall: 172 | rm -rf install 173 | -------------------------------------------------------------------------------- /wallet-connect/src/client/session.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use crate::client::{ClientChannelMessage, ClientChannelMessageType}; 4 | use crate::crypto::Key; 5 | use crate::protocol::{ 6 | Metadata, PeerMetadata, SessionParams, SessionRequest, SessionUpdate, Topic, 7 | }; 8 | use crate::uri::Uri; 9 | use ethers::prelude::Address; 10 | use secrecy::ExposeSecret; 11 | use serde::{Deserialize, Serialize}; 12 | use tokio::sync::mpsc::UnboundedSender; 13 | use url::form_urlencoded::Serializer; 14 | use url::Url; 15 | /// The WalletConnect 1.0 session information 16 | /// based on the initial request-response: https://docs.walletconnect.com/tech-spec#session-request 17 | 18 | #[derive(Clone, Debug, Deserialize, Serialize)] 19 | #[serde(rename_all = "camelCase")] 20 | pub struct SessionInfo { 21 | /// if the wallet approved the connection 22 | pub connected: bool, 23 | /// the accounts returned by the wallet 24 | pub accounts: Vec
, 25 | /// the chain id returned by the wallet 26 | pub chain_id: Option, 27 | /// the bridge server URL 28 | pub bridge: Url, 29 | /// the secret key used in encrypting wallet requests 30 | /// and decrypting wallet responses as per WalletConnect 1.0 31 | pub key: Key, 32 | /// this is the client's randomly generated ID 33 | pub client_id: Topic, 34 | /// the client metadata (that will be presented to the wallet in the initial request) 35 | pub client_meta: Metadata, 36 | /// the wallet's ID 37 | pub peer_id: Option, 38 | /// the wallet's metadata 39 | pub peer_meta: Option, 40 | /// the one-time request ID 41 | pub handshake_topic: Topic, 42 | } 43 | 44 | impl SessionInfo { 45 | pub fn uri(&self) -> Uri { 46 | Uri::parse(format!( 47 | "wc:{}@1?{}", 48 | self.handshake_topic, 49 | Serializer::new(String::new()) 50 | .append_pair("bridge", self.bridge.as_str()) 51 | .append_pair("key", self.key.display().expose_secret()) 52 | .finish() 53 | )) 54 | .expect("WalletConnect URIs from sessions are always valid") 55 | } 56 | } 57 | 58 | #[derive(Debug, Clone)] 59 | pub struct Session { 60 | pub info: SessionInfo, 61 | 62 | /// when memory is enough, and receive channel is valid 63 | /// send will succeed 64 | /// ref: https://docs.rs/futures/0.1.31/futures/sync/mpsc/fn.unbounded.html 65 | pub callback_channel: Option>, 66 | } 67 | 68 | impl Session { 69 | pub fn set_callback(&mut self, myfunc: UnboundedSender) { 70 | self.callback_channel = Some(myfunc); 71 | } 72 | 73 | /// generate the session URI: https://docs.walletconnect.com/tech-spec#requesting-connection 74 | /// https://eips.ethereum.org/EIPS/eip-1328 75 | pub fn uri(&self) -> Uri { 76 | self.info.uri() 77 | } 78 | 79 | /// generates a session request from the session: https://docs.walletconnect.com/tech-spec#session-request 80 | pub fn request(&self) -> SessionRequest { 81 | SessionRequest { 82 | peer_id: self.info.client_id.clone(), 83 | peer_meta: self.info.client_meta.clone(), 84 | chain_id: self.info.chain_id, 85 | } 86 | } 87 | 88 | /// updates the session details from the response 89 | pub fn apply(&mut self, params: SessionParams) { 90 | self.info.connected = params.approved; 91 | self.info.accounts = params.accounts; 92 | self.info.chain_id = Some(params.chain_id); 93 | self.info.peer_id = Some(params.peer_id); 94 | self.info.peer_meta = Some(params.peer_meta); 95 | 96 | if let Some(ref mut callback) = self.callback_channel { 97 | let msg = ClientChannelMessage { 98 | state: ClientChannelMessageType::Connected, 99 | session: Some(self.info.clone()), 100 | }; 101 | callback 102 | .send(msg) 103 | .expect("callback channel should be valid"); 104 | } 105 | } 106 | /// when start connecting 107 | pub fn event_connecting(&self) { 108 | if let Some(ref callback) = self.callback_channel { 109 | let msg = ClientChannelMessage { 110 | state: ClientChannelMessageType::Connecting, 111 | session: Some(self.info.clone()), 112 | }; 113 | callback 114 | .send(msg) 115 | .expect("callback channel should be valid"); 116 | } 117 | } 118 | 119 | /// when updated 120 | pub fn event_updated(&self) { 121 | if let Some(ref callback) = self.callback_channel { 122 | let msg = ClientChannelMessage { 123 | state: ClientChannelMessageType::Updated, 124 | session: Some(self.info.clone()), 125 | }; 126 | callback 127 | .send(msg) 128 | .expect("callback channel should be valid"); 129 | } 130 | } 131 | 132 | /// when session is disconnected 133 | pub fn event_disconnect(&self) { 134 | if let Some(ref callback) = self.callback_channel { 135 | let msg = ClientChannelMessage { 136 | state: ClientChannelMessageType::Disconnected, 137 | session: Some(self.info.clone()), 138 | }; 139 | callback 140 | .send(msg) 141 | .expect("callback channel should be valid"); 142 | } 143 | } 144 | 145 | /// updates the session details from the session update: https://docs.walletconnect.com/tech-spec#session-update 146 | pub fn update(&mut self, update: SessionUpdate) { 147 | self.info.connected = update.approved; 148 | 149 | if let Some(accounts) = update.accounts { 150 | self.info.accounts = accounts; 151 | } else { 152 | self.info.accounts = vec![]; 153 | } 154 | self.info.chain_id = update.chain_id; 155 | 156 | if self.info.connected { 157 | // notify updated information 158 | self.event_updated(); 159 | } else { 160 | // by update, session is desroyed 161 | self.event_disconnect(); 162 | } 163 | } 164 | } 165 | 166 | #[cfg(test)] 167 | mod tests { 168 | use super::*; 169 | use serde_json::json; 170 | 171 | #[test] 172 | fn new_topic_is_random() { 173 | assert_ne!(Topic::new(), Topic::new()); 174 | } 175 | 176 | #[test] 177 | fn zero_topic() { 178 | assert_eq!( 179 | json!(Topic::zero()), 180 | json!("00000000-0000-0000-0000-000000000000") 181 | ); 182 | } 183 | 184 | #[test] 185 | fn topic_serialization() { 186 | let topic = Topic::new(); 187 | let serialized = serde_json::to_string(&topic).unwrap(); 188 | let deserialized = serde_json::from_str(&serialized).unwrap(); 189 | assert_eq!(topic, deserialized); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /wallet-connect/src/protocol/rpc.rs: -------------------------------------------------------------------------------- 1 | //! Copyright (c) 2020 Nicholas Rodrigues Lordello (licensed under the Apache License, Version 2.0) 2 | //! Modifications Copyright (c) 2022, Cronos Labs (licensed under the Apache License, Version 2.0) 3 | use core::fmt; 4 | 5 | use super::Topic; 6 | use ethers::prelude::Address; 7 | pub use ethers::prelude::TransactionRequest as Transaction; 8 | use serde::{Deserialize, Serialize}; 9 | use serde_json::Value; 10 | use thiserror::Error; 11 | use url::Url; 12 | 13 | /// the metadata of the peer (client or wallet) 14 | /// that could be presented in the UI 15 | /// https://docs.walletconnect.com/tech-spec#session-request 16 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 17 | #[serde(rename_all = "camelCase")] 18 | pub struct Metadata { 19 | /// description of the dApp/wallet software 20 | pub description: String, 21 | /// a link to its homepage 22 | pub url: Url, 23 | /// links to icons ot display in the UI 24 | #[serde(default)] 25 | pub icons: Vec, 26 | /// name of the dApp/wallet software 27 | pub name: String, 28 | } 29 | 30 | /// the wrapper type of the metadata 31 | #[derive(Clone, Debug, Deserialize, Serialize)] 32 | #[serde(untagged)] 33 | pub enum PeerMetadata { 34 | /// correct metadata as per WalletConnect 1.0 protocol specs 35 | Strict(Metadata), 36 | /// some extra or missing fields 37 | Malformed(Value), 38 | } 39 | 40 | /// the request to start a session with an external wallet 41 | /// https://docs.walletconnect.com/tech-spec#session-request 42 | #[derive(Clone, Debug, Deserialize, Serialize)] 43 | #[serde(rename_all = "camelCase")] 44 | pub struct SessionRequest { 45 | /// the preferred chain ID 46 | pub chain_id: Option, 47 | /// sender's client id 48 | pub peer_id: Topic, 49 | /// sender's client metadata 50 | pub peer_meta: Metadata, 51 | } 52 | 53 | /// the response to the session request 54 | #[derive(Clone, Debug, Deserialize, Serialize)] 55 | #[serde(rename_all = "camelCase")] 56 | pub struct SessionParams { 57 | /// if the wallet user approved the connection 58 | pub approved: bool, 59 | /// the wallet's addresses 60 | pub accounts: Vec
, 61 | /// the chain where these addresses are expected to be used 62 | pub chain_id: u64, 63 | /// the receiver/wallet's ID 64 | pub peer_id: Topic, 65 | /// the receiver/wallet's metadata 66 | pub peer_meta: PeerMetadata, 67 | } 68 | 69 | /// when the wallet disconnects or changes some information 70 | /// (new accounts, a different chain id...) 71 | /// https://docs.walletconnect.com/tech-spec#session-update 72 | #[derive(Clone, Debug, Deserialize, Serialize)] 73 | #[serde(rename_all = "camelCase")] 74 | pub struct SessionUpdate { 75 | /// if the wallet user approved the connection 76 | pub approved: bool, 77 | /// the wallet's addresses 78 | /// null/None when the wallet disconnects 79 | pub accounts: Option>, 80 | /// the chain where these addresses are expected to be used 81 | /// null/None when the wallet disconnects 82 | pub chain_id: Option, 83 | } 84 | 85 | fn is_zst(_t: &T) -> bool { 86 | std::mem::size_of::() == 0 87 | } 88 | 89 | #[derive(Serialize, Deserialize, Debug)] 90 | /// A JSON-RPC request 91 | /// (taken from ethers as it's not exported) 92 | pub struct Request<'a, T> { 93 | pub id: u64, 94 | jsonrpc: &'a str, 95 | method: &'a str, 96 | #[serde(skip_serializing_if = "is_zst")] 97 | pub params: T, 98 | } 99 | 100 | impl<'a, T> Request<'a, T> { 101 | /// Creates a new JSON RPC request 102 | pub fn new(id: u64, method: &'a str, params: T) -> Self { 103 | Self { 104 | id, 105 | jsonrpc: "2.0", 106 | method, 107 | params, 108 | } 109 | } 110 | } 111 | 112 | /// the request coming in from the wallet 113 | /// (e.g. changing the chain id, address or disconnecting) 114 | #[derive(Serialize, Deserialize, Debug, Clone)] 115 | pub struct RequestSessionUpdate { 116 | /// JSON-RPC ID 117 | /// according to https://www.jsonrpc.org/specification 118 | /// it could be "String, Number, or NULL" 119 | /// but it seems that the bridge server or wallets use just numbers. 120 | /// TODO: change to be more general as per the official JSON-RPC specs? 121 | pub(crate) id: u64, 122 | /// "2.0" static string -- TODO: check? 123 | jsonrpc: String, 124 | /// the method name -- the expected one is "wc_sessionUpdate" 125 | /// TODO: it's checked in the socket.rs -- check here in deserialization instead? 126 | pub(crate) method: String, 127 | /// the session update params 128 | /// it's a vector of size one 129 | /// TODO: it's checked in the socket.rs -- check here in deserialization instead? 130 | pub(crate) params: Vec, 131 | } 132 | 133 | /// the wrapper type for data received from the bridge server 134 | #[derive(Clone, Debug, Deserialize, Serialize)] 135 | #[serde(untagged)] 136 | pub enum BridgeServerMsg { 137 | /// the session update request (e.g. changing the chain id, address or disconnecting) 138 | SessionUpdateRequest(RequestSessionUpdate), 139 | /// the responses to previous requests to the wallet (e.g. signing a transaction) 140 | Response(Response), 141 | } 142 | 143 | /// A JSON-RPC response 144 | /// (taken from ethers as it's not exported) 145 | #[derive(Serialize, Deserialize, Debug, Clone)] 146 | pub struct Response { 147 | /// it should correspond to the request id. 148 | /// according to https://www.jsonrpc.org/specification 149 | /// it could be "String, Number, or NULL" 150 | /// but we only use numbers in requests. 151 | /// TODO: change to be more general as per the official JSON-RPC specs? 152 | pub(crate) id: u64, 153 | jsonrpc: String, 154 | /// the result of the request 155 | #[serde(flatten)] 156 | pub data: ResponseData, 157 | } 158 | 159 | impl Response { 160 | pub fn new(id: u64, result: T) -> Self { 161 | Self { 162 | id, 163 | jsonrpc: "2.0".into(), 164 | data: ResponseData::Success { result }, 165 | } 166 | } 167 | } 168 | 169 | /// the result of the request 170 | #[derive(Serialize, Deserialize, Debug, Clone)] 171 | #[serde(untagged)] 172 | pub enum ResponseData { 173 | /// something went wrong 174 | Error { error: JsonRpcError }, 175 | /// the result of the request 176 | Success { result: R }, 177 | } 178 | 179 | impl ResponseData { 180 | /// Consume response and return value 181 | pub fn into_result(self) -> Result { 182 | match self { 183 | ResponseData::Success { result } => Ok(result), 184 | ResponseData::Error { error } => Err(error), 185 | } 186 | } 187 | } 188 | 189 | impl ResponseData { 190 | /// Encode the error to json value if it is an error 191 | #[allow(dead_code)] 192 | pub fn into_value(self) -> serde_json::Result { 193 | match self { 194 | ResponseData::Success { result } => Ok(result), 195 | ResponseData::Error { error } => serde_json::to_value(error), 196 | } 197 | } 198 | } 199 | 200 | /// A JSON-RPC 2.0 error 201 | #[derive(Serialize, Deserialize, Debug, Clone, Error)] 202 | pub struct JsonRpcError { 203 | /// The error code 204 | pub code: i64, 205 | /// The error message 206 | pub message: String, 207 | /// Additional data 208 | pub data: Option, 209 | } 210 | 211 | impl fmt::Display for JsonRpcError { 212 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 213 | write!( 214 | f, 215 | "(code: {}, message: {}, data: {:?})", 216 | self.code, self.message, self.data 217 | ) 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /demo/examples/src/chainmain_nft.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace org::defi_wallet_core; 8 | 9 | CosmosSDKTxInfoRaw build_txinfo() { 10 | CosmosSDKTxInfoRaw ret; 11 | ret.account_number = 0; 12 | ret.sequence_number = 0; 13 | ret.gas_limit = 5000000; 14 | ret.fee_amount = 25000000000; 15 | ret.fee_denom = "basecro"; 16 | ret.timeout_height = 0; 17 | ret.memo_note = ""; 18 | ret.chain_id = "chainmain-1"; 19 | ret.coin_type = 394; 20 | ret.bech32hrp = "cro"; 21 | return ret; 22 | } 23 | 24 | int main(int argc, char *argv[]) { 25 | CosmosSDKTxInfoRaw tx_info = build_txinfo(); 26 | 27 | rust::String myservertendermint = "http://127.0.0.1:26807"; 28 | rust::String mygrpc = "http://127.0.0.1:26803"; 29 | rust::String myservercosmos = "http://127.0.0.1:26804"; 30 | 31 | rust::String from = "cro1u08u5dvtnpmlpdq333uj9tcj75yceggszxpnsy"; 32 | rust::String to = "cro1apdh4yc2lnpephevc6lmpvkyv6s5cjh652n6e4"; 33 | 34 | rust::Box signer1_wallet = restore_wallet( 35 | "shed crumble dismiss loyal latin million oblige gesture " 36 | "shrug still oxygen custom remove ribbon disorder palace " 37 | "addict again blanket sad flock consider obey popular", 38 | ""); 39 | rust::Box signer1_privatekey = 40 | signer1_wallet->get_key("m/44'/394'/0'/0/0"); 41 | 42 | rust::Box signer2_wallet = 43 | restore_wallet("night renew tonight dinner shaft scheme domain oppose " 44 | "echo summer broccoli agent face guitar surface belt " 45 | "veteran siren poem alcohol menu custom crunch index", 46 | ""); 47 | rust::Box signer2_privatekey = 48 | signer2_wallet->get_key("m/44'/394'/0'/0/0"); 49 | 50 | CosmosAccountInfoRaw detailinfo = 51 | query_account_details_info(myservercosmos, from); 52 | auto signer1_sn = detailinfo.sequence_number; 53 | auto signer1_ac = detailinfo.account_number; 54 | 55 | detailinfo = query_account_details_info(myservercosmos, to); 56 | auto signer2_sn = detailinfo.sequence_number; 57 | auto signer2_ac = detailinfo.account_number; 58 | 59 | tx_info.account_number = signer1_ac; 60 | tx_info.sequence_number = signer1_sn; 61 | 62 | // chainmain nft tests 63 | auto denom_id = "testdenomid"; 64 | auto denom_name = "testdenomname"; 65 | auto schema = R""""( 66 | { 67 | "title": "Asset Metadata", 68 | "type": "object", 69 | "properties": { 70 | "name": { 71 | "type": "string", 72 | "description": "testidentity" 73 | }, 74 | "description": { 75 | "type": "string", 76 | "description": "testdescription" 77 | }, 78 | "image": { 79 | "type": "string", 80 | "description": "testdescription" 81 | } 82 | } 83 | })""""; 84 | 85 | // issue: from 86 | // signer1_sn += 1; // No need to add sn here, it is the first one 87 | tx_info.sequence_number = signer1_sn; 88 | rust::Vec signedtx = get_nft_issue_denom_signed_tx( 89 | tx_info, *signer1_privatekey, denom_id, denom_name, schema); 90 | 91 | rust::String resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; 92 | std::cout << "issue response: " << resp << std::endl; 93 | 94 | auto token_id = "testtokenid"; 95 | auto token_name = "testtokenname"; 96 | auto token_uri = "testtokenuri"; 97 | auto token_data = ""; 98 | 99 | // mint: from -> to 100 | signer1_sn += 1; 101 | tx_info.sequence_number = signer1_sn; 102 | signedtx = 103 | get_nft_mint_signed_tx(tx_info, *signer1_privatekey, token_id, denom_id, 104 | token_name, token_uri, token_data, to); 105 | resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; 106 | std::cout << "mint response: " << resp << std::endl; 107 | 108 | std::this_thread::sleep_for(std::chrono::seconds(3)); 109 | rust::Box grpc_client = new_grpc_client(mygrpc); 110 | 111 | Pagination pagination; 112 | assert(pagination.enable == false); 113 | assert(pagination.key.size() == 0); 114 | assert(pagination.offset == 0); 115 | assert(pagination.limit == 100); 116 | assert(pagination.count_total == false); 117 | assert(pagination.reverse == false); 118 | rust::Vec denoms = grpc_client->denoms(pagination); 119 | assert(denoms.size() == 1); 120 | assert(denoms[0].id == denom_id); 121 | assert(denoms[0].name == denom_name); 122 | assert(denoms[0].schema == schema); 123 | assert(denoms[0].creator == from); 124 | 125 | BaseNft nft = grpc_client->nft(denom_id, token_id); 126 | std::cout << "nft: " << nft.to_string() << std::endl; 127 | assert(nft.id == token_id); 128 | assert(nft.name == token_name); 129 | assert(nft.uri == token_uri); 130 | assert(nft.data == token_data); 131 | assert(nft.owner == to); 132 | 133 | Collection collection = grpc_client->collection(denom_id, pagination); 134 | std::cout << "collection: " << collection.to_string() << std::endl; 135 | Owner owner = grpc_client->owner(denom_id, to, pagination); 136 | std::cout << "owner: " << owner.to_string() << std::endl; 137 | assert(owner.address == to); 138 | assert(owner.id_collections.size() == 1); 139 | assert(owner.id_collections[0].denom_id == denom_id); 140 | assert(owner.id_collections[0].token_ids.size() == 1); 141 | assert(owner.id_collections[0].token_ids[0] == token_id); 142 | 143 | // transfer: to -> from 144 | tx_info.account_number = signer2_ac; 145 | tx_info.sequence_number = signer2_sn; 146 | signedtx = get_nft_transfer_signed_tx(tx_info, *signer2_privatekey, 147 | token_id, denom_id, from); 148 | resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; 149 | std::cout << "transfer response: " << resp << std::endl; 150 | std::this_thread::sleep_for(std::chrono::seconds(3)); 151 | nft = grpc_client->nft(denom_id, token_id); 152 | std::cout << "nft: " << nft.to_string() << std::endl; 153 | assert(nft.id == token_id); 154 | assert(nft.name == token_name); 155 | assert(nft.uri == token_uri); 156 | assert(nft.data == token_data); 157 | assert(nft.owner == from); 158 | owner = grpc_client->owner(denom_id, from, pagination); 159 | std::cout << "owner: " << owner.to_string() << std::endl; 160 | assert(owner.address == from); 161 | assert(owner.id_collections.size() == 1); 162 | assert(owner.id_collections[0].denom_id == denom_id); 163 | assert(owner.id_collections[0].token_ids.size() == 1); 164 | assert(owner.id_collections[0].token_ids[0] == token_id); 165 | 166 | // edit 167 | tx_info.account_number = signer1_ac; 168 | signer1_sn += 1; 169 | tx_info.sequence_number = signer1_sn; 170 | signedtx = get_nft_edit_signed_tx(tx_info, *signer1_privatekey, token_id, 171 | denom_id, "newname", "newuri", "newdata"); 172 | resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; 173 | std::cout << "edit response: " << resp << std::endl; 174 | std::this_thread::sleep_for(std::chrono::seconds(3)); 175 | nft = grpc_client->nft(denom_id, token_id); 176 | std::cout << "nft: " << nft.to_string() << std::endl; 177 | assert(nft.id == token_id); 178 | assert(nft.name == "newname"); 179 | assert(nft.uri == "newuri"); 180 | assert(nft.data == "newdata"); 181 | assert(nft.owner == from); 182 | uint64_t supply = grpc_client->supply(denom_id, from); 183 | std::cout << "supply: " << supply << std::endl; 184 | assert(supply == 1); 185 | 186 | // burn 187 | signer1_sn += 1; 188 | tx_info.sequence_number = signer1_sn; 189 | signedtx = get_nft_burn_signed_tx(tx_info, *signer1_privatekey, token_id, 190 | denom_id); 191 | resp = broadcast_tx(myservertendermint, signedtx).tx_hash_hex; 192 | std::cout << "burn response: " << resp << std::endl; 193 | std::this_thread::sleep_for(std::chrono::seconds(3)); 194 | supply = grpc_client->supply(denom_id, from); 195 | std::cout << "supply: " << supply << std::endl; 196 | assert(supply == 0); 197 | 198 | return 0; 199 | } 200 | --------------------------------------------------------------------------------