diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bca9d9cb..ac1d6d25 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }} - - run: cargo check --all + - run: cargo check test: name: cargo test runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index e82c96cc..2124cc61 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,21 @@ demo/cronos.h demo/sdk install + +wallet-connect/qrcode.png + +wallet-connect/session.bin + +defi-wallet-core-rs + +demo/third_party/easywsclient + +demo/third_party/json + +wallet-connect/yarn.lock + +wallet-connect/node_modules/ + +.DS_Store + +sessioninfo2.json diff --git a/Cargo.lock b/Cargo.lock index 337074eb..fd0c7dab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aead" version = "0.5.2" @@ -64,13 +70,19 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -203,7 +215,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -225,7 +237,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -242,7 +254,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -628,6 +640,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + [[package]] name = "byteorder" version = "1.4.3" @@ -744,14 +762,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "checked_int_cast" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919" + [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", - "num-integer", "num-traits", "serde", "winapi", @@ -797,7 +821,7 @@ dependencies = [ "bs58", "coins-core", "digest 0.10.7", - "getrandom 0.2.9", + "getrandom 0.2.10", "hmac", "k256", "lazy_static", @@ -814,7 +838,7 @@ checksum = "2a11892bcac83b4c6e95ab84b5b06c76d9d70ad73548dd07418269c5c7977171" dependencies = [ "bitvec 0.17.4", "coins-bip32", - "getrandom 0.2.9", + "getrandom 0.2.10", "hex", "hmac", "pbkdf2", @@ -844,6 +868,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "concurrent-queue" version = "2.2.0" @@ -910,7 +940,7 @@ dependencies = [ "cosmos-sdk-proto", "ecdsa", "eyre", - "getrandom 0.2.9", + "getrandom 0.2.10", "k256", "rand_core 0.6.4", "serde", @@ -1069,7 +1099,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -1086,7 +1116,7 @@ checksum = "4a076022ece33e7686fb76513518e219cca4fce5750a8ae6d1ce6c0f48fd1af9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -1110,7 +1140,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -1121,7 +1151,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -1134,7 +1164,7 @@ dependencies = [ "hashbrown 0.12.3", "lock_api", "once_cell", - "parking_lot_core 0.9.7", + "parking_lot_core 0.9.8", ] [[package]] @@ -1161,7 +1191,9 @@ dependencies = [ "hex", "hkdf", "hmac", + "image", "open", + "qrcode", "qrcodegen", "quickcheck", "quickcheck_macros", @@ -1261,6 +1293,16 @@ dependencies = [ "tonic", ] +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + [[package]] name = "der" version = "0.6.1" @@ -1357,7 +1399,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -1500,7 +1542,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -1672,7 +1714,7 @@ dependencies = [ "ethers-core", "ethers-etherscan", "eyre", - "getrandom 0.2.9", + "getrandom 0.2.10", "hex", "prettyplease", "proc-macro2", @@ -1718,7 +1760,7 @@ dependencies = [ "elliptic-curve", "ethabi", "generic-array 0.14.7", - "getrandom 0.2.9", + "getrandom 0.2.10", "hex", "k256", "num_enum", @@ -1746,7 +1788,7 @@ checksum = "0d769437fafd0b47ea8b95e774e343c5195c77423f0f54b48d11c0d9ed2148ad" dependencies = [ "ethers-core", "ethers-solc", - "getrandom 0.2.9", + "getrandom 0.2.10", "reqwest", "semver", "serde", @@ -1797,7 +1839,7 @@ dependencies = [ "futures-core", "futures-timer", "futures-util", - "getrandom 0.2.9", + "getrandom 0.2.10", "hashers", "hex", "http", @@ -1848,7 +1890,7 @@ dependencies = [ "cfg-if", "dunce", "ethers-core", - "getrandom 0.2.9", + "getrandom 0.2.10", "glob", "hex", "home", @@ -1970,7 +2012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -1991,9 +2033,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -2095,7 +2137,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -2175,9 +2217,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -2186,6 +2228,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gif" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "glob" version = "0.3.1" @@ -2374,7 +2426,7 @@ dependencies = [ "hyper", "rustls 0.21.1", "tokio", - "tokio-rustls 0.24.0", + "tokio-rustls 0.24.1", ] [[package]] @@ -2391,9 +2443,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2483,14 +2535,33 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", ] +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "gif", + "jpeg-decoder", + "num-iter", + "num-rational 0.3.2", + "num-traits", + "png", + "scoped_threadpool", + "tiff", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -2650,6 +2721,15 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +dependencies = [ + "rayon", +] + [[package]] name = "js-sys" version = "0.3.63" @@ -2748,9 +2828,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "link-cplusplus" @@ -2779,9 +2859,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -2789,12 +2869,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matchit" @@ -2841,6 +2918,25 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -2852,14 +2948,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2891,7 +2986,7 @@ dependencies = [ "num-complex", "num-integer", "num-iter", - "num-rational", + "num-rational 0.4.1", "num-traits", ] @@ -2947,6 +3042,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.1" @@ -3001,9 +3107,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -3118,7 +3224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.7", + "parking_lot_core 0.9.8", ] [[package]] @@ -3137,15 +3243,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] @@ -3227,9 +3333,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" @@ -3261,7 +3367,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -3363,7 +3469,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -3402,6 +3508,18 @@ dependencies = [ "extra-cpp-bindings", ] +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide 0.3.7", +] + [[package]] name = "polling" version = "2.8.0" @@ -3510,9 +3628,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] @@ -3549,6 +3667,16 @@ dependencies = [ "prost", ] +[[package]] +name = "qrcode" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f" +dependencies = [ + "checked_int_cast", + "image", +] + [[package]] name = "qrcodegen" version = "1.8.0" @@ -3657,7 +3785,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", ] [[package]] @@ -3715,16 +3843,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.8.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", @@ -3813,7 +3941,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls 0.24.0", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -3896,9 +4024,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags", "errno", @@ -4073,6 +4201,12 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + [[package]] name = "scopeguard" version = "1.1.0" @@ -4189,9 +4323,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] @@ -4217,13 +4351,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -4256,7 +4390,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -4296,7 +4430,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -4405,9 +4539,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "siwe" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4cc2eafb2354c1aeaeac5f53b7726ca4ea5ad16314a0b5ebacb6676f599c2b" +checksum = "4e6d1f422a568af1e98db37c6d0427c7218459ccac39218fd15a51a34d3933af" dependencies = [ "hex", "http", @@ -4574,9 +4708,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45b6ddbb36c5b969c182aec3c4a0bce7df3fbad4b77114706a49aacc80567388" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -4597,15 +4731,16 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -4710,7 +4845,7 @@ checksum = "991779ca9b697471df9d436489774d144a418c0e5da843c58ff9288105d5ddaa" dependencies = [ "bytes", "flex-error", - "getrandom 0.2.9", + "getrandom 0.2.10", "peg", "pin-project", "serde", @@ -4764,7 +4899,18 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", +] + +[[package]] +name = "tiff" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" +dependencies = [ + "jpeg-decoder", + "miniz_oxide 0.4.4", + "weezl", ] [[package]] @@ -4820,9 +4966,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", @@ -4853,7 +4999,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -4869,9 +5015,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls 0.21.1", "tokio", @@ -5056,7 +5202,7 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] @@ -5196,9 +5342,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -5218,7 +5364,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", "serde", ] @@ -5228,7 +5374,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", "serde", "wasm-bindgen", ] @@ -5300,7 +5446,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", "wasm-bindgen-shared", ] @@ -5334,7 +5480,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5402,6 +5548,12 @@ dependencies = [ "webpki", ] +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + [[package]] name = "winapi" version = "0.3.9" @@ -5439,7 +5591,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets", ] [[package]] @@ -5457,37 +5609,13 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -5745,7 +5873,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.17", + "syn 2.0.18", ] [[package]] diff --git a/defi-wallet-core-rs b/defi-wallet-core-rs index c68c9111..e452233f 160000 --- a/defi-wallet-core-rs +++ b/defi-wallet-core-rs @@ -1 +1 @@ -Subproject commit c68c9111ac7cea7f376badc3e7fa9297e4e4321f +Subproject commit e452233f54012ae16ba37e12b05aff9f3695ffc6 diff --git a/demo/extra.cc b/demo/extra.cc index b3570938..d4f8426e 100644 --- a/demo/extra.cc +++ b/demo/extra.cc @@ -5,6 +5,7 @@ #include "sdk/include/rust/cxx.h" #include "third_party/easywsclient/easywsclient.hpp" #include "third_party/json/single_include/nlohmann/json.hpp" +#include #include #include #include @@ -363,16 +364,17 @@ void test_wallet_connect() { * @summary test wallet connect 2.0 * @description basic test for wallet connect 2.0 */ - void test_wallet_connect2() { std::string mycronosrpc = getEnv("CRONOSRPC").c_str(); - bool test_personal = true; - bool test_basic = false; + bool test_personal = false; + bool test_basic = true; bool test_nft = false; std::string filename = "sessioninfo2.json"; bool exit_program = false; try { Box client = make_new_client2(filename); + String uri = client->print_uri(); + std::cout << "uri= " << uri.c_str() << std::endl; WalletConnect2EnsureSessionResult result = client->ensure_session_blocking(60000); std::cout << "session result=" << result.eip155.accounts.size() @@ -405,7 +407,6 @@ void test_wallet_connect2() { } assert(result.eip155.accounts.size() > 0); - bool test_personal = true; if (test_personal) { Vec sig1 = client->sign_personal_blocking( @@ -413,6 +414,30 @@ void test_wallet_connect2() { std::cout << "signature length=" << sig1.size() << endl; } + if (test_basic) { + std::string fromaddress = getenv("MYFROMADDRESS"); + std::cout << "mycronosrpc=" << mycronosrpc << endl; + std::cout << "fromaddress=" << fromaddress << endl; + std::string toaddress = getenv("MYTOADDRESS"); + std::cout << "toaddress=" << toaddress << endl; + std::string mynonce = org::defi_wallet_core::get_eth_nonce( + fromaddress.c_str(), mycronosrpc) + .c_str(); + std::cout << "nonce=" << mynonce << endl; + WalletConnectTxEip155 info; + info.to = toaddress; + info.common.gas_limit = "21000"; // gas limit + info.common.gas_price = "10000"; // gas price + info.value = "100000000000000"; // 0.0001 eth + info.data = Vec(); + info.common.nonce = mynonce; + info.common.chainid = 1; + + assert(result.eip155.accounts.size() > 0); + Vec rawtx = client->sign_eip155_transaction_blocking( + info, result.eip155.accounts[0].address.address); + } + std::cout << "enter q to exit" << std::endl; while (true) { // read input, if q is pressed, quit diff --git a/demo/main.cc b/demo/main.cc index e84e4dbb..8c292bf3 100644 --- a/demo/main.cc +++ b/demo/main.cc @@ -26,7 +26,6 @@ int main(int argc, char *argv[]) { test_interval(); test_blackscout_cronoscan(); test_wallet_connect(); - } catch (const std::exception &e) { // Use `Assertion failed`, the same as `assert` function std::cout << "Assertion failed: " << e.what() << std::endl; diff --git a/extra-cpp-bindings/src/lib.rs b/extra-cpp-bindings/src/lib.rs index e0c6b85a..88a251e3 100644 --- a/extra-cpp-bindings/src/lib.rs +++ b/extra-cpp-bindings/src/lib.rs @@ -334,6 +334,7 @@ mod ffi { pub fn save_client(self: &mut Walletconnect2Client) -> Result; /// print qrcode in termal, for debugging pub fn print_uri(self: &mut WalletconnectClient) -> Result; + pub fn print_uri(self: &mut Walletconnect2Client) -> Result; /// sign message pub fn sign_personal_blocking( self: &mut WalletconnectClient, @@ -354,6 +355,11 @@ mod ffi { info: &WalletConnectTxEip155, address: [u8; 20], ) -> Result>; + pub fn sign_eip155_transaction_blocking( + self: &mut Walletconnect2Client, + info: &WalletConnectTxEip155, + address: [u8; 20], + ) -> Result>; /// send cronos(eth) eip155 transaction /// Supported Wallets: Trust Wallet, MetaMask and Crypto.com Mobile Defi Wallet @@ -362,6 +368,11 @@ mod ffi { info: &WalletConnectTxEip155, address: [u8; 20], ) -> Result>; + pub fn send_eip155_transaction_blocking( + self: &mut Walletconnect2Client, + info: &WalletConnectTxEip155, + address: [u8; 20], + ) -> Result>; /// eip1559_transaction_request: json string of Eip1559TransactionRequest /// return signed transaction bytes @@ -370,6 +381,11 @@ mod ffi { eip1559_transaction_request: String, address: [u8; 20], ) -> Result>; + pub fn sign_transaction( + self: &mut Walletconnect2Client, + eip1559_transaction_request: String, + address: [u8; 20], + ) -> Result>; /// eip1559_transaction_request: json string of Eip1559TransactionRequest /// return transaction hash bytes @@ -378,6 +394,11 @@ mod ffi { eip1559_transaction_request: String, address: [u8; 20], ) -> Result>; + pub fn send_transaction( + self: &mut Walletconnect2Client, + eip1559_transaction_request: String, + address: [u8; 20], + ) -> Result>; /// sign a contract transaction /// contract_action is a json string of `ContractAction` type, for example: @@ -398,6 +419,12 @@ mod ffi { common: &WalletConnectTxCommon, address: [u8; 20], ) -> Result>; + pub fn sign_contract_transaction( + self: &mut Walletconnect2Client, + contract_action: String, + common: &WalletConnectTxCommon, + address: [u8; 20], + ) -> Result>; // send a contract transaction /// contract_action is a json string of `ContractAction` type @@ -418,6 +445,12 @@ mod ffi { common: &WalletConnectTxCommon, address: [u8; 20], ) -> Result>; + pub fn send_contract_transaction( + self: &mut Walletconnect2Client, + contract_action: String, + common: &WalletConnectTxCommon, + address: [u8; 20], + ) -> Result>; /// returns the transactions of a given address. /// The API key can be obtained from https://cronoscan.com @@ -1017,14 +1050,12 @@ pub fn walletconnect2_client_new( return Err(anyhow!("project_id is empty")); } // print all arguments - println!("relay_server_string: {:?}", relay_server_string); - println!("project_id: {:?}", project_id); - println!("required_namespaces_json: {:?}", required_namespaces_json); - println!("client_meta_json: {:?}", client_meta_json); + println!("relay_server_string: {relay_server_string:?}"); + println!("project_id: {project_id:?}"); + println!("required_namespaces_json: {required_namespaces_json:?}"); + println!("client_meta_json: {client_meta_json:?}"); let mut opts = defi_wallet_connect::v2::ClientOptions::default(); - // print opts - println!("opts1: {:?}", opts); if !relay_server_string.is_empty() { let relay_server = url::Url::parse(&relay_server_string)?; @@ -1047,11 +1078,11 @@ pub fn walletconnect2_client_new( opts.client_meta = client_meta; } - println!("opts: {:?}", opts); + println!("opts: {opts:?}"); let required_namespaces = serde_json::to_string(&opts.required_namespaces)?; - println!("required_namespaces_json: {}", required_namespaces); + println!("required_namespaces_json: {required_namespaces}",); let client_meta = serde_json::to_string(&opts.client_meta)?; - println!("client_meta_json: {}", client_meta); + println!("client_meta_json: {client_meta}"); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); diff --git a/extra-cpp-bindings/src/walletconnect.rs b/extra-cpp-bindings/src/walletconnect.rs index b50223fb..05ea1ee9 100644 --- a/extra-cpp-bindings/src/walletconnect.rs +++ b/extra-cpp-bindings/src/walletconnect.rs @@ -384,7 +384,7 @@ impl WalletconnectClient { if !userinfo.common.nonce.is_empty() { tx = tx.nonce(U256::from_dec_str(&userinfo.common.nonce)?); } - if !userinfo.common.chainid == 0 { + if userinfo.common.chainid != 0 { tx = tx.chain_id(userinfo.common.chainid); } if !userinfo.value.is_empty() { @@ -437,7 +437,7 @@ impl WalletconnectClient { if !userinfo.common.nonce.is_empty() { tx = tx.nonce(U256::from_dec_str(&userinfo.common.nonce)?); } - if !userinfo.common.chainid == 0 { + if userinfo.common.chainid != 0 { tx = tx.chain_id(userinfo.common.chainid); } if !userinfo.value.is_empty() { diff --git a/extra-cpp-bindings/src/walletconnect2.rs b/extra-cpp-bindings/src/walletconnect2.rs index 58b5f4ac..d6646c2a 100644 --- a/extra-cpp-bindings/src/walletconnect2.rs +++ b/extra-cpp-bindings/src/walletconnect2.rs @@ -1,9 +1,22 @@ use crate::ffi::WalletConnect2Eip155Accounts; use crate::ffi::WalletConnect2EnsureSessionResult; use crate::ffi::WalletConnectAddress; +use crate::ffi::WalletConnectTxCommon; use anyhow::{anyhow, Result}; use defi_wallet_connect::v2::Namespaces; use defi_wallet_connect::v2::{Client, ClientOptions, SessionInfo}; +use qrcodegen::{QrCode, QrCodeEcc}; + +use defi_wallet_connect::v2::WCMiddleware; + +use ethers::core::types::transaction::eip2718::TypedTransaction; + +use ethers::prelude::{Address, Eip1559TransactionRequest, NameOrAddress, U256}; +use ethers::prelude::{Middleware, Signature, TxHash}; +use ethers::types::H160; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; + pub struct Walletconnect2Client { pub client: Option, pub rt: tokio::runtime::Runtime, // need to use the same runtime, otherwise c++ side crash @@ -11,6 +24,38 @@ pub struct Walletconnect2Client { pub rx: tokio::sync::mpsc::UnboundedReceiver, // receiver } +#[derive(Serialize, Deserialize)] +enum ContractAction { + ContractApproval(defi_wallet_core_common::ContractApproval), + ContractTransfer(defi_wallet_core_common::ContractTransfer), +} + +/// sign eip-155 transaction +/// client: client for walletconnect +/// tx: transaction info +/// address: address of the signer +/// returns: Signature +async fn sign_typed_tx( + client: Client, + tx: &TypedTransaction, + address: Address, +) -> Result { + let middleware = WCMiddleware::new(client); + let signature = middleware.sign_transaction(tx, address).await?; + Ok(signature) +} + +/// send eip-155 transaction +/// client: client for walletconnect +/// tx: transaction info +/// address: address of the signer +/// returns: TxHash +async fn send_typed_tx(client: Client, tx: TypedTransaction, address: Address) -> Result { + let middleware = WCMiddleware::new(client).with_sender(address); + let receipt = middleware.send_transaction(tx, None).await?.tx_hash(); + Ok(receipt) +} + pub async fn restore_client( contents: String, callback_sender: Option>, @@ -65,6 +110,37 @@ impl Walletconnect2Client { }, ) } + + fn print_qr(qr: &QrCode) { + let border: i32 = 1; + for y in -border..qr.size() + border { + for x in -border..qr.size() + border { + let c = if qr.get_module(x, y) { + "\x1b[40m \x1b[0m" + } else { + "\x1b[47m \x1b[0m" + }; + print!("{c}"); + } + println!(); + } + println!(); + } + + /// print uri(qrcode) for debugging + pub fn print_uri(&mut self) -> Result { + if let Some(client) = self.client.as_ref() { + let result = self.rt.block_on(client.get_session_info()); + let uristring = result.uri(); + if let Ok(qr) = QrCode::encode_text(&uristring, QrCodeEcc::Medium) { + Self::print_qr(&qr); + } + Ok(uristring) + } else { + anyhow::bail!("no client"); + } + } + pub fn sign_personal_blocking( &mut self, message: String, @@ -152,4 +228,328 @@ impl Walletconnect2Client { }, ) } + + /// build cronos(eth) eip155 transaction + pub fn sign_eip155_transaction_blocking( + &mut self, + userinfo: &crate::ffi::WalletConnectTxEip155, + address: [u8; 20], + ) -> Result> { + if self.client.is_none() { + anyhow::bail!("no client"); + } + + let client = self + .client + .as_ref() + .ok_or_else(|| anyhow!("get walllet-connect client error"))?; + let signeraddress = Address::from_slice(&address); + + let mut tx = Eip1559TransactionRequest::new(); + + if !userinfo.to.is_empty() { + tx = tx.to(NameOrAddress::Address(Address::from_str(&userinfo.to)?)); + } + if !userinfo.data.is_empty() { + tx = tx.data(userinfo.data.as_slice().to_vec()); + } + if !userinfo.common.gas_limit.is_empty() { + tx = tx.gas(U256::from_dec_str(&userinfo.common.gas_limit)?); + } + if !userinfo.common.gas_price.is_empty() { + tx = tx + .max_priority_fee_per_gas(U256::from_dec_str(&userinfo.common.gas_price)?) + .max_fee_per_gas(U256::from_dec_str(&userinfo.common.gas_price)?); + } + if !userinfo.common.nonce.is_empty() { + tx = tx.nonce(U256::from_dec_str(&userinfo.common.nonce)?); + } + if userinfo.common.chainid != 0 { + tx = tx.chain_id(userinfo.common.chainid); + } + if !userinfo.value.is_empty() { + tx = tx.value(U256::from_dec_str(&userinfo.value)?); + } + let newclient = client.clone(); + let typedtx = TypedTransaction::Eip1559(tx); + + let sig = self + .rt + .block_on(sign_typed_tx(newclient, &typedtx, signeraddress)) + .map_err(|e| anyhow!("sign_typed_transaction error {}", e.to_string()))?; + + let signed_tx = &typedtx.rlp_signed(&sig); + Ok(signed_tx.to_vec()) + } + + /// send cronos(eth) eip155 transaction + pub fn send_eip155_transaction_blocking( + &mut self, + userinfo: &crate::ffi::WalletConnectTxEip155, + address: [u8; 20], + ) -> Result> { + if self.client.is_none() { + anyhow::bail!("no client"); + } + + let client = self + .client + .as_ref() + .ok_or_else(|| anyhow!("get walllet-connect client error"))?; + let signeraddress = Address::from_slice(&address); + + let mut tx = Eip1559TransactionRequest::new(); + + if !userinfo.to.is_empty() { + tx = tx.to(NameOrAddress::Address(Address::from_str(&userinfo.to)?)); + } + if !userinfo.data.is_empty() { + tx = tx.data(userinfo.data.as_slice().to_vec()); + } + if !userinfo.common.gas_limit.is_empty() { + tx = tx.gas(U256::from_dec_str(&userinfo.common.gas_limit)?); + } + if !userinfo.common.gas_price.is_empty() { + tx = tx + .max_priority_fee_per_gas(U256::from_dec_str(&userinfo.common.gas_price)?) + .max_fee_per_gas(U256::from_dec_str(&userinfo.common.gas_price)?); + } + if !userinfo.common.nonce.is_empty() { + tx = tx.nonce(U256::from_dec_str(&userinfo.common.nonce)?); + } + if userinfo.common.chainid != 0 { + tx = tx.chain_id(userinfo.common.chainid); + } + if !userinfo.value.is_empty() { + tx = tx.value(U256::from_dec_str(&userinfo.value)?); + } + + let newclient = client.clone(); + let typedtx = TypedTransaction::Eip1559(tx); + + let tx_bytes = self + .rt + .block_on(send_typed_tx(newclient, typedtx, signeraddress)) + .map_err(|e| anyhow!("send_typed_transaction error {}", e.to_string()))?; + + Ok(tx_bytes.0.to_vec()) + } + + fn get_signed_tx_raw_bytes( + &self, + newclient: Client, + signeraddress: H160, + typedtx: &mut TypedTransaction, + common: &WalletConnectTxCommon, + ) -> Result> { + let mynonce = U256::from_dec_str(&common.nonce)?; + if !mynonce.is_zero() { + typedtx.set_nonce(mynonce); + } + typedtx.set_from(signeraddress); + if !common.chainid == 0 { + typedtx.set_chain_id(common.chainid); + } + if !common.gas_limit.is_empty() { + typedtx.set_gas(U256::from_dec_str(&common.gas_limit)?); + } + if !common.gas_price.is_empty() { + typedtx.set_gas_price(U256::from_dec_str(&common.gas_price)?); + } + + let sig = self + .rt + .block_on(sign_typed_tx(newclient, typedtx, signeraddress)) + .map_err(|e| anyhow!("sign_typed_transaction error {}", e.to_string()))?; + + let signed_tx = &typedtx.rlp_signed(&sig); + Ok(signed_tx.to_vec()) + } + + fn get_sent_tx_raw_bytes( + &self, + newclient: Client, + signeraddress: H160, + typedtx: &mut TypedTransaction, + common: &WalletConnectTxCommon, + ) -> Result> { + let mynonce = U256::from_dec_str(&common.nonce)?; + if !mynonce.is_zero() { + typedtx.set_nonce(mynonce); + } + typedtx.set_from(signeraddress); + if !common.chainid == 0 { + typedtx.set_chain_id(common.chainid); + } + if !common.gas_limit.is_empty() { + typedtx.set_gas(U256::from_dec_str(&common.gas_limit)?); + } + if !common.gas_price.is_empty() { + typedtx.set_gas_price(U256::from_dec_str(&common.gas_price)?); + } + + let tx_bytes = self + .rt + .block_on(send_typed_tx(newclient, typedtx.clone(), signeraddress)) + .map_err(|e| anyhow!("send_typed_transaction error {}", e.to_string()))?; + + Ok(tx_bytes.0.to_vec()) + } + + pub fn sign_transaction( + &mut self, + eip1559_transaction_request: String, + address: [u8; 20], + ) -> Result> { + if self.client.is_none() { + anyhow::bail!("no client"); + } + + let client = self + .client + .as_ref() + .ok_or_else(|| anyhow!("get walllet-connect client error"))?; + let signeraddress = Address::from_slice(&address); + + // parse json string transaction_info to TransactionRequest + let tx: Eip1559TransactionRequest = serde_json::from_str(&eip1559_transaction_request)?; + let typedtx = TypedTransaction::Eip1559(tx); + + let newclient = client.clone(); + let sig = self + .rt + .block_on(sign_typed_tx(newclient, &typedtx, signeraddress)) + .map_err(|e| anyhow!("sign_typed_transaction error {}", e.to_string()))?; + + let signed_tx = &typedtx.rlp_signed(&sig); + Ok(signed_tx.to_vec()) + } + + pub fn send_transaction( + &mut self, + eip1559_transaction_request: String, + address: [u8; 20], + ) -> Result> { + if self.client.is_none() { + anyhow::bail!("no client"); + } + + let client = self + .client + .as_ref() + .ok_or_else(|| anyhow!("get walllet-connect client error"))?; + let signeraddress = Address::from_slice(&address); + + // parse json string transaction_info to TransactionRequest + let tx: Eip1559TransactionRequest = serde_json::from_str(&eip1559_transaction_request)?; + let typedtx = TypedTransaction::Eip1559(tx); + + let newclient = client.clone(); + let tx_bytes = self + .rt + .block_on(send_typed_tx(newclient, typedtx, signeraddress)) + .map_err(|e| anyhow!("send_typed_transaction error {}", e.to_string()))?; + + Ok(tx_bytes.0.to_vec()) + } + + pub fn sign_contract_transaction( + &mut self, + contract_action: String, + common: &WalletConnectTxCommon, + address: [u8; 20], + ) -> Result> { + if self.client.is_none() { + anyhow::bail!("no client"); + } + let signeraddress = Address::from_slice(&address); + let client = self + .client + .as_ref() + .ok_or_else(|| anyhow!("get walllet-connect client error"))?; + let newclient = client.clone(); + + let action: ContractAction = serde_json::from_str(&contract_action)?; + // parse json string transaction_info to TransactionRequest + // let tx: ContractTransfer = serde_json::from_str(&contract_transaction_info)?; + + let mut typedtx = match action { + ContractAction::ContractApproval(approval) => { + self.rt + .block_on(defi_wallet_core_common::construct_contract_approval_tx( + approval, + defi_wallet_core_common::EthNetwork::Custom { + chain_id: common.chainid, + legacy: false, + }, + common.web3api_url.as_str(), + ))? + } + ContractAction::ContractTransfer(transfer) => { + self.rt + .block_on(defi_wallet_core_common::construct_contract_transfer_tx( + transfer, + defi_wallet_core_common::EthNetwork::Custom { + chain_id: common.chainid, + legacy: false, + }, + // TODO unnessary for walletconnect + common.web3api_url.as_str(), + ))? + } + }; + + let tx = self.get_signed_tx_raw_bytes(newclient, signeraddress, &mut typedtx, common)?; + Ok(tx.to_vec()) + } + + pub fn send_contract_transaction( + &mut self, + contract_action: String, + common: &WalletConnectTxCommon, + address: [u8; 20], + ) -> Result> { + if self.client.is_none() { + anyhow::bail!("no client"); + } + let signeraddress = Address::from_slice(&address); + let client = self + .client + .as_ref() + .ok_or_else(|| anyhow!("get walllet-connect client error"))?; + let newclient = client.clone(); + + let action: ContractAction = serde_json::from_str(&contract_action)?; + // parse json string transaction_info to TransactionRequest + // let tx: ContractTransfer = serde_json::from_str(&contract_transaction_info)?; + + let mut typedtx = match action { + ContractAction::ContractApproval(approval) => { + self.rt + .block_on(defi_wallet_core_common::construct_contract_approval_tx( + approval, + defi_wallet_core_common::EthNetwork::Custom { + chain_id: common.chainid, + legacy: false, + }, + common.web3api_url.as_str(), + ))? + } + ContractAction::ContractTransfer(transfer) => { + self.rt + .block_on(defi_wallet_core_common::construct_contract_transfer_tx( + transfer, + defi_wallet_core_common::EthNetwork::Custom { + chain_id: common.chainid, + legacy: false, + }, + // TODO unnessary for walletconnect + common.web3api_url.as_str(), + ))? + } + }; + + let tx = self.get_sent_tx_raw_bytes(newclient, signeraddress, &mut typedtx, common)?; + Ok(tx.to_vec()) + } } diff --git a/wallet-connect/Cargo.toml b/wallet-connect/Cargo.toml index c34b4e19..bc32797c 100644 --- a/wallet-connect/Cargo.toml +++ b/wallet-connect/Cargo.toml @@ -34,6 +34,8 @@ url = { version = "2", features = ["serde"] } x25519-dalek = "1" zeroize = "1" hex = "0.4" +qrcode = "0.12" +image = "0.23" [dev-dependencies] quickcheck = "1" diff --git a/wallet-connect/examples/web3_v2.rs b/wallet-connect/examples/web3_v2.rs index 4010ba2f..f8e952f8 100644 --- a/wallet-connect/examples/web3_v2.rs +++ b/wallet-connect/examples/web3_v2.rs @@ -1,6 +1,38 @@ +use eyre::Result; +use image::Luma; +use qrcode::QrCode; + +use ethers::abi::Address; +use ethers::core::types::transaction::eip2718::TypedTransaction; +//use ethers::ethers_providers::Middleware; +use defi_wallet_connect::v2::WCMiddleware; +use ethers::prelude::*; + +use std::str::FromStr; + use defi_wallet_connect::v2::{Client, ClientOptions, Metadata, RequiredNamespaces, SessionInfo}; use std::error::Error; use std::io::BufRead; + +#[derive(Debug, Default)] +pub struct WalletConnectTxCommon { + pub gas_limit: String, // decimal string, "1" + pub gas_price: String, // decimal string + pub nonce: String, // decimal string + pub chainid: u64, // integer u64 + pub web3api_url: String, // string +} + +/// wallet connect cronos(eth) eip155-tx signing info +#[derive(Debug, Default)] +pub struct WalletConnectTxEip155 { + pub to: String, // hexstring, "0x..." + pub value: String, // decimal string, in wei units + pub data: Vec, // data, as bytes + + pub common: WalletConnectTxCommon, +} + async fn make_client( callback_sender: Option>, ) -> Result { @@ -42,8 +74,132 @@ async fn save(info: &SessionInfo) -> eyre::Result<()> { Ok(()) } +async fn sign_typed_tx( + client: Client, + tx: &TypedTransaction, + address: Address, +) -> Result { + let middleware = WCMiddleware::new(client); + let signature = middleware.sign_transaction(tx, address).await?; + Ok(signature) +} + +async fn send_typed_tx(client: Client, tx: TypedTransaction, address: Address) -> Result { + let middleware = WCMiddleware::new(client).with_sender(address); + let receipt = middleware.send_transaction(tx, None).await?.tx_hash(); + Ok(receipt) +} + +pub async fn sign_eip155_transaction_blocking( + client: &mut Client, + userinfo: &WalletConnectTxEip155, + address: [u8; 20], +) -> Result> { + let signeraddress = Address::from_slice(&address); + + let mut tx = Eip1559TransactionRequest::new(); + + if !userinfo.to.is_empty() { + tx = tx.to(NameOrAddress::Address(Address::from_str(&userinfo.to)?)); + } + if !userinfo.data.is_empty() { + tx = tx.data(userinfo.data.as_slice().to_vec()); + } + if !userinfo.common.gas_limit.is_empty() { + tx = tx.gas(U256::from_dec_str(&userinfo.common.gas_limit)?); + } + if !userinfo.common.gas_price.is_empty() { + tx = tx + .max_priority_fee_per_gas(U256::from_dec_str(&userinfo.common.gas_price)?) + .max_fee_per_gas(U256::from_dec_str(&userinfo.common.gas_price)?); + } + if !userinfo.common.nonce.is_empty() { + tx = tx.nonce(U256::from_dec_str(&userinfo.common.nonce)?); + } + if userinfo.common.chainid != 0 { + // tx = tx.chain_id(userinfo.common.chainid); + } + if !userinfo.value.is_empty() { + tx = tx.value(U256::from_dec_str(&userinfo.value)?); + } + let newclient = client.clone(); + let typedtx = TypedTransaction::Eip1559(tx); + + let mut sig = sign_typed_tx(newclient, &typedtx, signeraddress) + .await + .map_err(|e| eyre::eyre!("sign_typed_transaction error {}", e.to_string()))?; + + // eip155 v == chainid*2 + 35 + recovery (0 or 1), for mainnet 37 or 38 + // non eip155 v == 27 + recovery (0 or 1) + if sig.v == 27 || sig.v == 28 { + let recovery = sig.v - 27; + sig.v = recovery + 35 + userinfo.common.chainid * 2; + } + + let signed_tx = &typedtx.rlp_signed(&sig); + Ok(signed_tx.to_vec()) +} + +pub async fn send_eip155_transaction_blocking( + client: &mut Client, + userinfo: &WalletConnectTxEip155, + address: [u8; 20], +) -> Result> { + let signeraddress = Address::from_slice(&address); + + let mut tx = Eip1559TransactionRequest::new(); + + if !userinfo.to.is_empty() { + tx = tx.to(NameOrAddress::Address(Address::from_str(&userinfo.to)?)); + } + if !userinfo.data.is_empty() { + tx = tx.data(userinfo.data.as_slice().to_vec()); + } + if !userinfo.common.gas_limit.is_empty() { + tx = tx.gas(U256::from_dec_str(&userinfo.common.gas_limit)?); + } + if !userinfo.common.gas_price.is_empty() { + tx = tx + .max_priority_fee_per_gas(U256::from_dec_str(&userinfo.common.gas_price)?) + .max_fee_per_gas(U256::from_dec_str(&userinfo.common.gas_price)?); + } + if !userinfo.common.nonce.is_empty() { + tx = tx.nonce(U256::from_dec_str(&userinfo.common.nonce)?); + } + if userinfo.common.chainid != 0 { + // tx = tx.chain_id(userinfo.common.chainid); + } + if !userinfo.value.is_empty() { + tx = tx.value(U256::from_dec_str(&userinfo.value)?); + } + + let newclient = client.clone(); + let typedtx = TypedTransaction::Eip1559(tx); + + // print typedtx + println!("typedtx: {:?}", typedtx); + println!("send tx: {:?}", typedtx); + let tx_bytes = send_typed_tx(newclient, typedtx, signeraddress) + .await + .map_err(|e| eyre::eyre!("send_typed_transaction error {}", e.to_string()))?; + + //Ok(tx_bytes.0.to_vec()) + Ok(tx_bytes.0.to_vec()) +} + +async fn make_qrcode(uri: &str) -> Result<()> { + // Generate the QR code for the data you want + let code = QrCode::new(uri)?; + + // Create an empty image buffer + let image = code.render::>().build(); + image.save("qrcode.png")?; + + Ok(()) +} #[tokio::main] async fn main() -> Result<(), Box> { + println!("walletconnect v2.0"); let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); tokio::spawn(async move { while let Some(msg) = rx.recv().await { @@ -60,11 +216,15 @@ async fn main() -> Result<(), Box> { make_client(callback_sender).await? }; - let test_ping = true; - let test_signing = true; + let test_ping = false; + let test_signing = false; + let test_tx = true; let test_event_listening = false; let uri = client.get_connection_string().await; + // make qrimage with uri + make_qrcode(&uri).await?; + println!("uri= {}", uri); let namespaces = client.ensure_session().await?; println!( @@ -84,6 +244,35 @@ async fn main() -> Result<(), Box> { println!("sig1: {:?}", sig1); } + if test_tx { + // read env MYTOADDRESS + let to = std::env::var("MYTOADDRESS").expect("MYTOADDRESS not set"); + let fromaddress = namespaces.get_ethereum_addresses()[0].address.clone(); + // print fromaddress + println!("fromaddress= {:?}", fromaddress); + let txinfo = WalletConnectTxEip155 { + common: WalletConnectTxCommon { + chainid: 5, + gas_limit: "21000".into(), + gas_price: "1000000000".into(), + nonce: "0".into(), + web3api_url: "".into(), + }, + to: to.into(), + data: vec![], + value: "1000".into(), + }; + let sig = sign_eip155_transaction_blocking( + &mut client, + &txinfo, + (*fromaddress.as_fixed_bytes()).into(), + ) + .await?; + let sig_hex = hex::encode(sig.as_slice()); + let sig_hex_length = sig_hex.len(); + println!("signature length {sig_hex_length} 0x{sig_hex}"); + } + if test_event_listening { println!("press anykey to exit"); loop { diff --git a/wallet-connect/src/v2/client.rs b/wallet-connect/src/v2/client.rs index 75ade543..5d495d24 100644 --- a/wallet-connect/src/v2/client.rs +++ b/wallet-connect/src/v2/client.rs @@ -195,6 +195,9 @@ impl WCMiddleware> { pub fn new(client: Client) -> Self { WCMiddleware(Provider::new(client)) } + pub fn with_sender(self, address: impl Into
) -> Self { + WCMiddleware(self.0.with_sender(address)) + } } /// The wrapper error type for `ethers` middleware-related issues @@ -219,6 +222,26 @@ impl MiddlewareError for WCError { } } +/// make string even length by padding with 0 +/// s : string to pad +fn pad_zero(s: String) -> String { + if s.len() % 2 != 0 { + format!("0{s}") + } else { + s + } +} + +/// add 0x prefix if not present +/// s: string to append 0x to +fn append_hex(s: String) -> String { + if s.starts_with("0x") { + s + } else { + format!("0x{s}") + } +} + #[async_trait] impl Middleware for WCMiddleware> { type Error = WCError>; @@ -245,23 +268,23 @@ impl Middleware for WCMiddleware> { } if let Some(data) = tx.data() { tx_obj.insert("data", format!("0x{}", hex::encode(data))); - } else { - tx_obj.insert("data", "".to_string()); } if let Some(gas) = tx.gas() { - tx_obj.insert("gas", format!("0x{gas:x}")); + // gas not working for webwallet + tx_obj.insert("gasLimit", append_hex(pad_zero(format!("{gas:x}")))); } + if let Some(gas_price) = tx.gas_price() { - tx_obj.insert("gasPrice", format!("0x{gas_price:x}")); + tx_obj.insert("gasPrice", append_hex(pad_zero(format!("{gas_price:x}")))); } if let Some(value) = tx.value() { - tx_obj.insert("value", format!("0x{value:x}")); + tx_obj.insert("value", append_hex(pad_zero(format!("{value:x}")))); } if let Some(nonce) = tx.nonce() { - tx_obj.insert("nonce", format!("0x{nonce:x}")); + tx_obj.insert("nonce", append_hex(pad_zero(format!("{nonce:x}")))); } if let Some(c) = tx.chain_id() { - tx_obj.insert("chainId", format!("0x{c:x}")); + tx_obj.insert("chainId", append_hex(pad_zero(format!("{c:x}")))); } // TODO: put those error cases to WCError instead of wrapping in eyre let tx_bytes: Bytes = self diff --git a/wallet-connect/src/v2/protocol.rs b/wallet-connect/src/v2/protocol.rs index f0353263..b570bb07 100644 --- a/wallet-connect/src/v2/protocol.rs +++ b/wallet-connect/src/v2/protocol.rs @@ -1,12 +1,12 @@ use std::{fmt::Display, str::FromStr}; use ethers::types::Address; -///! https://docs.walletconnect.com/2.0/specs/clients/sign/rpc-methods -///! FIXME: wc_sessionUpdate -///! FIXME: wc_sessionExtend -///! FIXME: wc_sessionEvent -///! FIXME: wc_sessionDelete -///! FIXME: wc_sessionPing OK +// https://docs.walletconnect.com/2.0/specs/clients/sign/rpc-methods +// FIXME: wc_sessionUpdate +// FIXME: wc_sessionExtend +// FIXME: wc_sessionEvent +// FIXME: wc_sessionDelete +// FIXME: wc_sessionPing OK use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; /// https://docs.walletconnect.com/2.0/specs/clients/sign/rpc-methods#wc_sessionpropose