diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b39b65d..96c1c950 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,8 @@ jobs: check: name: cargo check runs-on: ubuntu-latest + env: + RUSTFLAGS: -A dead_code steps: - uses: actions/checkout@v3 with: @@ -35,6 +37,8 @@ jobs: test: name: cargo test runs-on: ubuntu-latest + env: + RUSTFLAGS: -A dead_code steps: - uses: actions/checkout@v3 with: @@ -73,6 +77,8 @@ jobs: clippy: name: cargo clippy runs-on: ubuntu-latest + env: + RUSTFLAGS: -A dead_code steps: - uses: actions/checkout@v3 with: diff --git a/demo/examples/src/wallet_connect.cc b/demo/examples/src/wallet_connect.cc index 386061dc..63672ffb 100644 --- a/demo/examples/src/wallet_connect.cc +++ b/demo/examples/src/wallet_connect.cc @@ -1,3 +1,4 @@ +#include <_types/_uint64_t.h> #include #include #include @@ -34,35 +35,36 @@ rust::String address_to_hex_string(::std::array<::std::uint8_t, 20> bytes) { } // if session already exists, restore session -rust::Box make_new_client(std::string filename) { +rust::Box make_new_client(std::string filename) { std::ifstream file(filename.c_str()); if (file.is_open()) { std::string sessioninfostring((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - rust::Box client = - walletconnect_restore_client(sessioninfostring); + rust::Box client = + walletconnect2_restore_client(sessioninfostring); return client; } else { - rust::Box client = walletconnect_new_client( - "Defi WalletConnect example.", "http://localhost:8080/", - rust::Vec(), "Defi WalletConnect Web3 Example", - 338); // ChainId of Cronos Testnet + std::string projectid = std::getenv("NEXT_PUBLIC_PROJECT_ID") + ? std::getenv("NEXT_PUBLIC_PROJECT_ID") + : ""; + // assert projectid not "" + assert(projectid != ""); + + rust::Box client = walletconnect2_client_new( + "wss://relay.walletconnect.org", projectid, + "{\"eip155\":{\"methods\":[\"eth_sendTransaction\",\"eth_" + "signTransaction\",\"eth_sign\",\"personal_sign\",\"eth_" + "signTypedData\"],\"chains\":[\"eip155:338\"],\"events\":[" + "\"chainChanged\",\"accountsChanged\"]}}", + "{\"description\":\"Defi WalletConnect v2 " + "example.\",\"url\":\"http://localhost:8080/" + "\",\"icons\":[],\"name\":\"Defi WalletConnect Web3 Example\"}"); std::cout << "qrcode= " << client->get_connection_string() << std::endl; return client; } } - -class UserWalletConnectCallback : public WalletConnectCallback { - public: - UserWalletConnectCallback() {} - virtual ~UserWalletConnectCallback() {} - void onConnected(const WalletConnectSessionInfo &sessioninfo) const; - void onDisconnected(const WalletConnectSessionInfo &sessioninfo) const; - void onConnecting(const WalletConnectSessionInfo &sessioninfo) const; - void onUpdated(const WalletConnectSessionInfo &sessioninfo) const; -}; void print_session(const WalletConnectSessionInfo &sessioninfo) { std::cout << "connected: " << sessioninfo.connected << std::endl; std::cout << "chain_id: " << sessioninfo.chain_id << std::endl; @@ -78,50 +80,21 @@ void print_session(const WalletConnectSessionInfo &sessioninfo) { std::cout << "handshake_topic: " << sessioninfo.handshake_topic << std::endl; } -void UserWalletConnectCallback::onConnected( - const WalletConnectSessionInfo &sessioninfo) const { - std::cout << "user c++ onConnected" << std::endl; - print_session(sessioninfo); -} -void UserWalletConnectCallback::onDisconnected( - const WalletConnectSessionInfo &sessioninfo) const { - std::cout << "user c++ onDisconnected" << std::endl; - print_session(sessioninfo); - exit(0); -} -void UserWalletConnectCallback::onConnecting( - const WalletConnectSessionInfo &sessioninfo) const { - std::cout << "user c++ onConnecting" << std::endl; - print_session(sessioninfo); - // !!! Important !!! - // Comment out this line for actual test - exit(0); -} -void UserWalletConnectCallback::onUpdated( - const WalletConnectSessionInfo &sessioninfo) const { - std::cout << "user c++ onUpdated" << std::endl; - print_session(sessioninfo); -} int main(int argc, char *argv[]) { std::string filename = "sessioninfo.json"; try { - rust::Box client = make_new_client(filename); - WalletConnectCallback *usercallbackraw = - new UserWalletConnectCallback(); - std::unique_ptr usercallback(usercallbackraw); - client->setup_callback_blocking(std::move(usercallback)); + rust::Box client = make_new_client(filename); // Print the QR code on terminal rust::String uri = client->print_uri(); // program is blocked here for waiting connecting - WalletConnectEnsureSessionResult result = - client->ensure_session_blocking(); + WalletConnect2EnsureSessionResult result = + client->ensure_session_blocking(60000); // once connected, program continues - std::cout << "connected chain_id: " << result.chain_id << std::endl; - assert(result.addresses.size() > 0); + assert(result.eip155.accounts.size() > 0); // get the connected session info as string and save it into a file rust::String sessioninfo = client->save_client(); @@ -138,11 +111,21 @@ int main(int argc, char *argv[]) { // sign personal message if (test_personal) { /* message signing */ - rust::Vec sig1 = client->sign_personal_blocking( - "hello", result.addresses[0].address); + ::std::uint64_t testchainid = result.eip155.accounts[0].chain_id; + ::std::array<::std::uint8_t, 20> testaddress = + result.eip155.accounts[0].address.address; + std::cout << "chainid=" << testchainid << std::endl; + std::cout << "address=" + << address_to_hex_string(testaddress).c_str() + << std::endl; + rust::Vec sig1 = + client->sign_personal_blocking("hello", testaddress); std::cout << "signature=" << bytes_to_hex_string(sig1).c_str() << std::endl; std::cout << "signature length=" << sig1.size() << std::endl; + bool verifyresult = + client->verify_personal_blocking("hello", sig1, testaddress); + std::cout << "verify result=" << verifyresult << std::endl; } // send transaction @@ -166,12 +149,13 @@ int main(int argc, char *argv[]) { // info.to = "0x...."; info.to = rust::String( std::string("0x") + - address_to_hex_string(result.addresses[0].address).c_str()); + address_to_hex_string(result.eip155.accounts[0].address.address) + .c_str()); info.value = "1000000000000000000"; // 1 TCRO - info.common.chainid = result.chain_id; + info.common.chainid = result.eip155.accounts[0].chain_id; rust::Vec tx_hash = client->send_eip155_transaction_blocking( - info, result.addresses[0].address); + info, result.eip155.accounts[0].address.address); std::cout << "transaction_hash=" << bytes_to_hex_string(tx_hash).c_str() << std::endl; @@ -205,7 +189,8 @@ int main(int argc, char *argv[]) { assert(erc20.decimals() == 18); rust::String from_address = rust::String( std::string("0x") + - address_to_hex_string(result.addresses[0].address).c_str()); + address_to_hex_string(result.eip155.accounts[0].address.address) + .c_str()); U256 erc20_balance = erc20.balance_of(from_address); std::cout << "erc20 balance=" << erc20_balance.to_string() << std::endl; @@ -222,13 +207,14 @@ int main(int argc, char *argv[]) { } })"; - common.chainid = result.chain_id; + common.chainid = result.eip155.accounts[0].chain_id; common.web3api_url = "https://evm-dev-t3.cronos.org"; // TODO unnessary for // walletconnect rust::Vec tx_hash = client->send_contract_transaction( - contract_action, common, result.addresses[0].address); + contract_action, common, + result.eip155.accounts[0].address.address); std::cout << "transaction_hash=" << bytes_to_hex_string(tx_hash).c_str() << std::endl; diff --git a/extra-cpp-bindings/src/lib.rs b/extra-cpp-bindings/src/lib.rs index fe464792..25c7dde2 100644 --- a/extra-cpp-bindings/src/lib.rs +++ b/extra-cpp-bindings/src/lib.rs @@ -347,6 +347,13 @@ mod ffi { message: String, address: [u8; 20], ) -> Result>; + /// verify message + pub fn verify_personal_blocking( + self: &mut Walletconnect2Client, + message: String, + signature_bytes: Vec, + user_address: [u8; 20], + ) -> Result; pub fn ping_blocking(self: &mut Walletconnect2Client, waitmillis: u64) -> Result; /// build cronos(eth) eip155 transaction diff --git a/extra-cpp-bindings/src/walletconnect2.rs b/extra-cpp-bindings/src/walletconnect2.rs index a19df8cd..c551e500 100644 --- a/extra-cpp-bindings/src/walletconnect2.rs +++ b/extra-cpp-bindings/src/walletconnect2.rs @@ -141,6 +141,25 @@ impl Walletconnect2Client { } } + // signature: 65 bytes (r:32, s:32,v:1) + pub fn verify_personal_blocking( + &mut self, + message: String, + signature_bytes: Vec, + user_address: [u8; 20], + ) -> Result { + let address = ethers::types::Address::from_slice(&user_address); + let signature = Signature::try_from(signature_bytes.as_slice()) + .map_err(|e| anyhow!("Invalid signature: {}", e))?; + + Ok(signature.verify(message, address).is_ok()) + } + + // signature + // r: 32 bytes + // s: 32 bytees + // v: 1 byte + // total 65 bytes pub fn sign_personal_blocking( &mut self, message: String, diff --git a/wallet-connect/examples/web3_v2.rs b/wallet-connect/examples/web3_v2.rs index b5665e9c..59dd3b68 100644 --- a/wallet-connect/examples/web3_v2.rs +++ b/wallet-connect/examples/web3_v2.rs @@ -264,9 +264,9 @@ async fn main() -> Result<(), Box> { }; let test_ping = false; - let test_personal_signing = false; + let test_personal_signing = true; let test_sign_tx = false; - let test_send_tx = true; + let test_send_tx = false; let test_send_typedtx = false; let test_event_listening = false; @@ -288,9 +288,21 @@ async fn main() -> Result<(), Box> { } if test_personal_signing { // 0xaddress + let message = "Hello Crypto"; let address1 = namespaces.get_ethereum_addresses()[0].address.clone(); - let sig1 = client.personal_sign("Hello Crypto", &address1).await?; + let sig1 = client.personal_sign(message, &address1).await?; println!("sig1: {:?}", sig1); + + // Verify the signature + let signer = sig1.verify(message, address1); + match signer { + Ok(_) => { + println!("Signature verified"); + } + Err(err) => { + println!("Error verifying signature: {:?}", err); + } + } } if test_sign_tx {