Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem: missing verification api for wc 2.0 (fix #474) #475

Merged
merged 1 commit into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading