Skip to content

Commit

Permalink
Problem: missing verification api for wc 2.0 (fix #474)
Browse files Browse the repository at this point in the history
feat: enable personal signing in web3_v2.rs example
feat: Add personal signature verification method
feat: Update wallet_connect.cc to use Walletconnect2Client
feat: Update wallet_connect.cc to use Walletconnect2Client

tidy up
  • Loading branch information
leejw51crypto committed May 20, 2024
1 parent 3b41318 commit 9325e0d
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 60 deletions.
84 changes: 27 additions & 57 deletions demo/examples/src/wallet_connect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,35 +34,30 @@ rust::String address_to_hex_string(::std::array<::std::uint8_t, 20> bytes) {
}

// if session already exists, restore session
rust::Box<WalletconnectClient> make_new_client(std::string filename) {
rust::Box<Walletconnect2Client> make_new_client(std::string filename) {

std::ifstream file(filename.c_str());
if (file.is_open()) {
std::string sessioninfostring((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
rust::Box<WalletconnectClient> client =
walletconnect_restore_client(sessioninfostring);
rust::Box<Walletconnect2Client> client =
walletconnect2_restore_client(sessioninfostring);
return client;
} else {
rust::Box<WalletconnectClient> client = walletconnect_new_client(
"Defi WalletConnect example.", "http://localhost:8080/",
rust::Vec<rust::String>(), "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<Walletconnect2Client> 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;
Expand All @@ -78,50 +73,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<WalletconnectClient> client = make_new_client(filename);
WalletConnectCallback *usercallbackraw =
new UserWalletConnectCallback();
std::unique_ptr<WalletConnectCallback> usercallback(usercallbackraw);
client->setup_callback_blocking(std::move(usercallback));
rust::Box<Walletconnect2Client> 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();
Expand All @@ -139,10 +105,14 @@ int main(int argc, char *argv[]) {
if (test_personal) {
/* message signing */
rust::Vec<uint8_t> sig1 = client->sign_personal_blocking(
"hello", result.addresses[0].address);
"hello", result.eip155.accounts[0].address.address);
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, result.eip155.accounts[0].address.address);
std::cout << "verify result=" << verifyresult << std::endl;
}

// send transaction
Expand All @@ -166,12 +136,12 @@ 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<uint8_t> 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;
Expand Down Expand Up @@ -205,7 +175,7 @@ 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;
Expand All @@ -222,13 +192,13 @@ 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<uint8_t> 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;
Expand Down
7 changes: 7 additions & 0 deletions extra-cpp-bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ mod ffi {
message: String,
address: [u8; 20],
) -> Result<Vec<u8>>;
/// verify message
pub fn verify_personal_blocking(
self: &mut Walletconnect2Client,
message: String,
signature_bytes: Vec<u8>,
user_address: [u8; 20],
) -> Result<bool>;
pub fn ping_blocking(self: &mut Walletconnect2Client, waitmillis: u64) -> Result<String>;

/// build cronos(eth) eip155 transaction
Expand Down
19 changes: 19 additions & 0 deletions extra-cpp-bindings/src/walletconnect2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>,
user_address: [u8; 20],
) -> Result<bool> {
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,
Expand Down
18 changes: 15 additions & 3 deletions wallet-connect/examples/web3_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
};

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;

Expand All @@ -288,9 +288,21 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
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 {
Expand Down

0 comments on commit 9325e0d

Please sign in to comment.