From 4740c9382b6f6452b5587cc2696f6dee62c0809d Mon Sep 17 00:00:00 2001 From: Severin Siffert Date: Tue, 26 Mar 2024 10:26:03 +0100 Subject: [PATCH] import evm_rpc code --- Cargo.lock | 1135 +++++++++++++++++++++-- dfx.json | 31 +- solidity/contract.json | 340 +++++++ solidity/contract.sol | 194 ++++ src/backend/Cargo.toml | 14 +- src/backend/build.rs | 14 + src/backend/src/declarations/evm_rpc.rs | 427 +++++++++ src/backend/src/declarations/mod.rs | 5 + src/backend/src/eth_rpc.rs | 449 +++++++++ src/backend/src/lib.rs | 37 +- 10 files changed, 2521 insertions(+), 125 deletions(-) create mode 100644 solidity/contract.json create mode 100644 solidity/contract.sol create mode 100644 src/backend/build.rs create mode 100644 src/backend/src/declarations/evm_rpc.rs create mode 100644 src/backend/src/declarations/mod.rs create mode 100644 src/backend/src/eth_rpc.rs diff --git a/Cargo.lock b/Cargo.lock index f5e3d35..107aa25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,12 +17,24 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + [[package]] name = "arrayvec" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "ascii-canvas" version = "3.0.0" @@ -32,6 +44,17 @@ dependencies = [ "term", ] +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -42,15 +65,34 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" name = "backend" version = "0.0.1" dependencies = [ - "candid 0.10.0", + "candid", + "ethers-core", + "futures", + "getrandom", + "hex", "ic-cdk", - "ic-cdk-macros 0.6.10", + "ic-cdk-bindgen", + "ic-cdk-macros 0.9.0", "ic-stable-structures", + "k256", "serde", "serde_bytes", "serde_json", + "url", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "beef" version = "0.5.2" @@ -107,6 +149,18 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -116,6 +170,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "byteorder" version = "1.5.0" @@ -123,51 +183,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "candid" -version = "0.8.4" +name = "bytes" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244005a1917bb7614cd775ca8a5d59efeb5ac74397bb14ba29a19347ebd78591" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" dependencies = [ - "anyhow", - "binread", - "byteorder", - "candid_derive 0.5.0", - "codespan-reporting", - "crc32fast", - "data-encoding", - "hex", - "lalrpop", - "lalrpop-util", - "leb128", - "logos", - "num-bigint", - "num-traits", - "num_enum", - "paste", - "pretty 0.10.0", "serde", - "serde_bytes", - "sha2", - "thiserror", ] [[package]] name = "candid" -version = "0.10.0" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2525ab7a58543c132da8c780abe3aa1ba394ddcc1888a4ad2ba4f5100906ebe" +checksum = "965e86b1bd1c0c26df70cf0c92ae16c56204ab402eb915c26a541cf949d841cf" dependencies = [ "anyhow", "binread", "byteorder", - "candid_derive 0.6.5", + "candid_derive", "hex", "ic_principal", "leb128", "num-bigint", "num-traits", "paste", - "pretty 0.12.3", + "pretty", "serde", "serde_bytes", "stacker", @@ -176,26 +216,33 @@ dependencies = [ [[package]] name = "candid_derive" -version = "0.5.0" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f1f4db7c7d04b87b70b3a35c5dc5c2c9dd73cef8bdf6760e2f18a0d45350dd" +checksum = "3de398570c386726e7a59d9887b68763c481477f9a043fb998a2e09d428df1a9" dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] -name = "candid_derive" -version = "0.6.5" +name = "candid_parser" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970c220da8aa2fa6f7ef5dbbf3ea5b620a59eb3ac107cfb95ae8c6eebdfb7a08" +checksum = "48a3da76f989cd350b7342c64c6c6008341bb6186f6832ef04e56dc50ba0fd76" dependencies = [ - "lazy_static", - "proc-macro2", - "quote", - "syn 2.0.39", + "anyhow", + "candid", + "codespan-reporting", + "convert_case", + "hex", + "lalrpop", + "lalrpop-util", + "logos", + "num-bigint", + "pretty", + "thiserror", ] [[package]] @@ -213,6 +260,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +dependencies = [ + "num-traits", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -223,6 +279,34 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "const-hex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba00838774b4ab0233e355d26710fbfc8327a05c017f6dc4873f876d1f79f78" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cpufeatures" version = "0.2.11" @@ -247,6 +331,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -264,10 +360,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] -name = "diff" -version = "0.1.13" +name = "der" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "digest" @@ -276,7 +387,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -300,12 +413,45 @@ dependencies = [ "winapi", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "ena" version = "0.14.2" @@ -321,6 +467,119 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers-core" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +dependencies = [ + "arrayvec 0.7.4", + "bytes", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array", + "k256", + "num_enum", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "fastrand" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -333,6 +592,110 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -341,6 +704,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -354,6 +718,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -361,10 +736,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] -name = "hermit-abi" -version = "0.3.9" +name = "heck" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hex" @@ -372,26 +747,44 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "ic-cdk" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4ec8231f413b8a4d74b99d7df26d6e917d6528a6245abde27f251210dcf9b72" dependencies = [ - "candid 0.10.0", + "candid", "ic-cdk-macros 0.8.2", "ic0", "serde", "serde_bytes", ] +[[package]] +name = "ic-cdk-bindgen" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dbbafccaeebdaa72fb5323db936d35202d79c245e62cf5a0911eaa0ea60bcd" +dependencies = [ + "candid_parser", +] + [[package]] name = "ic-cdk-macros" -version = "0.6.10" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebf50458685a0fc6b0e414cdba487610aeb199ac94db52d9fd76270565debee7" +checksum = "ba23aedf7b8f89201dd778ad1bc8a04c35e3fda6fa6402f51da2cd9bb21045e6" dependencies = [ - "candid 0.8.4", + "candid", "proc-macro2", "quote", "serde", @@ -401,11 +794,11 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba23aedf7b8f89201dd778ad1bc8a04c35e3fda6fa6402f51da2cd9bb21045e6" +checksum = "2fde5ca6ef1e69825c68916ff1bf7256b8f7ed69ac5ea3f1756f6e57f1503e27" dependencies = [ - "candid 0.10.0", + "candid", "proc-macro2", "quote", "serde", @@ -431,6 +824,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899a4e8ddada85b91a2fe32b4dc6c0d475ef7bfef3f51cf2aecb26ee4ac4724f" dependencies = [ + "arbitrary", "crc32fast", "data-encoding", "hex", @@ -441,31 +835,68 @@ dependencies = [ ] [[package]] -name = "indexmap" -version = "2.2.5" +name = "idna" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "equivalent", - "hashbrown", + "unicode-bidi", + "unicode-normalization", ] [[package]] -name = "is-terminal" -version = "0.4.12" +name = "impl-codec" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "hermit-abi", - "libc", - "windows-sys", + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -476,35 +907,58 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + [[package]] name = "lalrpop" -version = "0.19.12" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" dependencies = [ "ascii-canvas", "bit-set", - "diff", "ena", - "is-terminal", "itertools", "lalrpop-util", "petgraph", + "pico-args", "regex", - "regex-syntax 0.6.29", + "regex-syntax 0.8.2", "string_cache", "term", "tiny-keccak", "unicode-xid", + "walkdir", ] [[package]] name = "lalrpop-util" -version = "0.19.12" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex", + "regex-automata", ] [[package]] @@ -525,6 +979,12 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.0.1" @@ -536,6 +996,12 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "lock_api" version = "0.4.11" @@ -554,25 +1020,34 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "logos" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" +checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" dependencies = [ "logos-derive", ] [[package]] -name = "logos-derive" -version = "0.12.1" +name = "logos-codegen" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" +checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" dependencies = [ "beef", "fnv", "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 1.0.109", + "syn 2.0.39", +] + +[[package]] +name = "logos-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +dependencies = [ + "logos-codegen", ] [[package]] @@ -616,27 +1091,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] name = "num_enum" -version = "0.5.11" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -645,6 +1121,57 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -674,6 +1201,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "petgraph" version = "0.6.4" @@ -694,32 +1227,70 @@ dependencies = [ ] [[package]] -name = "precomputed-hash" -version = "0.1.1" +name = "pico-args" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] -name = "pretty" -version = "0.10.0" +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9940b913ee56ddd94aec2d3cd179dd47068236f42a1a6415ccf9d880ce2a61" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "arrayvec", - "typed-arena", + "der", + "spki", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "pretty" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b55c4d17d994b637e2f4daf6e5dc5d660d209d5642377d675d7a1c3ab69fa579" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "typed-arena", "unicode-width", ] +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -727,18 +1298,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", ] [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.4.2", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "unarray", +] + [[package]] name = "psm" version = "0.1.21" @@ -757,6 +1354,51 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -812,6 +1454,57 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -824,12 +1517,59 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "serde" version = "1.0.193" @@ -892,17 +1632,56 @@ dependencies = [ "digest", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "spki" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] [[package]] name = "stacker" @@ -917,6 +1696,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "string_cache" version = "0.8.7" @@ -930,6 +1715,34 @@ dependencies = [ "precomputed-hash", ] +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.39", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -952,6 +1765,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + [[package]] name = "term" version = "0.7.0" @@ -1001,11 +1833,26 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" @@ -1018,6 +1865,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typed-arena" version = "2.0.2" @@ -1030,12 +1888,51 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "unicode-width" version = "0.1.11" @@ -1048,12 +1945,33 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1222,3 +2140,18 @@ checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/dfx.json b/dfx.json index 0ea2dc8..baa6166 100644 --- a/dfx.json +++ b/dfx.json @@ -8,15 +8,36 @@ "backend": { "candid": "src/backend/backend.did", "package": "backend", - "type": "rust" + "type": "rust", + "dependencies": [ + "evm_rpc" + ] }, "frontend": { - "dependencies": ["backend", "ic_siwe_provider"], - "source": ["dist"], + "dependencies": [ + "backend", + "ic_siwe_provider" + ], + "source": [ + "dist" + ], "type": "assets", - "build": ["npm run build"] + "build": [ + "npm run build" + ] + }, + "evm_rpc": { + "type": "custom", + "candid": "https://github.com/internet-computer-protocol/evm-rpc-canister/releases/latest/download/evm_rpc.did", + "wasm": "https://github.com/internet-computer-protocol/evm-rpc-canister/releases/latest/download/evm_rpc_dev.wasm.gz", + "remote": { + "candid": "canisters/evm_rpc.did", + "id": { + "ic": "7hfb6-caaaa-aaaar-qadga-cai" + } + } } }, "output_env_file": ".env", "version": 1 -} +} \ No newline at end of file diff --git a/solidity/contract.json b/solidity/contract.json new file mode 100644 index 0000000..7e7c563 --- /dev/null +++ b/solidity/contract.json @@ -0,0 +1,340 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowances", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balances", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_description", + "type": "string" + } + ], + "name": "createProposal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_proposalId", + "type": "uint256" + } + ], + "name": "executeProposal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "executor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAllBalances", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "proposals", + "outputs": [ + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "enum AdminERC20Contract.ProposalState", + "name": "state", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/solidity/contract.sol b/solidity/contract.sol new file mode 100644 index 0000000..3f9350e --- /dev/null +++ b/solidity/contract.sol @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IERC20 { + function totalSupply() external view returns (uint256); + + function balanceOf(address account) external view returns (uint256); + + function transfer( + address recipient, + uint256 amount + ) external returns (bool); + + function allowance( + address owner, + address spender + ) external view returns (uint256); + + function approve(address spender, uint256 amount) external returns (bool); + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool); + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval( + address indexed owner, + address indexed spender, + uint256 value + ); +} + +contract AdminERC20Contract is IERC20 { + address public admin; + address public executor; + mapping(address => uint256) public balances; + mapping(address => mapping(address => uint256)) public allowances; + + uint256 private _totalSupply; + address[] private addresses; + + constructor() { + // Save the deployer's address as the admin + admin = msg.sender; + + // Assign an initial total supply to the deployer + _totalSupply = 1000000 * 10 ** 18; // 1 million tokens + balances[msg.sender] = _totalSupply; + addresses.push(msg.sender); + } + + function getAddresses() external view returns (address[] memory) { + return addresses; + } + + modifier onlyAdmin() { + require(msg.sender == admin, "Only admin can call this function"); + _; + } + + modifier onlyExecutor() { + require(msg.sender == executor, "Only executor can call this function"); + _; + } + + function addressExists(address a) internal view returns (bool) { + for (uint256 i = 0; i < addresses.length; i++) { + if (addresses[i] == a) { + return true; + } + } + return false; + } + + function totalSupply() external view override returns (uint256) { + return _totalSupply; + } + + function balanceOf( + address account + ) external view override returns (uint256) { + return balances[account]; + } + + function transfer( + address recipient, + uint256 amount + ) external override returns (bool) { + require(balances[msg.sender] >= amount, "Insufficient balance"); + balances[msg.sender] -= amount; + balances[recipient] += amount; + if (!addressExists(recipient)) { + addresses.push(recipient); // Add recipient's address to the array if it's not already present + } + emit Transfer(msg.sender, recipient, amount); + return true; + } + + function allowance( + address owner, + address spender + ) external view override returns (uint256) { + return allowances[owner][spender]; + } + + function approve( + address spender, + uint256 amount + ) external override returns (bool) { + allowances[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external override returns (bool) { + require(balances[sender] >= amount, "Insufficient balance"); + require( + allowances[sender][msg.sender] >= amount, + "Insufficient allowance" + ); + balances[sender] -= amount; + balances[recipient] += amount; + allowances[sender][msg.sender] -= amount; + if (!addressExists(recipient)) { + addresses.push(recipient); // Add recipient's address to the array if it's not already present + } + emit Transfer(sender, recipient, amount); + return true; + } + + function getAllBalances() + external + view + returns (address[] memory, uint256[] memory) + { + uint256 length = 0; + for (uint256 i = 0; i < addresses.length; i++) { + if (balances[addresses[i]] > 0) { + length++; + } + } + + address[] memory addrs = new address[](length); + uint256[] memory bals = new uint256[](length); + + uint256 index = 0; + for (uint256 i = 0; i < addresses.length; i++) { + if (balances[addresses[i]] > 0) { + addrs[index] = addresses[i]; + bals[index] = balances[addresses[i]]; + index++; + } + } + + return (addrs, bals); + } + + enum ProposalState { + Open, + Executed + } + + struct Proposal { + string description; + ProposalState state; + } + + // Example storage for proposals + mapping(uint256 => Proposal) public proposals; + + // Counter for generating unique proposal IDs + uint256 private proposalCounter; + + // Function to create a new proposal + function createProposal(string memory _description) external { + uint256 newProposalId = proposalCounter++; + proposals[newProposalId] = Proposal(_description, ProposalState.Open); + } + + // Function to execute a proposal + function executeProposal(uint256 _proposalId) external onlyExecutor { + Proposal storage proposal = proposals[_proposalId]; + require(proposal.state == ProposalState.Open, "Proposal is not open"); + + // Perform actions to execute the proposal (example: update state) + proposal.state = ProposalState.Executed; + } +} diff --git a/src/backend/Cargo.toml b/src/backend/Cargo.toml index ae21e8b..0dfacbc 100644 --- a/src/backend/Cargo.toml +++ b/src/backend/Cargo.toml @@ -9,9 +9,17 @@ crate-type = ["cdylib"] [dependencies] candid = "0.10.0" ic-cdk = "0.12.0" -serde = "1.0.193" -serde_json = "1.0.108" +ic-cdk-macros = "0.9.0" ic-stable-structures = "0.6.0" serde_bytes = "0.11" +hex = "0.4.3" +url = "2.3" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +ethers-core = "2.0" +futures = "0.3" +getrandom = { version = "0.2", features = ["custom"] } +k256 = "0.13" -ic-cdk-macros = "0.6.6" +[build-dependencies] +ic-cdk-bindgen = "0.1.3" diff --git a/src/backend/build.rs b/src/backend/build.rs new file mode 100644 index 0000000..f7212f4 --- /dev/null +++ b/src/backend/build.rs @@ -0,0 +1,14 @@ +use ic_cdk_bindgen::{Builder, Config}; +use std::path::PathBuf; + +fn main() { + let manifest_dir = + PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("Cannot find manifest dir")); + let mut evm_rpc = Config::new("evm_rpc"); + evm_rpc + .binding + .set_type_attributes("#[derive(Debug, CandidType, Deserialize)]".into()); + let mut builder = Builder::new(); + builder.add(evm_rpc); + builder.build(Some(manifest_dir.join("src/declarations"))); +} diff --git a/src/backend/src/declarations/evm_rpc.rs b/src/backend/src/declarations/evm_rpc.rs new file mode 100644 index 0000000..9cf60c0 --- /dev/null +++ b/src/backend/src/declarations/evm_rpc.rs @@ -0,0 +1,427 @@ +// This is an experimental feature to generate Rust binding from Candid. +// You may want to manually adjust some of the types. +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; +use ic_cdk::api::call::CallResult as Result; + +#[derive(Debug, CandidType, Deserialize)] +pub struct InitArgs { pub nodesInSubnet: u32 } + +#[derive(Debug, CandidType, Deserialize)] +pub enum Auth { RegisterProvider, FreeRpc, PriorityRpc, Manage } + +#[derive(Debug, CandidType, Deserialize)] +pub enum EthSepoliaService { Alchemy, BlockPi, PublicNode, Ankr } + +#[derive(Debug, CandidType, Deserialize)] +pub struct HttpHeader { pub value: String, pub name: String } + +#[derive(Debug, CandidType, Deserialize)] +pub struct RpcApi { pub url: String, pub headers: Option> } + +#[derive(Debug, CandidType, Deserialize)] +pub enum EthMainnetService { Alchemy, BlockPi, Cloudflare, PublicNode, Ankr } + +#[derive(Debug, CandidType, Deserialize)] +pub enum RpcServices { + EthSepolia(Option>), + Custom{ chainId: u64, services: Vec }, + EthMainnet(Option>), +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct RpcConfig { pub responseSizeEstimate: Option } + +#[derive(Debug, CandidType, Deserialize)] +pub enum BlockTag { + Earliest, + Safe, + Finalized, + Latest, + Number(candid::Nat), + Pending, +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct FeeHistoryArgs { + pub blockCount: candid::Nat, + pub newestBlock: BlockTag, + pub rewardPercentiles: Option, +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct FeeHistory { + pub reward: Vec>, + pub gasUsedRatio: Vec, + pub oldestBlock: candid::Nat, + pub baseFeePerGas: Vec, +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct JsonRpcError { pub code: i64, pub message: String } + +#[derive(Debug, CandidType, Deserialize)] +pub enum ProviderError { + TooFewCycles{ expected: candid::Nat, received: candid::Nat }, + MissingRequiredProvider, + ProviderNotFound, + NoPermission, +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum ValidationError { + CredentialPathNotAllowed, + HostNotAllowed(String), + CredentialHeaderNotAllowed, + UrlParseError(String), + Custom(String), + InvalidHex(String), +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum RejectionCode { + NoError, + CanisterError, + SysTransient, + DestinationInvalid, + Unknown, + SysFatal, + CanisterReject, +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum HttpOutcallError { + IcError{ code: RejectionCode, message: String }, + InvalidHttpJsonRpcResponse{ + status: u16, + body: String, + parsingError: Option, + }, +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum RpcError { + JsonRpcError(JsonRpcError), + ProviderError(ProviderError), + ValidationError(ValidationError), + HttpOutcallError(HttpOutcallError), +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum FeeHistoryResult { Ok(Option), Err(RpcError) } + +#[derive(Debug, CandidType, Deserialize)] +pub enum RpcService { + EthSepolia(EthSepoliaService), + Custom(RpcApi), + EthMainnet(EthMainnetService), + Chain(u64), + Provider(u64), +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum MultiFeeHistoryResult { + Consistent(FeeHistoryResult), + Inconsistent(Vec<(RpcService,FeeHistoryResult,)>), +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct Block { + pub miner: String, + pub totalDifficulty: candid::Nat, + pub receiptsRoot: String, + pub stateRoot: String, + pub hash: String, + pub difficulty: candid::Nat, + pub size: candid::Nat, + pub uncles: Vec, + pub baseFeePerGas: candid::Nat, + pub extraData: String, + pub transactionsRoot: Option, + pub sha3Uncles: String, + pub nonce: candid::Nat, + pub number: candid::Nat, + pub timestamp: candid::Nat, + pub transactions: Vec, + pub gasLimit: candid::Nat, + pub logsBloom: String, + pub parentHash: String, + pub gasUsed: candid::Nat, + pub mixHash: String, +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum GetBlockByNumberResult { Ok(Block), Err(RpcError) } + +#[derive(Debug, CandidType, Deserialize)] +pub enum MultiGetBlockByNumberResult { + Consistent(GetBlockByNumberResult), + Inconsistent(Vec<(RpcService,GetBlockByNumberResult,)>), +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct GetLogsArgs { + pub fromBlock: Option, + pub toBlock: Option, + pub addresses: Vec, + pub topics: Option>>, +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct LogEntry { + pub transactionHash: Option, + pub blockNumber: Option, + pub data: String, + pub blockHash: Option, + pub transactionIndex: Option, + pub topics: Vec, + pub address: String, + pub logIndex: Option, + pub removed: bool, +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum GetLogsResult { Ok(Vec), Err(RpcError) } + +#[derive(Debug, CandidType, Deserialize)] +pub enum MultiGetLogsResult { + Consistent(GetLogsResult), + Inconsistent(Vec<(RpcService,GetLogsResult,)>), +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct GetTransactionCountArgs { pub address: String, pub block: BlockTag } + +#[derive(Debug, CandidType, Deserialize)] +pub enum GetTransactionCountResult { Ok(candid::Nat), Err(RpcError) } + +#[derive(Debug, CandidType, Deserialize)] +pub enum MultiGetTransactionCountResult { + Consistent(GetTransactionCountResult), + Inconsistent(Vec<(RpcService,GetTransactionCountResult,)>), +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct TransactionReceipt { + pub to: String, + pub status: candid::Nat, + pub transactionHash: String, + pub blockNumber: candid::Nat, + pub from: String, + pub logs: Vec, + pub blockHash: String, + pub r#type: String, + pub transactionIndex: candid::Nat, + pub effectiveGasPrice: candid::Nat, + pub logsBloom: String, + pub contractAddress: Option, + pub gasUsed: candid::Nat, +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum GetTransactionReceiptResult { + Ok(Option), + Err(RpcError), +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum MultiGetTransactionReceiptResult { + Consistent(GetTransactionReceiptResult), + Inconsistent(Vec<(RpcService,GetTransactionReceiptResult,)>), +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum SendRawTransactionStatus { + Ok, + NonceTooLow, + NonceTooHigh, + InsufficientFunds, +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum SendRawTransactionResult { + Ok(SendRawTransactionStatus), + Err(RpcError), +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum MultiSendRawTransactionResult { + Consistent(SendRawTransactionResult), + Inconsistent(Vec<(RpcService,SendRawTransactionResult,)>), +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct Metrics { + pub cyclesWithdrawn: candid::Nat, + pub responses: Vec<((String,String,String,),u64,)>, + pub errNoPermission: u64, + pub inconsistentResponses: Vec<((String,String,),u64,)>, + pub cyclesCharged: Vec<((String,String,),candid::Nat,)>, + pub requests: Vec<((String,String,),u64,)>, + pub errHttpOutcall: Vec<((String,String,),u64,)>, + pub errHostNotAllowed: Vec<(String,u64,)>, +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct ProviderView { + pub cyclesPerCall: u64, + pub owner: Principal, + pub hostname: String, + pub primary: bool, + pub chainId: u64, + pub cyclesPerMessageByte: u64, + pub providerId: u64, +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct ManageProviderArgs { + pub service: Option, + pub primary: Option, + pub providerId: u64, +} + +#[derive(Debug, CandidType, Deserialize)] +pub struct RegisterProviderArgs { + pub cyclesPerCall: u64, + pub credentialPath: String, + pub hostname: String, + pub credentialHeaders: Option>, + pub chainId: u64, + pub cyclesPerMessageByte: u64, +} + +#[derive(Debug, CandidType, Deserialize)] +pub enum RequestResult { Ok(String), Err(RpcError) } + +#[derive(Debug, CandidType, Deserialize)] +pub enum RequestCostResult { Ok(candid::Nat), Err(RpcError) } + +#[derive(Debug, CandidType, Deserialize)] +pub struct UpdateProviderArgs { + pub cyclesPerCall: Option, + pub credentialPath: Option, + pub hostname: Option, + pub credentialHeaders: Option>, + pub primary: Option, + pub cyclesPerMessageByte: Option, + pub providerId: u64, +} + +pub struct EvmRpc(pub Principal); +impl EvmRpc { + pub async fn authorize(&self, arg0: Principal, arg1: Auth) -> Result< + (bool,) + > { ic_cdk::call(self.0, "authorize", (arg0,arg1,)).await } + pub async fn deauthorize(&self, arg0: Principal, arg1: Auth) -> Result< + (bool,) + > { ic_cdk::call(self.0, "deauthorize", (arg0,arg1,)).await } + pub async fn eth_fee_history( + &self, + arg0: RpcServices, + arg1: Option, + arg2: FeeHistoryArgs, + ) -> Result<(MultiFeeHistoryResult,)> { + ic_cdk::call(self.0, "eth_feeHistory", (arg0,arg1,arg2,)).await + } + pub async fn eth_get_block_by_number( + &self, + arg0: RpcServices, + arg1: Option, + arg2: BlockTag, + ) -> Result<(MultiGetBlockByNumberResult,)> { + ic_cdk::call(self.0, "eth_getBlockByNumber", (arg0,arg1,arg2,)).await + } + pub async fn eth_get_logs( + &self, + arg0: RpcServices, + arg1: Option, + arg2: GetLogsArgs, + ) -> Result<(MultiGetLogsResult,)> { + ic_cdk::call(self.0, "eth_getLogs", (arg0,arg1,arg2,)).await + } + pub async fn eth_get_transaction_count( + &self, + arg0: RpcServices, + arg1: Option, + arg2: GetTransactionCountArgs, + ) -> Result<(MultiGetTransactionCountResult,)> { + ic_cdk::call(self.0, "eth_getTransactionCount", (arg0,arg1,arg2,)).await + } + pub async fn eth_get_transaction_receipt( + &self, + arg0: RpcServices, + arg1: Option, + arg2: String, + ) -> Result<(MultiGetTransactionReceiptResult,)> { + ic_cdk::call(self.0, "eth_getTransactionReceipt", (arg0,arg1,arg2,)).await + } + pub async fn eth_send_raw_transaction( + &self, + arg0: RpcServices, + arg1: Option, + arg2: String, + ) -> Result<(MultiSendRawTransactionResult,)> { + ic_cdk::call(self.0, "eth_sendRawTransaction", (arg0,arg1,arg2,)).await + } + pub async fn get_accumulated_cycle_count(&self, arg0: u64) -> Result< + (candid::Nat,) + > { ic_cdk::call(self.0, "getAccumulatedCycleCount", (arg0,)).await } + pub async fn get_authorized(&self, arg0: Auth) -> Result<(Vec,)> { + ic_cdk::call(self.0, "getAuthorized", (arg0,)).await + } + pub async fn get_metrics(&self) -> Result<(Metrics,)> { + ic_cdk::call(self.0, "getMetrics", ()).await + } + pub async fn get_nodes_in_subnet(&self) -> Result<(u32,)> { + ic_cdk::call(self.0, "getNodesInSubnet", ()).await + } + pub async fn get_open_rpc_access(&self) -> Result<(bool,)> { + ic_cdk::call(self.0, "getOpenRpcAccess", ()).await + } + pub async fn get_providers(&self) -> Result<(Vec,)> { + ic_cdk::call(self.0, "getProviders", ()).await + } + pub async fn get_service_provider_map(&self) -> Result< + (Vec<(RpcService,u64,)>,) + > { ic_cdk::call(self.0, "getServiceProviderMap", ()).await } + pub async fn manage_provider(&self, arg0: ManageProviderArgs) -> Result<()> { + ic_cdk::call(self.0, "manageProvider", (arg0,)).await + } + pub async fn register_provider(&self, arg0: RegisterProviderArgs) -> Result< + (u64,) + > { ic_cdk::call(self.0, "registerProvider", (arg0,)).await } + pub async fn request( + &self, + arg0: RpcService, + arg1: String, + arg2: u64, + ) -> Result<(RequestResult,)> { + ic_cdk::call(self.0, "request", (arg0,arg1,arg2,)).await + } + pub async fn request_cost( + &self, + arg0: RpcService, + arg1: String, + arg2: u64, + ) -> Result<(RequestCostResult,)> { + ic_cdk::call(self.0, "requestCost", (arg0,arg1,arg2,)).await + } + pub async fn set_open_rpc_access(&self, arg0: bool) -> Result<()> { + ic_cdk::call(self.0, "setOpenRpcAccess", (arg0,)).await + } + pub async fn unregister_provider(&self, arg0: u64) -> Result<(bool,)> { + ic_cdk::call(self.0, "unregisterProvider", (arg0,)).await + } + pub async fn update_provider(&self, arg0: UpdateProviderArgs) -> Result<()> { + ic_cdk::call(self.0, "updateProvider", (arg0,)).await + } + pub async fn withdraw_accumulated_cycles( + &self, + arg0: u64, + arg1: Principal, + ) -> Result<()> { + ic_cdk::call(self.0, "withdrawAccumulatedCycles", (arg0,arg1,)).await + } +} +pub const CANISTER_ID : Principal = Principal::from_slice(&[176, 158, 149, 62, 135, 109, 202, 192]); // yvu24-pnqt2-kt5b3-nzlaa +pub const evm_rpc : EvmRpc = EvmRpc(CANISTER_ID); \ No newline at end of file diff --git a/src/backend/src/declarations/mod.rs b/src/backend/src/declarations/mod.rs new file mode 100644 index 0000000..5ad6d79 --- /dev/null +++ b/src/backend/src/declarations/mod.rs @@ -0,0 +1,5 @@ +#![allow(unused_imports)] +#![allow(non_upper_case_globals)] +#![allow(non_snake_case)] +#[rustfmt::skip] +pub mod evm_rpc; diff --git a/src/backend/src/eth_rpc.rs b/src/backend/src/eth_rpc.rs new file mode 100644 index 0000000..8d1d9a4 --- /dev/null +++ b/src/backend/src/eth_rpc.rs @@ -0,0 +1,449 @@ +use crate::declarations::evm_rpc::*; +use candid::{Nat, Principal}; +use ethers_core::abi::ethereum_types::{Address, H160, U256, U64}; +use ethers_core::abi::{Contract, FunctionExt, Token, Uint}; +use ethers_core::types::Bytes; +use ethers_core::utils::keccak256; +use hex::FromHexError; +use ic_cdk::api::{ + call::{call_with_payment, CallResult}, + management_canister::ecdsa::{ + ecdsa_public_key, sign_with_ecdsa, EcdsaKeyId, EcdsaPublicKeyArgument, + SignWithEcdsaArgument, + }, +}; +use k256::elliptic_curve::sec1::ToEncodedPoint; +use k256::PublicKey; +use serde::{Deserialize, Serialize}; +use std::cell::RefCell; +use std::rc::Rc; +use std::str::FromStr; + +// const CHAIN_ID: u128 = 1337; +const CHAIN_ID: u128 = 11155111; +const GAS: u128 = 80_000; +const MAX_FEE_PER_GAS: u128 = 156_083_066_522_u128; +const MAX_PRIORITY_FEE_PER_GAS: u128 = 3_000_000_000; + +#[derive(Clone, Debug, Serialize, Deserialize)] +struct JsonRpcRequest { + id: u64, + jsonrpc: String, + method: String, + params: (EthCallParams, String), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +struct EthCallParams { + to: String, + data: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +struct JsonRpcResult { + result: Option, + error: Option, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +struct JsonRpcError { + code: isize, + message: String, +} + +#[macro_export] +macro_rules! include_abi { + ($file:expr $(,)?) => {{ + match serde_json::from_str::(include_str!($file)) { + Ok(contract) => contract, + Err(err) => panic!("Error loading ABI contract {:?}: {}", $file, err), + } + }}; +} + +pub fn ecdsa_key_id() -> EcdsaKeyId { + EcdsaKeyId { + curve: ic_cdk::api::management_canister::ecdsa::EcdsaCurve::Secp256k1, + name: String::from("test_key_1"), + } +} + +fn next_id() -> u64 { + thread_local! { + static NEXT_ID: RefCell = RefCell::default(); + } + NEXT_ID.with(|next_id| { + let mut next_id = next_id.borrow_mut(); + let id = *next_id; + *next_id = next_id.wrapping_add(1); + id + 10_512425 + }) +} + +// Load relevant ABIs (Ethereum equivalent of Candid interfaces) +thread_local! { + static ETH_CONTRACT: Rc = Rc::new(include_abi!("../../../solidity/contract.json")); +} + +pub fn parse_address(address_str: &str) -> Result { + // Remove any leading or trailing whitespace + + // Check if the address string starts with "0x" prefix + if address_str.starts_with("0x") && address_str.len() == 42 { + // Try to parse the hexadecimal string into an Address + if let Ok(address_bytes) = hex::decode(&address_str[2..]) { + if address_bytes.len() == 20 { + let mut address = [0u8; 20]; + address.copy_from_slice(&address_bytes); + return Ok(Address::from(address)); + } + } + } + + // If the address format is invalid, return an error + Err("Invalid Ethereum address format") +} + +/// Call an Ethereum smart contract. +pub async fn eth_call( + contract_address: String, + abi: &Contract, + function_name: &str, + args: &[Token], + block_number: &str, +) -> Vec { + let f = match abi.functions_by_name(function_name).map(|v| &v[..]) { + Ok([f]) => f, + Ok(fs) => panic!( + "Found {} function overloads. Please pass one of the following: {}", + fs.len(), + fs.iter() + .map(|f| format!("{:?}", f.abi_signature())) + .collect::>() + .join(", ") + ), + Err(_) => abi + .functions() + .find(|f| function_name == f.abi_signature()) + .expect("Function not found"), + }; + let data = f + .encode_input(args) + .expect("Error while encoding input args"); + let json_rpc_payload = serde_json::to_string(&JsonRpcRequest { + id: next_id(), + jsonrpc: "2.0".to_string(), + method: "eth_call".to_string(), + params: ( + EthCallParams { + to: contract_address, + data: to_hex(&data), + }, + block_number.to_string(), + ), + }) + .expect("Error while encoding JSON-RPC request"); + + let res: CallResult<(RequestResult,)> = call_with_payment( + crate::declarations::evm_rpc::evm_rpc.0, + "request", + ( + RpcService::EthSepolia(EthSepoliaService::BlockPi), + json_rpc_payload, + 2048_u64, + ), + 2_000_000_000, + ) + .await; + + match res { + Ok((RequestResult::Ok(ok),)) => { + let json: JsonRpcResult = + serde_json::from_str(&ok).expect("JSON was not well-formatted"); + let result = from_hex(&json.result.expect("Unexpected JSON response")).unwrap(); + f.decode_output(&result).expect("Error decoding output") + } + err => panic!("Response error: {err:?}"), + } +} + +/// Submit an ETH TX. +pub async fn eth_transaction( + contract_address: String, + abi: &Contract, + function_name: &str, + args: &[Token], +) -> String { + let f = match abi.functions_by_name(function_name).map(|v| &v[..]) { + Ok([f]) => f, + Ok(fs) => panic!( + "Found {} function overloads. Please pass one of the following: {}", + fs.len(), + fs.iter() + .map(|f| format!("{:?}", f.abi_signature())) + .collect::>() + .join(", ") + ), + Err(_) => abi + .functions() + .find(|f| function_name == f.abi_signature()) + .expect("Function not found"), + }; + let data = f + .encode_input(args) + .expect("Error while encoding input args"); + let signed_data = sign_transaction(SignRequest { + chain_id: CHAIN_ID.into(), + to: contract_address, + gas: GAS.into(), + max_fee_per_gas: MAX_FEE_PER_GAS.into(), + max_priority_fee_per_gas: MAX_PRIORITY_FEE_PER_GAS.into(), + value: 0_u8.into(), + nonce: next_id().into(), + data: Some(data.into()), + }) + .await; + + let (res,): (MultiSendRawTransactionResult,) = call_with_payment( + crate::declarations::evm_rpc::evm_rpc.0, + "eth_sendRawTransaction", + ( + RpcServices::EthSepolia(Some(vec![ + EthSepoliaService::PublicNode, + EthSepoliaService::BlockPi, + EthSepoliaService::Ankr, + ])), + None::, + signed_data.clone(), + ), + 2_000_000_000, + ) + .await + .unwrap(); + + match res { + MultiSendRawTransactionResult::Consistent(SendRawTransactionResult::Ok( + SendRawTransactionStatus::Ok, + )) => "OK".into(), + other => format!("call: {signed_data}, error: {:?}", other), + // Ok((RequestResult::Ok(ok),)) => { + // let json: JsonRpcResult = + // serde_json::from_str(&ok).expect("JSON was not well-formatted"); + // let result = from_hex(&json.result.expect("Unexpected JSON response")).unwrap(); + // f.decode_output(&result).expect("Error decoding output") + // } + // err => panic!("Response error: {err:?}"), + } +} + +fn to_hex(data: &[u8]) -> String { + format!("0x{}", hex::encode(data)) +} + +pub fn from_hex(data: &str) -> Result, FromHexError> { + hex::decode(&data[2..]) +} + +#[derive(Debug)] +pub struct SignRequest { + pub chain_id: Nat, + pub to: String, + pub gas: Nat, + pub max_fee_per_gas: Nat, + pub max_priority_fee_per_gas: Nat, + /// ETH to send + pub value: Nat, + pub nonce: Nat, + pub data: Option, +} + +/// Computes a signature for an [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) transaction. +pub async fn sign_transaction(req: SignRequest) -> String { + use ethers_core::types::transaction::eip1559::Eip1559TransactionRequest; + use ethers_core::types::Signature; + + const EIP1559_TX_ID: u8 = 2; + + let tx = Eip1559TransactionRequest { + chain_id: Some(nat_to_u64(&req.chain_id)), + from: None, + to: Some( + Address::from_str(&req.to) + .expect("failed to parse the destination address") + .into(), + ), + gas: Some(nat_to_u256(&req.gas)), + value: Some(nat_to_u256(&req.value)), + nonce: Some(nat_to_u256(&req.nonce)), + data: req.data, + access_list: Default::default(), + max_priority_fee_per_gas: Some(nat_to_u256(&req.max_priority_fee_per_gas)), + max_fee_per_gas: Some(nat_to_u256(&req.max_fee_per_gas)), + }; + + let mut unsigned_tx_bytes = tx.rlp().to_vec(); + unsigned_tx_bytes.insert(0, EIP1559_TX_ID); + + let txhash = keccak256(&unsigned_tx_bytes); + + let (pubkey, signature) = pubkey_and_signature(txhash.to_vec()).await; + + let signature = Signature { + v: y_parity(&txhash, &signature, &pubkey), + r: U256::from_big_endian(&signature[0..32]), + s: U256::from_big_endian(&signature[32..64]), + }; + + let mut signed_tx_bytes = tx.rlp_signed(&signature).to_vec(); + signed_tx_bytes.insert(0, EIP1559_TX_ID); + + format!("0x{}", hex::encode(&signed_tx_bytes)) +} + +/// Computes the parity bit allowing to recover the public key from the signature. +fn y_parity(prehash: &[u8], sig: &[u8], pubkey: &[u8]) -> u64 { + use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; + + let orig_key = VerifyingKey::from_sec1_bytes(pubkey).expect("failed to parse the pubkey"); + let signature = Signature::try_from(sig).unwrap(); + for parity in [0u8, 1] { + let recid = RecoveryId::try_from(parity).unwrap(); + let recovered_key = VerifyingKey::recover_from_prehash(prehash, &signature, recid) + .expect("failed to recover key"); + if recovered_key == orig_key { + return parity as u64; + } + } + + panic!( + "failed to recover the parity bit from a signature; sig: {}, pubkey: {}", + hex::encode(sig), + hex::encode(pubkey) + ) +} + +/// Returns the public key and a message signature for the specified principal. +async fn pubkey_and_signature(message_hash: Vec) -> (Vec, Vec) { + // Fetch the pubkey and the signature concurrently to reduce latency. + let (pubkey, response) = futures::join!( + ecdsa_public_key(EcdsaPublicKeyArgument { + canister_id: None, + derivation_path: vec![], + key_id: ecdsa_key_id() + }), + sign_with_ecdsa(SignWithEcdsaArgument { + message_hash, + derivation_path: vec![], + key_id: ecdsa_key_id(), + }) + ); + ( + pubkey.unwrap().0.public_key, + response.expect("failed to sign the message").0.signature, + ) +} +fn nat_to_u256(n: &Nat) -> U256 { + let be_bytes = n.0.to_bytes_be(); + U256::from_big_endian(&be_bytes) +} + +fn nat_to_u64(n: &Nat) -> U64 { + let be_bytes = n.0.to_bytes_be(); + U64::from_big_endian(&be_bytes) +} + +fn decode_hex(hex: &str) -> Bytes { + Bytes::from(hex::decode(hex.trim_start_matches("0x")).expect("failed to decode hex")) +} + +pub async fn rpc_request_with_cycles( + cycles: u64, + arg1: String, + max_response_bytes: u64, +) -> CallResult<(RequestResult,)> { + call_with_payment( + crate::declarations::evm_rpc::evm_rpc.0, + "request", + ( + RpcService::EthSepolia(EthSepoliaService::Alchemy), + arg1, + max_response_bytes, + ), + cycles, + ) + .await +} + +/// returns latest block number in `U256` and hex encoded form +pub async fn block_number() -> (U256, String) { + let RequestResult::Ok(response) = rpc_request_with_cycles( + 1_000_000_000, + "{\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\":[]}".into(), + 2000, + ) + .await + .expect("RPC failed") + .0 + else { + panic!("oops") + }; + let json: JsonRpcResult = serde_json::from_str(&response).expect("JSON was not well-formatted"); + if let Some(err) = json.error { + panic!("JSON-RPC error code {}: {}", err.code, err.message); + } + let hex_result = json.result.expect("Unexpected JSON response"); + let result = from_hex(&hex_result).unwrap(); + + (U256::from_big_endian(&result), hex_result) +} + +pub async fn balance_of(user: &str, block_number: &str) -> Uint { + let Token::Uint(balance) = eth_call( + super::TARGET_CONTRACT.into(), + Ð_CONTRACT.with(Rc::clone), + "balanceOf", + &[Token::Address(parse_address(user).unwrap())], + block_number, + ) + .await + .get(0) + .unwrap() + .clone() else { + panic!("oops") + }; + balance +} + +pub async fn transfer_to(to: &str, amount: u128) -> String { + eth_transaction( + super::TARGET_CONTRACT.into(), + Ð_CONTRACT.with(Rc::clone), + "transfer", + &[ + Token::Address(parse_address(to).unwrap()), + Token::Uint(amount.into()), + ], + ) + .await +} + +pub async fn get_self_eth_address() -> String { + let (pubkey,) = ecdsa_public_key(EcdsaPublicKeyArgument { + canister_id: None, + derivation_path: vec![], + key_id: ecdsa_key_id(), + }) + .await + .unwrap(); + + let key = PublicKey::from_sec1_bytes(&pubkey.public_key) + .expect("failed to parse the public key as SEC1"); + let point = key.to_encoded_point(false); + // we re-encode the key to the decompressed representation. + let point_bytes = point.as_bytes(); + assert_eq!(point_bytes[0], 0x04); + + let hash = keccak256(&point_bytes[1..]); + + ethers_core::utils::to_checksum(&Address::from_slice(&hash[12..32]), None) +} diff --git a/src/backend/src/lib.rs b/src/backend/src/lib.rs index 2bffe8e..00f99d1 100644 --- a/src/backend/src/lib.rs +++ b/src/backend/src/lib.rs @@ -1,3 +1,5 @@ +mod declarations; +mod eth_rpc; mod service; mod user_profile; @@ -8,10 +10,11 @@ use std::cell::RefCell; use user_profile::UserProfile; use ic_cdk::api::{caller, time}; -use ic_cdk_macros::*; -use ic_cdk::println; +use ic_cdk::{println, query, update}; use std::collections::HashMap; +pub const TARGET_CONTRACT: &str = "0xcd76a64b5914aca2b59615a66af9073bb25b5008"; + type Memory = VirtualMemory; type GetAddressResponse = Result; @@ -87,12 +90,12 @@ async fn submit_proposal(title: String, description: String, proposal_type: Stri println!("Address: {}", address); // Store the address in submitter_eth_address if successful submitter_eth_address = address; - }, + } Err(e) => { println!("Error retrieving address: {}", e); // Here you may choose to handle the error, like defaulting to a fallback address, or stopping execution // For this example, we'll just log the error. You might want to return or handle differently in real code. - }, + } } PROPOSALS.with(|proposals| { @@ -115,24 +118,21 @@ async fn submit_proposal(title: String, description: String, proposal_type: Stri }) } - #[query] fn get_proposals() -> Vec { - PROPOSALS.with(|proposals_ref| { - proposals_ref.borrow().clone() - }) + PROPOSALS.with(|proposals_ref| proposals_ref.borrow().clone()) } - #[update] fn vote_on_proposal(proposal_id: u64, vote: bool) -> Result<(), String> { let voter_principal = caller().to_text(); - println!("Received vote: {}, from principal: {}, for proposal: {}", vote, voter_principal, proposal_id); + println!( + "Received vote: {}, from principal: {}, for proposal: {}", + vote, voter_principal, proposal_id + ); // First, check if the proposal exists. - let exists = PROPOSALS.with(|proposals| { - proposals.borrow().iter().any(|p| p.id == proposal_id) - }); + let exists = PROPOSALS.with(|proposals| proposals.borrow().iter().any(|p| p.id == proposal_id)); if !exists { println!("Proposal not found for ID: {}", proposal_id); @@ -145,12 +145,18 @@ fn vote_on_proposal(proposal_id: u64, vote: bool) -> Result<(), String> { let proposal_votes = votes.entry(proposal_id).or_insert_with(HashMap::new); if proposal_votes.contains_key(&voter_principal) { - println!("Principal: {} has already voted on proposal: {}", voter_principal, proposal_id); + println!( + "Principal: {} has already voted on proposal: {}", + voter_principal, proposal_id + ); true } else { // Record the new vote. proposal_votes.insert(voter_principal.clone(), vote); - println!("Vote: {} recorded for principal: {} on proposal: {}", vote, voter_principal, proposal_id); + println!( + "Vote: {} recorded for principal: {} on proposal: {}", + vote, voter_principal, proposal_id + ); false } }); @@ -175,4 +181,3 @@ fn vote_on_proposal(proposal_id: u64, vote: bool) -> Result<(), String> { Ok(()) } -