Skip to content

Commit

Permalink
Problem: missing verification api for wc 2.0 (fix #474) (#475)
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

reformat

change warning error level

chore: update cargo test command in CI workflow

chore: add RUSTFLAGS to enable dead code linting in CI workflow

chore: enable dead code linting in CI workflow

chore: update cargo test command in CI workflow

chore: update clippy command in CI workflow

feat: Update wallet_connect.cc to use Walletconnect2Client

feat: Update wallet_connect.cc to improve personal message signing and verification

feat: Fix c++ walletconnect example to use wc 2.0 and add verification for sign_personal

feat: Remove unnecessary include in wallet_connect.cc
  • Loading branch information
leejw51crypto authored May 22, 2024
1 parent 3b41318 commit 9eaa34d
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 61 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
check:
name: cargo check
runs-on: ubuntu-latest
env:
RUSTFLAGS: -A dead_code
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -35,6 +37,8 @@ jobs:
test:
name: cargo test
runs-on: ubuntu-latest
env:
RUSTFLAGS: -A dead_code
steps:
- uses: actions/checkout@v3
with:
Expand Down Expand Up @@ -73,6 +77,8 @@ jobs:
clippy:
name: cargo clippy
runs-on: ubuntu-latest
env:
RUSTFLAGS: -A dead_code
steps:
- uses: actions/checkout@v3
with:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog
## [Unreleased]

## [v0.0.27-alpha] - 2004-5-22
- fix c++ walletconnect example to use wc 2.0
- add verification for sign_personal

## [v0.0.26-alpha] - 2024-4-24
- fix null `data` field in wc 2.0

Expand Down
101 changes: 43 additions & 58 deletions demo/examples/src/wallet_connect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,35 +34,36 @@ 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 +79,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 @@ -138,11 +110,21 @@ int main(int argc, char *argv[]) {
// sign personal message
if (test_personal) {
/* message signing */
rust::Vec<uint8_t> 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<uint8_t> 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
Expand All @@ -166,12 +148,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<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 +188,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;
Expand All @@ -222,13 +206,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<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 9eaa34d

Please sign in to comment.