diff --git a/Cargo.lock b/Cargo.lock index f54cea7edf..84c11da4e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,23 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -26,6 +43,18 @@ version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[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.2" @@ -43,6 +72,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_impl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -70,6 +111,16 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + [[package]] name = "bitvec" version = "0.20.4" @@ -77,7 +128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" dependencies = [ "funty", - "radium", + "radium 0.6.2", "tap", "wyz", ] @@ -104,6 +155,15 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "block-buffer" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +dependencies = [ + "generic-array 0.14.4", +] + [[package]] name = "block-padding" version = "0.1.5" @@ -119,6 +179,51 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "borsh" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18dda7dc709193c0d86a1a51050a926dc3df1cf262ec46a23a25dba421ea1924" +dependencies = [ + "borsh-derive", + "hashbrown 0.9.1", +] + +[[package]] +name = "borsh-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684155372435f578c0fa1acd13ebbb182cc19d6b38b64ae7901da4393217d264" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2102f62f8b6d3edeab871830782285b64cc1830168094db05c8e458f209bc5c3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196c978c4c9b0b142d446ef3240690bf5a8a33497074a113ff9a337ccb750483" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bstr" version = "0.2.17" @@ -137,6 +242,12 @@ version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +[[package]] +name = "byte-slice-cast" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" + [[package]] name = "byte-slice-cast" version = "1.2.0" @@ -254,6 +365,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + [[package]] name = "criterion" version = "0.3.5" @@ -265,7 +385,7 @@ dependencies = [ "clap", "criterion-plot", "csv", - "itertools", + "itertools 0.10.3", "lazy_static", "num-traits", "oorandom", @@ -287,7 +407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" dependencies = [ "cast", - "itertools", + "itertools 0.10.3", ] [[package]] @@ -340,6 +460,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +dependencies = [ + "generic-array 0.14.4", +] + [[package]] name = "csv" version = "1.1.6" @@ -402,6 +531,17 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "digest" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" +dependencies = [ + "block-buffer 0.10.0", + "crypto-common", + "generic-array 0.14.4", +] + [[package]] name = "either" version = "1.6.1" @@ -421,7 +561,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01317735d563b3bad2d5f90d2e1799f414165408251abb762510f40e790e69a" dependencies = [ "anyhow", - "ethereum-types", + "ethereum-types 0.11.0", + "hex", + "serde", + "serde_json", + "sha3 0.9.1", + "thiserror", + "uint", +] + +[[package]] +name = "ethabi" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c98847055d934070b90e806e12d3936b787d0a115068981c1d8dfd5dfef5a5" +dependencies = [ + "ethereum-types 0.12.1", "hex", "serde", "serde_json", @@ -449,11 +604,11 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567ce064a8232c16e2b2c2173a936b91fbe35c2f2c5278871f5a1a31688b42e9" dependencies = [ - "ethereum-types", + "ethereum-types 0.11.0", "funty", "hash-db", "hash256-std-hasher", - "parity-scale-codec", + "parity-scale-codec 2.3.1", "rlp", "rlp-derive", "serde", @@ -471,7 +626,21 @@ dependencies = [ "fixed-hash", "impl-rlp", "impl-serde", - "primitive-types", + "primitive-types 0.9.1", + "uint", +] + +[[package]] +name = "ethereum-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types 0.10.1", "uint", ] @@ -486,8 +655,8 @@ dependencies = [ "evm-gasometer", "evm-runtime", "log", - "parity-scale-codec", - "primitive-types", + "parity-scale-codec 2.3.1", + "primitive-types 0.9.1", "rlp", "serde", "sha3 0.8.2", @@ -500,8 +669,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f235e93b84fccc1ebdffad226dc56caf833de2fb2f3395f933d95fbf66b254e" dependencies = [ "funty", - "parity-scale-codec", - "primitive-types", + "parity-scale-codec 2.3.1", + "primitive-types 0.9.1", "serde", ] @@ -513,7 +682,7 @@ checksum = "463412356790c5e34e8a13cd23ba06284d9afa999e82e8c64497aed2ee625375" dependencies = [ "evm-core", "evm-runtime", - "primitive-types", + "primitive-types 0.9.1", ] [[package]] @@ -523,7 +692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c08f510e5535cee2352adb9b93ff24dc80f8ca1bad445a9aa1292ce144b45a1" dependencies = [ "evm-core", - "primitive-types", + "primitive-types 0.9.1", "sha3 0.8.2", ] @@ -599,7 +768,10 @@ dependencies = [ name = "fe-compiler-test-utils" version = "0.13.0-alpha" dependencies = [ - "ethabi", + "bytes", + "criterion", + "ethabi 14.1.0", + "ethabi 16.0.0", "evm", "evm-runtime", "fe-analyzer", @@ -608,12 +780,15 @@ dependencies = [ "fe-test-files", "fe-yulc", "fe-yulgen", + "fevm", "getrandom 0.2.3", "hex", "indexmap", - "primitive-types", + "primitive-types 0.10.1", + "primitive-types 0.9.1", + "revm", "serde_json", - "solc", + "solc 0.1.0 (git+https://github.com/g-r-a-n-t/solc-rust?rev=52d4146)", "yultsur", ] @@ -621,7 +796,7 @@ dependencies = [ name = "fe-compiler-tests" version = "0.13.0-alpha" dependencies = [ - "ethabi", + "ethabi 14.1.0", "evm", "evm-runtime", "fe-analyzer", @@ -633,10 +808,12 @@ dependencies = [ "fe-test-files", "fe-yulc", "fe-yulgen", + "fevm", "hex", "insta", + "once_cell", "pretty_assertions", - "primitive-types", + "primitive-types 0.9.1", "proptest", "rand 0.7.3", "rstest", @@ -719,7 +896,7 @@ dependencies = [ "fe-yulgen", "indexmap", "serde_json", - "solc", + "solc 0.1.0 (git+https://github.com/g-r-a-n-t/solc-rust?rev=52d4146)", ] [[package]] @@ -744,6 +921,28 @@ dependencies = [ "yultsur", ] +[[package]] +name = "fevm" +version = "0.1.0" +dependencies = [ + "bytes", + "ethabi 16.0.0", + "fe-analyzer", + "fe-common", + "fe-driver", + "fe-test-files", + "fe-yulc", + "fe-yulgen", + "getrandom 0.2.3", + "hex", + "indexmap", + "primitive-types 0.10.1", + "revm", + "serde_json", + "solc 0.1.0 (git+https://github.com/g-r-a-n-t/solc-rust?rev=da554b3)", + "yultsur", +] + [[package]] name = "fixed-hash" version = "0.7.0" @@ -844,11 +1043,23 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.7", +] + [[package]] name = "hashbrown" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.6", +] [[package]] name = "heck" @@ -886,7 +1097,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 2.3.1", ] [[package]] @@ -974,7 +1185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", ] [[package]] @@ -1001,6 +1212,15 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.10.3" @@ -1042,6 +1262,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1118,6 +1341,26 @@ dependencies = [ "autocfg", ] +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -1129,6 +1372,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -1139,6 +1391,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -1158,6 +1433,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" +dependencies = [ + "proc-macro-crate 1.1.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "once_cell" version = "1.9.0" @@ -1191,15 +1487,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "parity-scale-codec" +version = "1.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b26b16c7687c3075982af47719e481815df30bc544f7a6690763a25ca16e9d" +dependencies = [ + "arrayvec 0.5.2", + "bitvec 0.17.4", + "byte-slice-cast 0.3.5", + "serde", +] + [[package]] name = "parity-scale-codec" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", + "arrayvec 0.7.2", + "bitvec 0.20.4", + "byte-slice-cast 1.2.0", "impl-trait-for-tuples", "parity-scale-codec-derive", "serde", @@ -1211,7 +1519,7 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.1.0", "proc-macro2", "quote", "syn", @@ -1312,6 +1620,28 @@ dependencies = [ "uint", ] +[[package]] +name = "primitive-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + [[package]] name = "proc-macro-crate" version = "1.1.0" @@ -1322,6 +1652,30 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -1369,6 +1723,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + [[package]] name = "radium" version = "0.6.2" @@ -1509,6 +1869,50 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "revm" +version = "1.0.0" +source = "git+https://github.com/bluealloy/revm#d7fa214af76c5105e450fc3ff6dcc2ea8bb67276" +dependencies = [ + "arrayref", + "auto_impl", + "bytes", + "hashbrown 0.11.2", + "num_enum", + "primitive-types 0.10.1", + "revm_precompiles", + "rlp", + "sha3 0.10.0", + "zkp-u256", +] + +[[package]] +name = "revm_precompiles" +version = "0.3.0" +source = "git+https://github.com/bluealloy/revm#d7fa214af76c5105e450fc3ff6dcc2ea8bb67276" +dependencies = [ + "borsh", + "bytes", + "num", + "primitive-types 0.10.1", + "ripemd160", + "secp256k1", + "sha2", + "sha3 0.9.1", + "substrate-bn", +] + +[[package]] +name = "ripemd160" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "rlp" version = "0.5.1" @@ -1646,6 +2050,24 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "secp256k1" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "0.9.0" @@ -1699,9 +2121,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" dependencies = [ "itoa 1.0.1", "ryu", @@ -1720,6 +2142,19 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "sha3" version = "0.8.2" @@ -1745,6 +2180,16 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha3" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" +dependencies = [ + "digest 0.10.1", + "keccak", +] + [[package]] name = "similar" version = "1.3.0" @@ -1775,6 +2220,21 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "solc" +version = "0.1.0" +source = "git+https://github.com/g-r-a-n-t/solc-rust?rev=da554b3#da554b3ba7cb8e63083440eecb77f637c92c40e8" +dependencies = [ + "cmake", + "lazy_static", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1809,6 +2269,19 @@ dependencies = [ "syn", ] +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand 0.8.4", + "rustc-hex", +] + [[package]] name = "syn" version = "1.0.82" @@ -2163,3 +2636,19 @@ source = "git+https://github.com/g-r-a-n-t/yultsur?rev=ae85470#ae854702e90b2c70e dependencies = [ "indenter", ] + +[[package]] +name = "zkp-u256" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9931b419a40ffca971d538c4b5edca60d1d82d77fd6bce73fb4bcb9639776c4" +dependencies = [ + "crunchy", + "hex", + "itertools 0.9.0", + "no-std-compat", + "num-traits", + "parity-scale-codec 1.3.7", + "rand 0.7.3", + "serde", +] diff --git a/crates/analyzer/tests/snapshots/analysis__uniswap.snap b/crates/analyzer/tests/snapshots/analysis__uniswap.snap index e54a08d2b9..259549503d 100644 --- a/crates/analyzer/tests/snapshots/analysis__uniswap.snap +++ b/crates/analyzer/tests/snapshots/analysis__uniswap.snap @@ -4159,7 +4159,7 @@ note: 311 │ ╭ pub fn create_pair(self, token_a: address, token_b: address) -> address: 312 │ │ assert token_a != token_b, "UniswapV2: IDENTICAL_ADDRESSES" 313 │ │ -314 │ │ let token0: address = token_a if token_a < token_b else token_b +314 │ │ let token0: address = token_a · │ 328 │ │ emit PairCreated(token0, token1, pair=address(pair), index=self.pair_counter) 329 │ │ return address(pair) @@ -4197,9 +4197,9 @@ note: note: ┌─ demos/uniswap.fe:314:21 │ -314 │ let token0: address = token_a if token_a < token_b else token_b +314 │ let token0: address = token_a │ ^^^^^^^ address -315 │ let token1: address = token_a if token_a > token_b else token_b +315 │ let token1: address = token_b │ ^^^^^^^ address · 319 │ let salt: u256 = keccak256((token0, token1).abi_encode()) @@ -4223,44 +4223,10 @@ note: │ │ │ bool: Value 313 │ -314 │ let token0: address = token_a if token_a < token_b else token_b - │ ^^^^^^^ ^^^^^^^ address: Value - │ │ - │ address: Value - -note: - ┌─ demos/uniswap.fe:314:31 - │ -314 │ let token0: address = token_a if token_a < token_b else token_b - │ ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^ address: Value - │ │ │ - │ │ bool: Value - │ address: Value - -note: - ┌─ demos/uniswap.fe:314:31 - │ -314 │ let token0: address = token_a if token_a < token_b else token_b - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ address: Value -315 │ let token1: address = token_a if token_a > token_b else token_b - │ ^^^^^^^ ^^^^^^^ address: Value - │ │ - │ address: Value - -note: - ┌─ demos/uniswap.fe:315:31 - │ -315 │ let token1: address = token_a if token_a > token_b else token_b - │ ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^ address: Value - │ │ │ - │ │ bool: Value - │ address: Value - -note: - ┌─ demos/uniswap.fe:315:31 - │ -315 │ let token1: address = token_a if token_a > token_b else token_b - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ address: Value +314 │ let token0: address = token_a + │ ^^^^^^^ address: Value +315 │ let token1: address = token_b + │ ^^^^^^^ address: Value 316 │ assert token0 != address(0), "UniswapV2: ZERO_ADDRESS" │ ^^^^^^ ^ u256: Value │ │ diff --git a/crates/fevm/Cargo.toml b/crates/fevm/Cargo.toml new file mode 100644 index 0000000000..43bf33f2ca --- /dev/null +++ b/crates/fevm/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "fevm" +version = "0.1.0" +authors = ["The Fe Developers "] +edition = "2021" +license = "GPL-3.0-or-later" +repository = "https://github.com/ethereum/fe" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bytes = { version = "1.1.0", default-features = false } +ethabi = "16.0.0" +hex = "0.4.3" +primitive-types = { version = "0.10.1", default-features = false, features = ["rlp"] } +serde_json = "1.0.74" +revm = {git = "https://github.com/bluealloy/revm"} +fe-common = {path = "../common", version = "^0.13.0-alpha"} +fe-driver = {path = "../driver", version = "^0.13.0-alpha"} +fe-yulgen = {path = "../yulgen", version = "^0.13.0-alpha"} +fe-yulc = {path = "../yulc", version = "^0.13.0-alpha", optional = true, features = ["solc-backend"]} +fe-analyzer = {path = "../analyzer", version = "^0.13.0-alpha"} +solc = {git = "https://github.com/g-r-a-n-t/solc-rust", rev = "da554b3", optional = true} +yultsur = {git = "https://github.com/g-r-a-n-t/yultsur", rev = "ae85470"} +indexmap = "1.6.2" +getrandom = { version = "0.2.3", features = ["js"] } +test-files = {path = "../test-files", package = "fe-test-files" } + + +[features] +solc-backend = ["fe-yulc", "solc", "fe-driver/solc-backend"] diff --git a/crates/fevm/src/conversion/mod.rs b/crates/fevm/src/conversion/mod.rs new file mode 100644 index 0000000000..7a3da9fa9f --- /dev/null +++ b/crates/fevm/src/conversion/mod.rs @@ -0,0 +1,75 @@ + +use crate::{U256, H160}; +use std::str::FromStr; + + +#[allow(dead_code)] +pub fn uint_token(n: u64) -> ethabi::Token { + ethabi::Token::Uint(U256::from(n)) +} + +#[allow(dead_code)] +pub fn uint_token_from_dec_str(val: &str) -> ethabi::Token { + ethabi::Token::Uint(U256::from_dec_str(val).expect("Not a valid dec string")) +} + +#[allow(dead_code)] +pub fn address_token(addr: primitive_types::H160) -> ethabi::Token { + ethabi::Token::Address(addr.clone()) +} + +#[allow(dead_code)] +pub fn address_token_from_str(s: &str) -> ethabi::Token { + // left pads to 40 characters + ethabi::Token::Address(address(&format!("{:0>40}", s))) +} + +#[allow(dead_code)] +pub fn string_token(s: &str) -> ethabi::Token { + ethabi::Token::String(s.to_string()) +} + +#[allow(dead_code)] +pub fn bool_token(val: bool) -> ethabi::Token { + ethabi::Token::Bool(val) +} + +#[allow(dead_code)] +pub fn address(s: &str) -> primitive_types::H160 { + H160::from_str(s).unwrap_or_else(|_| panic!("couldn't create address from: {}", s)) +} + + +#[allow(dead_code)] +pub fn tuple_token(tokens: &[ethabi::Token]) -> ethabi::Token { + ethabi::Token::Tuple(tokens.to_owned()) +} + + +#[allow(dead_code)] +pub fn int_token(val: i64) -> ethabi::Token { + ethabi::Token::Int(to_2s_complement(val)) +} + +#[allow(dead_code)] +pub fn to_2s_complement(val: i64) -> U256 { + // Since this API takes an `i64` we can be sure that the min and max values + // will never be above what fits the `I256` type which has the same capacity + // as U256 but splits it so that one half covers numbers above 0 and the + // other half covers the numbers below 0. + + // Conversion to Two's Complement: https://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html + + if val >= 0 { + U256::from(val) + } else { + let positive_val = -val; + get_2s_complement_for_negative(U256::from(positive_val)) + } +} + +#[allow(dead_code)] +pub fn get_2s_complement_for_negative(assume_negative: U256) -> U256 { + let (negated, _) = assume_negative.overflowing_neg(); + negated + 1 +} \ No newline at end of file diff --git a/crates/fevm/src/lib.rs b/crates/fevm/src/lib.rs new file mode 100644 index 0000000000..5210e1c0cb --- /dev/null +++ b/crates/fevm/src/lib.rs @@ -0,0 +1,179 @@ +pub mod types; +use ethabi::Token; +use revm::Log; +pub use types::*; + + +use bytes::Bytes; +use fe_common::diagnostics::print_diagnostics; +use fe_common::files::FileStore; +use fe_common::utils::keccak; +use fe_yulgen::runtime::functions; +use std::borrow::{Borrow, BorrowMut}; +use std::collections::HashMap; +use std::str::FromStr; +use yultsur::*; +pub use revm::{ + self, + Return, + InMemoryDB, + EVM, + AccountInfo, + TransactTo, + TransactOut, + SpecId, + NoOpInspector, + Host +}; +pub use primitive_types::{self, H160, U256}; +use std::cell::RefCell; +use std::sync::Mutex; +pub mod conversion; +pub use conversion::*; +pub use ethabi; +pub type GasUsed = u64; +pub type CallResult = (Return, TransactOut, GasUsed, Vec); + + +pub struct TransactionResult { + pub return_code: Return, + pub return_data: TransactOut, + pub gas_used: u64, + pub logs: Vec +} + +impl TransactionResult { + pub fn ret_eq(&self, other: TransactionResult) -> bool { + todo!() + } + + pub fn data_eq(&self, other: TransactionResult) -> bool { + todo!() + } + + pub fn gas_lt(&self, other: TransactionResult) -> bool { + todo!() + } + + pub fn gas_eq(&self, other: TransactionResult) -> bool { + todo!() + } + + pub fn gas_gt(&self, other: TransactionResult) -> bool { + todo!() + } + + +} + + + +pub trait ToBeBytes { + fn to_be_bytes(&self) -> [u8; 32]; +} + +impl ToBeBytes for U256 { + fn to_be_bytes(&self) -> [u8; 32] { + let mut input_bytes: [u8; 32] = [0; 32]; + self.to_big_endian(&mut input_bytes); + input_bytes + } +} + +pub trait AsToken { + fn as_token(&self) -> Token; +} + +pub struct Fevm<'a>{ + inner: Mutex>, + contracts: HashMap<&'a ContractId, Contract<'a>> + +} + + + +impl Fevm<'_> { + + pub fn new() -> Self { + let mut vm = revm::new(); + vm.database(InMemoryDB::default()); + Self { + inner: Mutex::new(vm), + contracts: HashMap::new() + } + } + + pub fn reset(&mut self) { + self.inner = Mutex::new(revm::new()); + self.contracts = HashMap::new(); + } + pub fn call(&self, input: Vec, addr: &Address, caller: &Caller) -> CallResult { + let mut vm = self.inner.lock().unwrap(); + vm.env.tx.caller = caller.0; + vm.env.tx.transact_to = TransactTo::Call(addr.clone()); + vm.env.tx.data = input.into(); + vm.inspect_commit(NoOpInspector{}) + } + + pub fn deploy(&self, contract: &mut Contract, deployer: &Caller, init_params: &[ethabi::Token]) { + if let ContractCode::Bytes(bin) = &contract.code { + let mut bytecode = bin.clone(); + + if let Some(constructor) = &contract.abi.constructor { + bytecode = constructor.encode_input(bytecode, init_params).unwrap() + } + + let mut vm = self.inner.lock().unwrap(); + match vm.db().expect("DB not found").cache().get_key_value(deployer.as_ref()) { + Some(_) => { + vm.env.tx.caller = deployer.as_ref().clone(); + vm.env.tx.transact_to = TransactTo::create(); + vm.env.tx.data = Bytes::from(bytecode); + let (_, out, _, _) = vm.transact_commit(); + let contract_address = match out { + TransactOut::Create(_, Some(contract)) => contract, + _ => panic!("Invalid create. This is a bug in the EVM"), + }; + contract.code = ContractCode::Deployed; + contract.address = Some(contract_address); + + }, + None => panic!("Invalid caller. Please deploy with an existing address."), + } + } else { + panic!("Contract does not have bytecode. If you wish to redeploy, please re-instantiate with bytecode"); + } + } + + pub fn create_account(&self, address: impl AsRef
, balance: impl Into) { + let acc = AccountInfo::from_balance(balance.into()); + self.inner.lock().unwrap().db().unwrap().insert_cache(address.as_ref().clone(), acc); + } + + pub fn fund_account(&self, address: &Address, amt: impl Into) { + let mut vm = self.inner.lock().unwrap(); + + let mut acc = vm.db().unwrap().cache().get(address) + .expect(format!("Cannot find account for address {:?}. Please create account first", address).as_str()) + .clone(); + acc.balance += amt.into(); + vm.db().unwrap().insert_cache(address.clone(), acc); + } + + pub fn balance_of(&self, address: &Address) -> U256 { + match self.inner.lock().unwrap().db().unwrap().cache().get(address) { + Some(acc) => acc.balance, + None => 0.into() + } + } + + pub fn get_account(&self, address: &Address) -> Option { + self.inner.lock().unwrap().db().unwrap().cache().get(address).cloned() + } + + pub fn erase(&self, address: &Address) -> Address { + todo!() + } + + +} \ No newline at end of file diff --git a/crates/fevm/src/types/address.rs b/crates/fevm/src/types/address.rs new file mode 100644 index 0000000000..8078caf54c --- /dev/null +++ b/crates/fevm/src/types/address.rs @@ -0,0 +1,53 @@ +use crate::primitive_types::H160; +use crate::AsToken; +use crate::conversion::address_token; +use ethabi::token::Token; +pub type Address = H160; +fn random_address() -> Address { + Address::random() +} + + + +pub struct Caller(pub Address); + +impl Caller { + pub fn random() -> Self { + Self(random_address()) + } + + pub fn address(&self) -> Address { + self.0 + } +} + +impl AsRef
for Caller { + fn as_ref(&self) -> &Address { + &self.0 + } +} + + +impl From
for Caller { + fn from(addr: Address) -> Self { + Self(addr) + } +} + +impl Into for Caller { + fn into(self) -> Token { + Token::Address(self.address()) + } +} + +impl AsToken for Address { + fn as_token(&self) -> Token { + address_token(self.clone()) + } +} + +impl AsToken for Caller { + fn as_token(&self) -> Token { + Token::Address(self.address()) + } +} \ No newline at end of file diff --git a/crates/fevm/src/types/contract.rs b/crates/fevm/src/types/contract.rs new file mode 100644 index 0000000000..411385cecf --- /dev/null +++ b/crates/fevm/src/types/contract.rs @@ -0,0 +1,279 @@ +use std::{str::FromStr, path::{PathBuf, Path}}; +use bytes::Bytes; +use fe_common::files::FileStore; +use primitive_types::{H160, U256}; +use revm::{TransactOut, Return}; +use serde_json; +use crate::{Fevm, Caller, CallResult, Address}; + + +#[derive(Debug)] +pub struct SolidityCompileError(Vec); + +#[derive(Hash, PartialEq, Eq, Clone, Debug)] +pub enum ContractId { + Name(String), + Address(H160), +} + +impl From for ContractId { + fn from(other: String) -> Self { + ContractId::Name(other) + } +} + +impl From for ContractId { + fn from(other: H160) -> Self { + ContractId::Address(other) + } +} + +impl From<&str> for ContractId { + fn from(other: &str) -> Self { + let as_address = H160::from_str(other); + match as_address { + Ok(addr) => ContractId::Address(addr), + Err(_) => ContractId::Name(other.to_owned()) + } + } +} +#[derive(Clone)] +pub enum ContractCode { + Bytes(Vec), + Deployed +} + + +#[derive(Default)] +pub struct ContractBuilder<'a> { + vm: Option<&'a Fevm<'a>>, + abi: Option, + address: Option
, + code: Option, +} + +impl<'a> ContractBuilder<'a> { + + pub fn new(vm: &'a Fevm<'a>) -> Self { + Self { + vm: Some(vm), + ..Default::default() + } + } + + pub fn address(mut self, addr: Address) -> Self { + self.address = Some(addr); + self + } + + #[cfg(feature = "solc-backend")] + pub fn sol_fixture(mut self, fixture: &str, contract_name: &str) -> Contract<'a> { + let src = test_files::fixture(fixture) + .replace("\n", "") + .replace("\"", "\\\""); + + let (bytecode, abi) = compile_solidity_contract(contract_name, &src, true) + .expect("Could not compile contract"); + + Contract { + vm: self.vm.unwrap(), + abi: ethabi::Contract::load(abi.as_bytes()).expect("Unable to generate solidity contract abi"), + address: self.address, + code: ContractCode::Bytes(hex::decode(bytecode).expect("Failed to decode Solidity bytecode")) + } + + } + #[cfg(feature = "solc-backend")] + pub fn fixture( + mut self, + fixture: &str, + contract_name: &str, + ) -> Contract<'a> + { + let src = test_files::fixture(fixture); + let mut files = FileStore::new(); + let id = files.add_file(fixture, src); + let deps = files.add_included_libraries(); + + let compiled_module = match fe_driver::compile_module(&files, id, &deps, true, true) { + Ok(module) => module, + Err(error) => { + fe_common::diagnostics::print_diagnostics(&error.0, &files); + panic!("failed to compile module: {}", fixture) + } + }; + let compiled_contract = compiled_module + .contracts + .get(contract_name) + .expect("could not find contract in fixture"); + + + let mut bytecode = hex::decode(&compiled_contract.bytecode) + .expect("Failed to decode bytecode"); + Contract { + vm: self.vm.unwrap(), + abi: ethabi::Contract::load(compiled_contract.json_abi.as_bytes()).expect("Unable to load contract abi from compiled module"), + address: self.address, + code: ContractCode::Bytes(bytecode) + } + + } +} + + +#[derive(Clone)] +pub struct Contract<'a> { + vm: &'a Fevm<'a>, + pub abi: ethabi::Contract, + pub address: Option
, + pub code: ContractCode, + +} + + + + + +impl Contract<'_> { + + pub fn capture_call(&self, name: &str, input: &[ethabi::Token], caller: &Caller) -> CallResult { + if self.address.is_none() { + panic!("Please deploy contract prior to making calls!"); + } + let function = &self.abi.functions[name][0]; + let input = self.build_calldata(name, input); + + + self.vm.call(input, self.address.as_ref().unwrap(), caller) + + } + pub fn call(&self, name: &str, input: &[ethabi::Token], caller: &Caller) -> Option { + if self.address.is_none() { + panic!("Please deploy contract prior to making calls!"); + } + let function = &self.abi.functions[name][0]; + let input = self.build_calldata(name, input); + + let (return_code, tx_result, gas, logs) = + self.vm.call(input, self.address.as_ref().unwrap(), caller); + match return_code { + Return::Return | Return::Stop => { + if let TransactOut::Call(data) = tx_result { + function.decode_output(&data) + .unwrap_or_else(|e| panic!("unable to decode output of {}: {:?}\nError: {:?}", name, &data, e)) + .pop() + } else { + panic!("Unexpected result of function call!"); + } + }, + Return::Revert => { + if let TransactOut::Call(data) = &tx_result { + function.decode_output(&data.to_vec()) + .unwrap_or_else(|e| panic!("Tx Revert! Unable to decode output of {}: {:?}\nError: {:?}", name, &data, e)) + .pop(); + panic!("Tx Revert! Tx Data: {:?}", tx_result) + } + panic!("Tx Revert! Tx Data: {:?}", tx_result) + } + _ => panic!("Unexpected return code! {:?}", return_code) + } + } + + pub fn build_calldata(&self, name: &str, input: &[ethabi::Token]) -> Vec { + let function = &self.abi.functions[name][0]; + let encoded = function + .encode_input(input) + .unwrap_or_else(|_| panic!("Unable to encode input for {}", name)); + encoded + } + + pub fn deploy(mut self, deployer: &Caller, init_params: &[ethabi::Token]) -> Self { + self.vm.deploy(&mut self, deployer, init_params); + + self + } + + pub fn address(&self) -> Address { + self.address.clone().unwrap() + } +} + + +#[cfg(feature = "solc-backend")] +pub fn compile_solidity_contract( + name: &str, + solidity_src: &str, + optimized: bool, +) -> Result<(String, String), SolidityCompileError> { + let solc_config = r#" + { + "language": "Solidity", + "sources": { "input.sol": { "content": "{src}" } }, + "settings": { + "optimizer": { "enabled": {optimizer_enabled} }, + "outputSelection": { "*": { "*": ["*"], "": [ "*" ] } } + } + } + "#; + let solc_config = solc_config + .replace("{src}", solidity_src) + .replace("{optimizer_enabled}", &optimized.to_string()); + + let raw_output = solc::compile(&solc_config); + + let output: serde_json::Value = + serde_json::from_str(&raw_output).expect("Unable to compile contract"); + + if output["errors"].is_array() { + let severity: serde_json::Value = + serde_json::to_value("error").expect("Unable to convert into serde value type"); + let errors: serde_json::Value = output["errors"] + .as_array() + .unwrap() + .iter() + .cloned() + .filter_map(|err| { + if err["severity"] == severity { + Some(err["formattedMessage"].clone()) + } else { + None + } + }) + .collect(); + + let errors_list = errors + .as_array() + .unwrap_or_else(|| panic!("Unable to parse error properly")); + if !errors_list.is_empty() { + return Err(SolidityCompileError(errors_list.clone())); + } + } + + let bytecode = output["contracts"]["input.sol"][name]["evm"]["bytecode"]["object"] + .to_string() + .replace("\"", ""); + + let abi = if let serde_json::Value::Array(data) = &output["contracts"]["input.sol"][name]["abi"] + { + data.iter() + .cloned() + .filter(|val| { + // ethabi doesn't yet support error types so we just filter them out for now + // https://github.com/rust-ethereum/ethabi/issues/225 + val["type"] != "error" + }) + .collect::>() + } else { + vec![] + }; + + let abi = serde_json::Value::Array(abi).to_string(); + + if [&bytecode, &abi].iter().any(|val| val == &"null") { + return Err(SolidityCompileError(vec![serde_json::Value::String( + String::from("Bytecode not found"), + )])); + } + + Ok((bytecode, abi)) +} \ No newline at end of file diff --git a/crates/fevm/src/types/mod.rs b/crates/fevm/src/types/mod.rs new file mode 100644 index 0000000000..851c7629ba --- /dev/null +++ b/crates/fevm/src/types/mod.rs @@ -0,0 +1,5 @@ +pub mod contract; +pub mod address; + +pub use contract::*; +pub use address::*; \ No newline at end of file diff --git a/crates/fevm/tests/fevm.rs b/crates/fevm/tests/fevm.rs new file mode 100644 index 0000000000..58b1915ff2 --- /dev/null +++ b/crates/fevm/tests/fevm.rs @@ -0,0 +1,315 @@ +// use fevm::{Fevm, ContractBuilder, Contract, Caller, Address, U256, conversion::*, AsToken}; +// use primitive_types::H160; +// use std::str::FromStr; + + +// #[test] +// fn test_get_u256() { +// let mut fevm = Fevm::new(); + +// let contract = ContractBuilder::new(&fevm) +// .fixture("features/return_u256.fe", "Foo"); + +// let caller = Caller::random(); + +// fevm.create_account(&caller,1000); + +// let contract = contract.deploy(&caller, &[]); + +// let call_result = contract.call("bar", &[], &caller); + +// assert_eq!(Some(uint_token(42)), call_result); +// } + +// #[test] +// fn uniswap_fevm() { +// // -------------------------------ENVIRONMENT SETUP------------------------------- +// let mut fevm = Fevm::new(); + +// let alice = Caller::random(); +// let bob = Caller::random(); +// let deployer = Caller::random(); + +// fevm.create_account(&alice, 0_u64); +// fevm.create_account(&bob, 0_u64); +// fevm.create_account(&deployer, 2000_u64); + + +// // -------------------------------TOKEN SETUP------------------------------- +// let token0_name = string_token("Fe Coin"); +// let token0_symbol = string_token("fe"); +// let token1_name = string_token("Maker"); +// let token1_symbol = string_token("mkr"); + +// let token0_contract = ContractBuilder::new(&fevm) +// .fixture("demos/erc20_token.fe", "ERC20"); +// let token0_contract = token0_contract.deploy(&deployer, &[token0_name, token0_symbol]); + +// let token1_contract = ContractBuilder::new(&fevm) +// .fixture("demos/erc20_token.fe", "ERC20"); +// let token1_contract = token1_contract.deploy(&deployer, &[token1_name, token1_symbol]); + +// let token0_address = token0_contract.address.clone().unwrap().as_token(); +// let token1_address = token1_contract.address.clone().unwrap().as_token(); +// token0_contract.call( +// "transfer", +// &[ +// alice.as_token(), +// uint_token_from_dec_str("500000000000000000000000"), +// ], +// &deployer +// ); +// token1_contract.call( +// "transfer", +// &[alice.as_token(), +// uint_token_from_dec_str("500000000000000000000000")], +// &deployer +// ); + +// let balance_alice = token1_contract.call( +// "balanceOf", +// &[alice.as_token()], +// &alice +// ).unwrap(); + +// assert_eq!(balance_alice, uint_token_from_dec_str("500000000000000000000000")); + +// let balance_alice = token0_contract.call( +// "balanceOf", +// &[alice.as_token()], +// &alice +// ).unwrap(); + +// assert_eq!(balance_alice, uint_token_from_dec_str("500000000000000000000000")); + +// // -------------------------------FACTORY SETUP------------------------------- + +// let factory_contract = ContractBuilder::new(&fevm) +// .fixture("demos/uniswap.fe", "UniswapV2Factory"); +// let factory_contract = factory_contract.deploy(&deployer, &[address_token(H160::default())]); +// let factory_address = factory_contract.address.clone().unwrap().as_token(); + +// let pair_address = factory_contract.call( +// "create_pair", +// &[token0_address.clone(), token1_address.clone()], +// &deployer +// ).unwrap(); +// let pair_address = pair_address.into_address().unwrap(); +// let pair_contract = ContractBuilder::new(&fevm) +// .address(pair_address) +// .fixture( "demos/uniswap.fe", "UniswapV2Pair"); + + +// let read_factory_ret = pair_contract.call("factory", &[], &deployer).unwrap(); + +// assert_eq!(read_factory_ret, factory_address); + + +// let token0_pair_addr = pair_contract +// .call("token0", &[], &deployer) +// .unwrap(); +// assert!(token0_pair_addr == token0_address.clone() || token0_pair_addr == token1_address.clone()); + +// let token1_pair_addr = pair_contract +// .call("token1", &[], &deployer) +// .unwrap(); +// assert!(token1_pair_addr == token1_address.clone() || token0_pair_addr == token1_address.clone()); + + +// // -------------------------------ALICE ADDS LIQUIDITY------------------------------- +// let ret = token0_contract +// .call("transfer", &[ +// pair_address.as_token(), +// uint_token_from_dec_str("200000000000000000000") +// ], &alice) +// .unwrap(); +// assert_eq!(ret, bool_token(true)); + +// let ret = token1_contract +// .call("transfer", &[ +// pair_address.as_token(), +// uint_token_from_dec_str("100000000000000000000") +// ], &alice) +// .unwrap(); +// assert_eq!(ret, bool_token(true)); + +// //---------------------Mint alice liquidity tokens--------------------- +// // Since we have sent 200 of token0 and 100 of token1, +// // value of token0 is 1/2 that of token1 +// let alice_liquidity = pair_contract +// .call("mint", &[alice.as_token()], &bob) +// .unwrap(); + +// let alice_lp_tkn_balance = pair_contract +// .call("balanceOf",&[alice.as_token()], &bob) +// .unwrap(); +// assert_eq!(alice_liquidity, alice_lp_tkn_balance); + +// // ---------------------Check Min Liquidity--------------------- + +// let locked_liquidity = pair_contract.call( +// "balanceOf", +// &[address_token_from_str("0")], +// &alice +// ).unwrap(); +// assert_eq!(locked_liquidity, uint_token(1000)); + +// // ---------------------Validate reserves--------------------- + +// let reserves = pair_contract.call( +// "get_reserves", +// &[], +// &alice +// ).unwrap(); +// assert_eq!(reserves, tuple_token(&[ +// uint_token_from_dec_str("200000000000000000000"), +// uint_token_from_dec_str("100000000000000000000"), +// uint_token_from_dec_str("1"), +// ])); + + +// // -------------------------------BOB PERFORMS SWAP------------------------------- + +// //--------------------- Give bob some token1 to swap with--------------------- +// token1_contract.call( +// "transfer", +// &[bob.as_token(), uint_token(1000)], +// &deployer, +// ); + +// // ---------------------Actual Swap--------------------- +// // Bob performs a swap by depositing to 1000 smallest units of token 1 to +// // the pair contract +// // Since token1 price = 1tk1/2tk0, we should expect to receive +// // roughly 2000 tk0 +// token1_contract.call( +// "transfer", +// &[pair_address.as_token(), uint_token(1000)], +// &bob +// ); + +// pair_contract.call( +// "swap", +// &[uint_token(1993), uint_token(0), bob.as_token()], +// &bob +// ); + +// // ---------------------Validate Swap--------------------- +// // Check that bob's token0 balance has increase to 1993 (accounting for 0.3% fee) +// let bob_bal = token0_contract.call( +// "balanceOf", +// &[bob.as_token()], +// &bob +// ).unwrap(); + +// assert_eq!(bob_bal, uint_token_from_dec_str("1993")); + + +// // -------------------------------Validate Reserves------------------------------- +// let reserves_post_swap = pair_contract.call( +// "get_reserves", +// &[], +// &bob +// ).unwrap(); + +// assert_eq!(reserves_post_swap, +// tuple_token(&[ +// uint_token_from_dec_str("199999999999999998007"), +// uint_token_from_dec_str("100000000000000001000"), +// uint_token_from_dec_str("1"), +// ]) +// ); + +// // -------------------------------ALICE REMOVES LIQUIDITY------------------------------- +// pair_contract.call( +// "transfer", +// &[pair_address.as_token(), alice_liquidity], +// &alice +// ); + +// // Alice burn liquidity she sent back +// let burned = pair_contract.call( +// "burn", +// &[alice.as_token()], +// &alice +// ).unwrap(); +// assert_eq!( +// burned, +// tuple_token(&[ +// uint_token_from_dec_str("199999999999999996592"), +// uint_token_from_dec_str("100000000000000000292"), +// ] +// ) +// ); + +// // -------------------------------FINAL CHECK OF TOKEN BALANCES------------------------------- + +// //---------------------Validate Token 0 Balances--------------------- + +// let bob_tkn0 = token0_contract.call( +// "balanceOf", +// &[bob.as_token()], +// &deployer +// ).unwrap(); + +// assert_eq!(bob_tkn0, uint_token_from_dec_str("1993")); + +// let alice_tkn0 = token0_contract.call( +// "balanceOf", +// &[alice.as_token()], +// &deployer +// ).unwrap(); + +// assert_eq!(alice_tkn0, uint_token_from_dec_str("499999999999999999996592")); + +// let pair_tkn0 = token0_contract.call( +// "balanceOf", +// &[pair_address.as_token()], +// &deployer +// ).unwrap(); + +// assert_eq!(pair_tkn0, uint_token_from_dec_str("1415")); + +// let deployer_tkn0 = token0_contract.call( +// "balanceOf", +// &[address_token(deployer.0.clone())], +// &deployer +// ).unwrap(); +// assert_eq!(deployer_tkn0, uint_token_from_dec_str("500000000000000000000000")); + + + +// //---------------------Validate Token1 Balances--------------------- + +// let bob_tkn1 = token1_contract.call( +// "balanceOf", +// &[bob.as_token()], +// &deployer +// ).unwrap(); + +// assert_eq!(bob_tkn1, uint_token_from_dec_str("0")); + +// let alice_tkn1 = token1_contract.call( +// "balanceOf", +// &[alice.as_token()], +// &deployer +// ).unwrap(); + +// assert_eq!(alice_tkn1, uint_token_from_dec_str("500000000000000000000292")); + +// let pair_tkn1 = token1_contract.call( +// "balanceOf", +// &[pair_address.as_token()], +// &deployer +// ).unwrap(); + +// assert_eq!(pair_tkn1, uint_token_from_dec_str("708")); + +// let deployer_tkn1 = token1_contract.call( +// "balanceOf", +// &[address_token(deployer.0.clone())], +// &deployer +// ).unwrap(); +// assert_eq!(deployer_tkn1, uint_token_from_dec_str("499999999999999999999000")); + +// } \ No newline at end of file diff --git a/crates/test-files/fixtures/demos/uniswap.fe b/crates/test-files/fixtures/demos/uniswap.fe index 845f7951fb..dd836a0f2f 100644 --- a/crates/test-files/fixtures/demos/uniswap.fe +++ b/crates/test-files/fixtures/demos/uniswap.fe @@ -311,8 +311,8 @@ contract UniswapV2Factory: pub fn create_pair(self, token_a: address, token_b: address) -> address: assert token_a != token_b, "UniswapV2: IDENTICAL_ADDRESSES" - let token0: address = token_a if token_a < token_b else token_b - let token1: address = token_a if token_a > token_b else token_b + let token0: address = token_a + let token1: address = token_b assert token0 != address(0), "UniswapV2: ZERO_ADDRESS" assert self.pairs[token0][token1] == address(0), "UniswapV2: PAIR_EXISTS" diff --git a/crates/test-files/fixtures/differential/math_i8.fe b/crates/test-files/fixtures/differential/math_i8.fe index 11cc7f5216..b7b00b4e16 100644 --- a/crates/test-files/fixtures/differential/math_i8.fe +++ b/crates/test-files/fixtures/differential/math_i8.fe @@ -1,4 +1,4 @@ -contract Foo: +contract Foomath_i8Fe: pub fn add(val1: i8, val2: i8) -> i8: return val1 + val2 diff --git a/crates/test-files/fixtures/differential/math_i8.sol b/crates/test-files/fixtures/differential/math_i8.sol index 34889e7e6c..2b8d640e9a 100644 --- a/crates/test-files/fixtures/differential/math_i8.sol +++ b/crates/test-files/fixtures/differential/math_i8.sol @@ -1,4 +1,4 @@ -contract Foo { +contract Foomath_i8Sol { function add(int8 val1, int8 val2) public pure returns (int8){ return val1 + val2; diff --git a/crates/test-files/fixtures/differential/math_u8.fe b/crates/test-files/fixtures/differential/math_u8.fe index 9d266de3dc..a04e11b11e 100644 --- a/crates/test-files/fixtures/differential/math_u8.fe +++ b/crates/test-files/fixtures/differential/math_u8.fe @@ -1,4 +1,4 @@ -contract Foo: +contract Foomath_u8Fe: pub fn add(val1: u8, val2: u8) -> u8: return val1 + val2 diff --git a/crates/test-files/fixtures/differential/math_u8.sol b/crates/test-files/fixtures/differential/math_u8.sol index 8934631585..c248ed3f02 100644 --- a/crates/test-files/fixtures/differential/math_u8.sol +++ b/crates/test-files/fixtures/differential/math_u8.sol @@ -1,4 +1,4 @@ -contract Foo { +contract Foomath_u8Sol { function add(uint8 val1, uint8 val2) public pure returns (uint8){ return val1 + val2; diff --git a/crates/test-files/fixtures/differential/storage_and_memory.fe b/crates/test-files/fixtures/differential/storage_and_memory.fe index bd693aa53e..79008cc4c0 100644 --- a/crates/test-files/fixtures/differential/storage_and_memory.fe +++ b/crates/test-files/fixtures/differential/storage_and_memory.fe @@ -5,7 +5,7 @@ struct MyStruct: my_addr: address my_num3: i8 -contract Foo: +contract Foostorage_and_memoryFe: data: MyStruct items: Array diff --git a/crates/test-files/fixtures/differential/storage_and_memory.sol b/crates/test-files/fixtures/differential/storage_and_memory.sol index a882f62d1f..2d6b11e5d8 100644 --- a/crates/test-files/fixtures/differential/storage_and_memory.sol +++ b/crates/test-files/fixtures/differential/storage_and_memory.sol @@ -6,7 +6,7 @@ struct MyStruct { int8 my_num3; } -contract Foo { +contract Foostorage_and_memorySol { MyStruct data; int8[1] items; diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index 96fc6effbd..c84b14e7ce 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -7,7 +7,8 @@ license = "GPL-3.0-or-later" repository = "https://github.com/ethereum/fe" [dependencies] -ethabi = "14.0" +ethabi-old = {package = "ethabi", version = "14.0"} +ethabi-new = {package = "ethabi", version = "16.0"} evm = "0.26.0" evm-runtime = "0.26.0" fe-common = {path = "../common", version = "^0.13.0-alpha"} @@ -16,15 +17,32 @@ fe-yulgen = {path = "../yulgen", version = "^0.13.0-alpha"} fe-yulc = {path = "../yulc", version = "^0.13.0-alpha", optional = true, features = ["solc-backend"]} fe-analyzer = {path = "../analyzer", version = "^0.13.0-alpha"} test-files = {path = "../test-files", package = "fe-test-files" } +fevm = {path = "../fevm", version = "0.1.0"} hex = "0.4" -primitive-types = {version = "0.9", default-features = false, features = ["rlp"]} +primitive-types-old = {package = "primitive-types", version = "0.9", default-features = false, features = ["rlp"]} +primitive-types-new = {package = "primitive-types", version = "0.10", default-features = false, features = ["rlp"]} serde_json = "1.0.64" solc = {git = "https://github.com/g-r-a-n-t/solc-rust", rev = "52d4146", optional = true} yultsur = {git = "https://github.com/g-r-a-n-t/yultsur", rev = "ae85470"} indexmap = "1.6.2" - +bytes = {version = "1.1", default-features = false} # used by ethabi, we need to force the js feature for wasm support getrandom = { version = "0.2.3", features = ["js"] } +revm = {git = "https://github.com/bluealloy/revm"} + +[dev-dependencies] +criterion = "0.3.5" + +[[bench]] +name = "evm" +harness = false +[[bench]] +name = "sputnik" +harness = false + [features] solc-backend = ["fe-yulc", "solc", "fe-driver/solc-backend"] + +[profile.bench] +debug = true \ No newline at end of file diff --git a/crates/test-utils/benches/evm.rs b/crates/test-utils/benches/evm.rs new file mode 100644 index 0000000000..afed24cef1 --- /dev/null +++ b/crates/test-utils/benches/evm.rs @@ -0,0 +1,308 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use fevm::{Fevm, ContractBuilder, Contract, Caller, Address, U256, conversion::*, AsToken}; +use primitive_types_new::H160; +use std::str::FromStr; + + + + +fn uniswap_fevm() { +// -------------------------------ENVIRONMENT SETUP------------------------------- + let mut fevm = Fevm::new(); + + let alice = Caller::random(); + let bob = Caller::random(); + let deployer = Caller::random(); + + fevm.create_account(&alice, 0_u64); + fevm.create_account(&bob, 0_u64); + fevm.create_account(&deployer, 2000_u64); + + +// -------------------------------TOKEN SETUP------------------------------- + let token0_name = string_token("Fe Coin"); + let token0_symbol = string_token("fe"); + let token1_name = string_token("Maker"); + let token1_symbol = string_token("mkr"); + + let token0_contract = ContractBuilder::new(&fevm) + .fixture("demos/erc20_token.fe", "ERC20"); + let token0_contract = token0_contract.deploy(&deployer, &[token0_name, token0_symbol]); + + let token1_contract = ContractBuilder::new(&fevm) + .fixture("demos/erc20_token.fe", "ERC20"); + let token1_contract = token1_contract.deploy(&deployer, &[token1_name, token1_symbol]); + + let token0_address = token0_contract.address.clone().unwrap().as_token(); + let token1_address = token1_contract.address.clone().unwrap().as_token(); + token0_contract.call( + "transfer", + &[ + alice.as_token(), + uint_token_from_dec_str("500000000000000000000000"), + ], + &deployer + ); + token1_contract.call( + "transfer", + &[alice.as_token(), + uint_token_from_dec_str("500000000000000000000000")], + &deployer + ); + + let balance_alice = token1_contract.call( + "balanceOf", + &[alice.as_token()], + &alice + ).unwrap(); + + assert_eq!(balance_alice, uint_token_from_dec_str("500000000000000000000000")); + + let balance_alice = token0_contract.call( + "balanceOf", + &[alice.as_token()], + &alice + ).unwrap(); + + assert_eq!(balance_alice, uint_token_from_dec_str("500000000000000000000000")); + +// -------------------------------FACTORY SETUP------------------------------- + + let factory_contract = ContractBuilder::new(&fevm) + .fixture("demos/uniswap.fe", "UniswapV2Factory"); + let factory_contract = factory_contract.deploy(&deployer, &[address_token(H160::default())]); + let factory_address = factory_contract.address.clone().unwrap().as_token(); + + let pair_address = factory_contract.call( + "create_pair", + &[token0_address.clone(), token1_address.clone()], + &deployer + ).unwrap(); + let pair_address = pair_address.into_address().unwrap(); + let pair_contract = ContractBuilder::new(&fevm) + .address(pair_address) + .fixture( "demos/uniswap.fe", "UniswapV2Pair"); + + + let read_factory_ret = pair_contract.call("factory", &[], &deployer).unwrap(); + + assert_eq!(read_factory_ret, factory_address); + + + let token0_pair_addr = pair_contract + .call("token0", &[], &deployer) + .unwrap(); + assert!(token0_pair_addr == token0_address.clone() || token0_pair_addr == token1_address.clone()); + + let token1_pair_addr = pair_contract + .call("token1", &[], &deployer) + .unwrap(); + assert!(token1_pair_addr == token1_address.clone() || token0_pair_addr == token1_address.clone()); + + +// -------------------------------ALICE ADDS LIQUIDITY------------------------------- + let ret = token0_contract + .call("transfer", &[ + pair_address.as_token(), + uint_token_from_dec_str("200000000000000000000") + ], &alice) + .unwrap(); + assert_eq!(ret, bool_token(true)); + + let ret = token1_contract + .call("transfer", &[ + pair_address.as_token(), + uint_token_from_dec_str("100000000000000000000") + ], &alice) + .unwrap(); + assert_eq!(ret, bool_token(true)); + + //---------------------Mint alice liquidity tokens--------------------- + // Since we have sent 200 of token0 and 100 of token1, + // value of token0 is 1/2 that of token1 + let alice_liquidity = pair_contract + .call("mint", &[alice.as_token()], &bob) + .unwrap(); + + let alice_lp_tkn_balance = pair_contract + .call("balanceOf",&[alice.as_token()], &bob) + .unwrap(); + assert_eq!(alice_liquidity, alice_lp_tkn_balance); + + // ---------------------Check Min Liquidity--------------------- + + let locked_liquidity = pair_contract.call( + "balanceOf", + &[address_token_from_str("0")], + &alice + ).unwrap(); + assert_eq!(locked_liquidity, uint_token(1000)); + + // ---------------------Validate reserves--------------------- + + let reserves = pair_contract.call( + "get_reserves", + &[], + &alice + ).unwrap(); + assert_eq!(reserves, tuple_token(&[ + uint_token_from_dec_str("200000000000000000000"), + uint_token_from_dec_str("100000000000000000000"), + uint_token_from_dec_str("1"), + ])); + + +// -------------------------------BOB PERFORMS SWAP------------------------------- + + //--------------------- Give bob some token1 to swap with--------------------- + token1_contract.call( + "transfer", + &[bob.as_token(), uint_token(1000)], + &deployer, + ); + + // ---------------------Actual Swap--------------------- + // Bob performs a swap by depositing to 1000 smallest units of token 1 to + // the pair contract + // Since token1 price = 1tk1/2tk0, we should expect to receive + // roughly 2000 tk0 + token1_contract.call( + "transfer", + &[pair_address.as_token(), uint_token(1000)], + &bob + ); + + pair_contract.call( + "swap", + &[uint_token(1993), uint_token(0), bob.as_token()], + &bob + ); + + // ---------------------Validate Swap--------------------- + // Check that bob's token0 balance has increase to 1993 (accounting for 0.3% fee) + let bob_bal = token0_contract.call( + "balanceOf", + &[bob.as_token()], + &bob + ).unwrap(); + + assert_eq!(bob_bal, uint_token_from_dec_str("1993")); + + + // -------------------------------Validate Reserves------------------------------- + let reserves_post_swap = pair_contract.call( + "get_reserves", + &[], + &bob + ).unwrap(); + + assert_eq!(reserves_post_swap, + tuple_token(&[ + uint_token_from_dec_str("199999999999999998007"), + uint_token_from_dec_str("100000000000000001000"), + uint_token_from_dec_str("1"), + ]) + ); + +// -------------------------------ALICE REMOVES LIQUIDITY------------------------------- + pair_contract.call( + "transfer", + &[pair_address.as_token(), alice_liquidity], + &alice + ); + + // Alice burn liquidity she sent back + let burned = pair_contract.call( + "burn", + &[alice.as_token()], + &alice + ).unwrap(); + assert_eq!( + burned, + tuple_token(&[ + uint_token_from_dec_str("199999999999999996592"), + uint_token_from_dec_str("100000000000000000292"), + ] + ) + ); + +// -------------------------------FINAL CHECK OF TOKEN BALANCES------------------------------- + + //---------------------Validate Token 0 Balances--------------------- + + let bob_tkn0 = token0_contract.call( + "balanceOf", + &[bob.as_token()], + &deployer + ).unwrap(); + + assert_eq!(bob_tkn0, uint_token_from_dec_str("1993")); + + let alice_tkn0 = token0_contract.call( + "balanceOf", + &[alice.as_token()], + &deployer + ).unwrap(); + + assert_eq!(alice_tkn0, uint_token_from_dec_str("499999999999999999996592")); + + let pair_tkn0 = token0_contract.call( + "balanceOf", + &[pair_address.as_token()], + &deployer + ).unwrap(); + + assert_eq!(pair_tkn0, uint_token_from_dec_str("1415")); + + let deployer_tkn0 = token0_contract.call( + "balanceOf", + &[address_token(deployer.0.clone())], + &deployer + ).unwrap(); + assert_eq!(deployer_tkn0, uint_token_from_dec_str("500000000000000000000000")); + + + + //---------------------Validate Token1 Balances--------------------- + + let bob_tkn1 = token1_contract.call( + "balanceOf", + &[bob.as_token()], + &deployer + ).unwrap(); + + assert_eq!(bob_tkn1, uint_token_from_dec_str("0")); + + let alice_tkn1 = token1_contract.call( + "balanceOf", + &[alice.as_token()], + &deployer + ).unwrap(); + + assert_eq!(alice_tkn1, uint_token_from_dec_str("500000000000000000000292")); + + let pair_tkn1 = token1_contract.call( + "balanceOf", + &[pair_address.as_token()], + &deployer + ).unwrap(); + + assert_eq!(pair_tkn1, uint_token_from_dec_str("708")); + + let deployer_tkn1 = token1_contract.call( + "balanceOf", + &[address_token(deployer.0.clone())], + &deployer + ).unwrap(); + assert_eq!(deployer_tkn1, uint_token_from_dec_str("499999999999999999999000")); + +} + +pub fn criterion_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("fevm"); + group.sample_size(10); + group.bench_function("uniswap_fevm", |b| b.iter(|| uniswap_fevm())); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); \ No newline at end of file diff --git a/crates/test-utils/benches/sputnik.rs b/crates/test-utils/benches/sputnik.rs new file mode 100644 index 0000000000..b6dcc2e8fa --- /dev/null +++ b/crates/test-utils/benches/sputnik.rs @@ -0,0 +1,297 @@ +use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId}; + + +use fe_compiler_test_utils::*; + + +fn uniswap_contracts() { + with_executor(&|mut executor| { + /* SETUP */ + + // Create the actors Alice and Bob. + // Alice starts with all of the token supply (1m each). + let alice = address_token(DEFAULT_CALLER); + let bob = address_token("42"); + + // Set the names and symbols of our tokens. + let token0_name = string_token("Fe Coin"); + let token0_symbol = string_token("fe"); + let token1_name = string_token("Maker"); + let token1_symbol = string_token("mkr"); + + // Create the token0 contract. + let token0_harness = deploy_contract( + &mut executor, + "demos/erc20_token.fe", + "ERC20", + &[token0_name, token0_symbol], + ); + + // Create the token1 contract. + let mut token1_harness = deploy_contract( + &mut executor, + "demos/erc20_token.fe", + "ERC20", + &[token1_name, token1_symbol], + ); + + // Alice transfers half of her token1 tokens to Bob (500k) + token1_harness.test_function( + &mut executor, + "transfer", + &[ + bob.clone(), + uint_token_from_dec_str("500000000000000000000000"), + ], + Some(&bool_token(true)), + ); + + // Set the token addresses for convenience. + let token0_address = ethabi::Token::Address(token0_harness.address); + let token1_address = ethabi::Token::Address(token1_harness.address); + + // Deploy the Uniswap pair factory. This is used to create the pair we will + // test. + let factory_harness = deploy_contract( + &mut executor, + "demos/uniswap.fe", + "UniswapV2Factory", + &[address_token("0")], + ); + + // Set the factory address for convenience. + let factory_address = ethabi::Token::Address(factory_harness.address); + + // Create a token0/token1 pair using the factory. + let pair_address = factory_harness + .call_function( + &mut executor, + "create_pair", + &[token0_address.clone(), token1_address.clone()], + ) + .expect("factory did not return a token"); + + // Set the pair address for convenience. + let pair_harness = load_contract( + pair_address.clone().into_address().expect("not an address"), + "demos/uniswap.fe", + "UniswapV2Pair", + ); + + /* VALIDATE SETUP */ + + // Check that the factory address is set correctly + pair_harness.test_function(&mut executor, "factory", &[], Some(&factory_address)); + + // Check that the token0 address is set correctly in the pair contract + pair_harness.test_function(&mut executor, "token0", &[], Some(&token0_address)); + + // Check that the token1 address is set correctly in the pair contract + pair_harness.test_function(&mut executor, "token1", &[], Some(&token1_address)); + + /* ALICE ADDS LIQUIDITY */ + + // Alice sends 200 full token0 tokens to the pair for liquidity + token0_harness.test_function( + &mut executor, + "transfer", + &[ + pair_address.clone(), + uint_token_from_dec_str("200000000000000000000"), + ], + Some(&bool_token(true)), + ); + + // Alice sends 100 full token1 tokens to the pair for liquidity + token1_harness.test_function( + &mut executor, + "transfer", + &[ + pair_address.clone(), + uint_token_from_dec_str("100000000000000000000"), + ], + Some(&bool_token(true)), + ); + + // Now that Alice has sent tokens to the pair contract, we need to mint her + // liquidity tokens. + // + // Since we have sent 200 of token0 and 100 of token1, the value of token0 is + // equal to 1/2 that of token1. + let alices_liquidity = pair_harness + .call_function(&mut executor, "mint", &[alice.clone()]) + .expect("no return from mint"); + + /* VALIDATE LIQUIDITY */ + + // Validate that Alice's liquidity token balance is equal to what was returned + // by `mint`. + // + // A portion of the tokens she has added is locked forever to maintain + // `MINIMUM_LIQUIDITY`, as we will see in the next test. + pair_harness.test_function( + &mut executor, + "balanceOf", + &[alice.clone()], + Some(&alices_liquidity), + ); + + // Check that `MINIMUM_LIQUIDITY` is locked at address(0). + pair_harness.test_function( + &mut executor, + "balanceOf", + &[address_token("0")], + Some(&uint_token(1000)), + ); + + // Validate reserves. + pair_harness.test_function( + &mut executor, + "get_reserves", + &[], + Some(&tuple_token(&[ + uint_token_from_dec_str("200000000000000000000"), + uint_token_from_dec_str("100000000000000000000"), + uint_token_from_dec_str("0"), + ])), + ); + + /* BOB PERFORMS A SWAP */ + + // Set Bob as the token1 caller, this is so Bob can perform a swap. + token1_harness.set_caller(bob.clone().into_address().unwrap()); + + // Bob sends 1000 smallest units of token1 to the pair for swapping. + // token1 is twice as valuable as token0, so we should expect to receive roughly + // 2000 smallest units of token1 in return. + token1_harness.test_function( + &mut executor, + "transfer", + &[pair_address.clone(), uint_token(1000)], + Some(&bool_token(true)), + ); + + // Bob wishes to take 1993 units of token 0 from the pool. The amount received + // is (2000 - 7). This is accounted for by the .3% swap fee. + pair_harness.test_function( + &mut executor, + "swap", + &[uint_token(1993), uint_token(0), bob.clone()], + None, + ); + + /* VALIDATE SWAP */ + + // Check that Bob's token0 balance has increased from 0 to 1993 smallest units. + token0_harness.test_function( + &mut executor, + "balanceOf", + &[bob.clone()], + Some(&uint_token_from_dec_str("1993")), + ); + + // Validate reserves. + pair_harness.test_function( + &mut executor, + "get_reserves", + &[], + Some(&tuple_token(&[ + uint_token_from_dec_str("199999999999999998007"), + uint_token_from_dec_str("100000000000000001000"), + uint_token_from_dec_str("0"), + ])), + ); + + /* ALICE REMOVES LIQUIDITY */ + + // Alice sends liquidity back to pair contract. + pair_harness.test_function( + &mut executor, + "transfer", + &[pair_address.clone(), alices_liquidity], + Some(&bool_token(true)), + ); + + // Alice burns the liquidity that she has sent back. + pair_harness.test_function( + &mut executor, + "burn", + &[alice.clone()], + Some(&tuple_token(&[ + uint_token_from_dec_str("199999999999999996592"), + uint_token_from_dec_str("100000000000000000292"), + ])), + ); + + /* VALIDATE LIQUIDITY REMOVAL */ + + // Validate reserves. + pair_harness.test_function( + &mut executor, + "get_reserves", + &[], + Some(&tuple_token(&[ + uint_token_from_dec_str("1415"), + uint_token_from_dec_str("708"), + uint_token_from_dec_str("0"), + ])), + ); + + /* SANITY CHECK TOKEN BALANCES */ + + // Validate that all of the token0 tokens are held between the pair contract and + // actors. + // + // 1993 + 999999999999999999996592 + 1415 = 1e24 + token0_harness.test_function( + &mut executor, + "balanceOf", + &[bob.clone()], + Some(&uint_token_from_dec_str("1993")), + ); + token0_harness.test_function( + &mut executor, + "balanceOf", + &[alice.clone()], + Some(&uint_token_from_dec_str("999999999999999999996592")), + ); + token0_harness.test_function( + &mut executor, + "balanceOf", + &[pair_address.clone()], + Some(&uint_token_from_dec_str("1415")), + ); + + // Validate that all of the token1 tokens are held between the pair contract and + // actors. + // + // 499999999999999999999000 + 500000000000000000000292 + 708 = 1e24 + token1_harness.test_function( + &mut executor, + "balanceOf", + &[bob], + Some(&uint_token_from_dec_str("499999999999999999999000")), + ); + token1_harness.test_function( + &mut executor, + "balanceOf", + &[alice], + Some(&uint_token_from_dec_str("500000000000000000000292")), + ); + token1_harness.test_function( + &mut executor, + "balanceOf", + &[pair_address], + Some(&uint_token_from_dec_str("708")), + ); + }); +} + + + +pub fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("uniswap_sputnik", |b| b.iter(|| uniswap_contracts())); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); \ No newline at end of file diff --git a/crates/test-utils/src/lib.rs b/crates/test-utils/src/lib.rs index fe10519b71..0dbc455d54 100644 --- a/crates/test-utils/src/lib.rs +++ b/crates/test-utils/src/lib.rs @@ -4,11 +4,11 @@ use fe_common::files::FileStore; use fe_common::utils::keccak; use fe_driver as driver; use fe_yulgen::runtime::functions; -use primitive_types::{H160, U256}; +pub use primitive_types_old::{self as primitive_types, H160, U256}; use std::collections::BTreeMap; use std::str::FromStr; use yultsur::*; - +pub use ethabi_old as ethabi; pub trait ToBeBytes { fn to_be_bytes(&self) -> [u8; 32]; } diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml index e7d9e1f33f..c02d6fb0fa 100644 --- a/crates/tests/Cargo.toml +++ b/crates/tests/Cargo.toml @@ -20,6 +20,7 @@ fe-parser = {path = "../parser", version = "^0.13.0-alpha"} fe-yulgen = {path = "../yulgen", version = "^0.13.0-alpha"} fe-yulc = {path = "../yulc", version = "^0.13.0-alpha"} fe-driver = {path = "../driver", version = "^0.13.0-alpha"} +fevm = {path = "../fevm"} test-files = {path = "../test-files", package = "fe-test-files" } hex = "0.4" primitive-types = {version = "0.9", default-features = false, features = ["rlp"]} @@ -30,9 +31,9 @@ yultsur = {git = "https://github.com/g-r-a-n-t/yultsur", rev = "ae85470"} insta = "1.7.1" pretty_assertions = "1.0.0" wasm-bindgen-test = "0.3.24" - +once_cell = "1.9.0" [features] -solc-backend = ["fe-yulc/solc-backend", "fe-compiler-test-utils/solc-backend"] +solc-backend = ["fe-yulc/solc-backend", "fe-compiler-test-utils/solc-backend", "fevm/solc-backend"] [dev-dependencies.proptest] version = "1.0.0" @@ -41,3 +42,4 @@ version = "1.0.0" default-features = false # Enable using the `std` crate. features = ["std"] + diff --git a/crates/tests/src/demo_guestbook.rs b/crates/tests/src/demo_guestbook.rs index 3083fe70c8..8ab0083c1f 100644 --- a/crates/tests/src/demo_guestbook.rs +++ b/crates/tests/src/demo_guestbook.rs @@ -1,21 +1,32 @@ #![cfg(feature = "solc-backend")] -use fe_compiler_test_utils::*; + +use fevm::{Fevm, ContractBuilder, Contract, Caller, Address, U256, conversion::*, AsToken, H160}; + #[test] fn guest_book() { - with_executor(&|mut executor| { - let mut harness = deploy_contract(&mut executor, "demos/guest_book.fe", "GuestBook", &[]); + let mut fevm = Fevm::new(); + + let alice = Caller::random(); + let sender = Caller::random(); + fevm.create_account(&alice, 0_u64); + + fevm.create_account(&sender, 1000_u64); - let sender = address_token("1234000000000000000000000000000000005678"); - let msg = string_token("hello world"); + let guestbook_contract = ContractBuilder::new(&fevm) + .fixture("demos/guest_book.fe", "GuestBook"); + let guestbook_contract = guestbook_contract.deploy(&alice, &[]); + let msg = string_token("hello world"); - harness.caller = sender.clone().into_address().unwrap(); + let sign_result = guestbook_contract.call("sign", &[msg.clone()], &sender); + assert_eq!(sign_result, None); - harness.test_function(&mut executor, "sign", &[msg.clone()], None); + let get_msg_result = guestbook_contract.call("get_msg", &[sender.as_token()], &sender).unwrap(); + assert_eq!(get_msg_result, msg); - harness.test_function(&mut executor, "get_msg", &[sender], Some(&msg)); - harness.events_emitted(executor, &[("Signed", &[msg])]); - }) + // TO DO: Grab events + // harness.events_emitted(executor, &[("Signed", &[msg])]); + } diff --git a/crates/tests/src/demo_uniswap.rs b/crates/tests/src/demo_uniswap.rs index 01e3166d1b..2776cb5c4e 100644 --- a/crates/tests/src/demo_uniswap.rs +++ b/crates/tests/src/demo_uniswap.rs @@ -1,287 +1,296 @@ #![cfg(feature = "solc-backend")] -use fe_compiler_test_utils::*; +use fevm::{Fevm, ContractBuilder, Contract, Caller, Address, U256, conversion::*, AsToken, H160}; #[test] fn uniswap_contracts() { - with_executor(&|mut executor| { - /* SETUP */ - - // Create the actors Alice and Bob. - // Alice starts with all of the token supply (1m each). - let alice = address_token(DEFAULT_CALLER); - let bob = address_token("42"); - - // Set the names and symbols of our tokens. - let token0_name = string_token("Fe Coin"); - let token0_symbol = string_token("fe"); - let token1_name = string_token("Maker"); - let token1_symbol = string_token("mkr"); - - // Create the token0 contract. - let token0_harness = deploy_contract( - &mut executor, - "demos/erc20_token.fe", - "ERC20", - &[token0_name, token0_symbol], - ); - - // Create the token1 contract. - let mut token1_harness = deploy_contract( - &mut executor, - "demos/erc20_token.fe", - "ERC20", - &[token1_name, token1_symbol], - ); - - // Alice transfers half of her token1 tokens to Bob (500k) - token1_harness.test_function( - &mut executor, - "transfer", - &[ - bob.clone(), - uint_token_from_dec_str("500000000000000000000000"), - ], - Some(&bool_token(true)), - ); - - // Set the token addresses for convenience. - let token0_address = ethabi::Token::Address(token0_harness.address); - let token1_address = ethabi::Token::Address(token1_harness.address); - - // Deploy the Uniswap pair factory. This is used to create the pair we will - // test. - let factory_harness = deploy_contract( - &mut executor, - "demos/uniswap.fe", - "UniswapV2Factory", - &[address_token("0")], - ); - - // Set the factory address for convenience. - let factory_address = ethabi::Token::Address(factory_harness.address); - - // Create a token0/token1 pair using the factory. - let pair_address = factory_harness - .call_function( - &mut executor, - "create_pair", - &[token0_address.clone(), token1_address.clone()], - ) - .expect("factory did not return a token"); - - // Set the pair address for convenience. - let pair_harness = load_contract( - pair_address.clone().into_address().expect("not an address"), - "demos/uniswap.fe", - "UniswapV2Pair", - ); - - /* VALIDATE SETUP */ - - // Check that the factory address is set correctly - pair_harness.test_function(&mut executor, "factory", &[], Some(&factory_address)); - - // Check that the token0 address is set correctly in the pair contract - pair_harness.test_function(&mut executor, "token0", &[], Some(&token0_address)); - - // Check that the token1 address is set correctly in the pair contract - pair_harness.test_function(&mut executor, "token1", &[], Some(&token1_address)); - - /* ALICE ADDS LIQUIDITY */ - - // Alice sends 200 full token0 tokens to the pair for liquidity - token0_harness.test_function( - &mut executor, - "transfer", - &[ - pair_address.clone(), - uint_token_from_dec_str("200000000000000000000"), - ], - Some(&bool_token(true)), - ); - - // Alice sends 100 full token1 tokens to the pair for liquidity - token1_harness.test_function( - &mut executor, - "transfer", - &[ - pair_address.clone(), - uint_token_from_dec_str("100000000000000000000"), - ], - Some(&bool_token(true)), - ); - - // Now that Alice has sent tokens to the pair contract, we need to mint her - // liquidity tokens. - // - // Since we have sent 200 of token0 and 100 of token1, the value of token0 is - // equal to 1/2 that of token1. - let alices_liquidity = pair_harness - .call_function(&mut executor, "mint", &[alice.clone()]) - .expect("no return from mint"); - - /* VALIDATE LIQUIDITY */ - - // Validate that Alice's liquidity token balance is equal to what was returned - // by `mint`. - // - // A portion of the tokens she has added is locked forever to maintain - // `MINIMUM_LIQUIDITY`, as we will see in the next test. - pair_harness.test_function( - &mut executor, - "balanceOf", - &[alice.clone()], - Some(&alices_liquidity), - ); - - // Check that `MINIMUM_LIQUIDITY` is locked at address(0). - pair_harness.test_function( - &mut executor, - "balanceOf", - &[address_token("0")], - Some(&uint_token(1000)), - ); - - // Validate reserves. - pair_harness.test_function( - &mut executor, - "get_reserves", - &[], - Some(&tuple_token(&[ - uint_token_from_dec_str("200000000000000000000"), - uint_token_from_dec_str("100000000000000000000"), - uint_token_from_dec_str("0"), - ])), - ); - - /* BOB PERFORMS A SWAP */ - - // Set Bob as the token1 caller, this is so Bob can perform a swap. - token1_harness.set_caller(bob.clone().into_address().unwrap()); - - // Bob sends 1000 smallest units of token1 to the pair for swapping. - // token1 is twice as valuable as token0, so we should expect to receive roughly - // 2000 smallest units of token1 in return. - token1_harness.test_function( - &mut executor, - "transfer", - &[pair_address.clone(), uint_token(1000)], - Some(&bool_token(true)), - ); - - // Bob wishes to take 1993 units of token 0 from the pool. The amount received - // is (2000 - 7). This is accounted for by the .3% swap fee. - pair_harness.test_function( - &mut executor, - "swap", - &[uint_token(1993), uint_token(0), bob.clone()], - None, - ); - - /* VALIDATE SWAP */ - - // Check that Bob's token0 balance has increased from 0 to 1993 smallest units. - token0_harness.test_function( - &mut executor, - "balanceOf", - &[bob.clone()], - Some(&uint_token_from_dec_str("1993")), - ); - - // Validate reserves. - pair_harness.test_function( - &mut executor, - "get_reserves", - &[], - Some(&tuple_token(&[ - uint_token_from_dec_str("199999999999999998007"), - uint_token_from_dec_str("100000000000000001000"), - uint_token_from_dec_str("0"), - ])), - ); - - /* ALICE REMOVES LIQUIDITY */ - - // Alice sends liquidity back to pair contract. - pair_harness.test_function( - &mut executor, - "transfer", - &[pair_address.clone(), alices_liquidity], - Some(&bool_token(true)), - ); - - // Alice burns the liquidity that she has sent back. - pair_harness.test_function( - &mut executor, - "burn", - &[alice.clone()], - Some(&tuple_token(&[ - uint_token_from_dec_str("199999999999999996592"), - uint_token_from_dec_str("100000000000000000292"), - ])), - ); - - /* VALIDATE LIQUIDITY REMOVAL */ - - // Validate reserves. - pair_harness.test_function( - &mut executor, - "get_reserves", - &[], - Some(&tuple_token(&[ - uint_token_from_dec_str("1415"), - uint_token_from_dec_str("708"), - uint_token_from_dec_str("0"), - ])), - ); - - /* SANITY CHECK TOKEN BALANCES */ - - // Validate that all of the token0 tokens are held between the pair contract and - // actors. - // - // 1993 + 999999999999999999996592 + 1415 = 1e24 - token0_harness.test_function( - &mut executor, - "balanceOf", - &[bob.clone()], - Some(&uint_token_from_dec_str("1993")), - ); - token0_harness.test_function( - &mut executor, - "balanceOf", - &[alice.clone()], - Some(&uint_token_from_dec_str("999999999999999999996592")), - ); - token0_harness.test_function( - &mut executor, - "balanceOf", - &[pair_address.clone()], - Some(&uint_token_from_dec_str("1415")), - ); - - // Validate that all of the token1 tokens are held between the pair contract and - // actors. - // - // 499999999999999999999000 + 500000000000000000000292 + 708 = 1e24 - token1_harness.test_function( - &mut executor, - "balanceOf", - &[bob], - Some(&uint_token_from_dec_str("499999999999999999999000")), - ); - token1_harness.test_function( - &mut executor, - "balanceOf", - &[alice], - Some(&uint_token_from_dec_str("500000000000000000000292")), - ); - token1_harness.test_function( - &mut executor, - "balanceOf", - &[pair_address], - Some(&uint_token_from_dec_str("708")), - ); - }); -} +// -------------------------------ENVIRONMENT SETUP------------------------------- + let mut fevm = Fevm::new(); + + let alice = Caller::random(); + let bob = Caller::random(); + let deployer = Caller::random(); + + fevm.create_account(&alice, 0_u64); + fevm.create_account(&bob, 0_u64); + fevm.create_account(&deployer, 2000_u64); + + +// -------------------------------TOKEN SETUP------------------------------- + let token0_name = string_token("Fe Coin"); + let token0_symbol = string_token("fe"); + let token1_name = string_token("Maker"); + let token1_symbol = string_token("mkr"); + + let token0_contract = ContractBuilder::new(&fevm) + .fixture("demos/erc20_token.fe", "ERC20"); + let token0_contract = token0_contract.deploy(&deployer, &[token0_name, token0_symbol]); + + let token1_contract = ContractBuilder::new(&fevm) + .fixture("demos/erc20_token.fe", "ERC20"); + let token1_contract = token1_contract.deploy(&deployer, &[token1_name, token1_symbol]); + + let token0_address = token0_contract.address.clone().unwrap().as_token(); + let token1_address = token1_contract.address.clone().unwrap().as_token(); + token0_contract.call( + "transfer", + &[ + alice.as_token(), + uint_token_from_dec_str("500000000000000000000000"), + ], + &deployer + ); + token1_contract.call( + "transfer", + &[alice.as_token(), + uint_token_from_dec_str("500000000000000000000000")], + &deployer + ); + + let balance_alice = token1_contract.call( + "balanceOf", + &[alice.as_token()], + &alice + ).unwrap(); + + assert_eq!(balance_alice, uint_token_from_dec_str("500000000000000000000000")); + + let balance_alice = token0_contract.call( + "balanceOf", + &[alice.as_token()], + &alice + ).unwrap(); + + assert_eq!(balance_alice, uint_token_from_dec_str("500000000000000000000000")); + +// -------------------------------FACTORY SETUP------------------------------- + + let factory_contract = ContractBuilder::new(&fevm) + .fixture("demos/uniswap.fe", "UniswapV2Factory"); + let factory_contract = factory_contract.deploy(&deployer, &[address_token(H160::default())]); + let factory_address = factory_contract.address.clone().unwrap().as_token(); + + let pair_address = factory_contract.call( + "create_pair", + &[token0_address.clone(), token1_address.clone()], + &deployer + ).unwrap(); + let pair_address = pair_address.into_address().unwrap(); + let pair_contract = ContractBuilder::new(&fevm) + .address(pair_address) + .fixture( "demos/uniswap.fe", "UniswapV2Pair"); + + + let read_factory_ret = pair_contract.call("factory", &[], &deployer).unwrap(); + + assert_eq!(read_factory_ret, factory_address); + + + let token0_pair_addr = pair_contract + .call("token0", &[], &deployer) + .unwrap(); + assert!(token0_pair_addr == token0_address.clone() || token0_pair_addr == token1_address.clone()); + + let token1_pair_addr = pair_contract + .call("token1", &[], &deployer) + .unwrap(); + assert!(token1_pair_addr == token1_address.clone() || token0_pair_addr == token1_address.clone()); + + +// -------------------------------ALICE ADDS LIQUIDITY------------------------------- + let ret = token0_contract + .call("transfer", &[ + pair_address.as_token(), + uint_token_from_dec_str("200000000000000000000") + ], &alice) + .unwrap(); + assert_eq!(ret, bool_token(true)); + + let ret = token1_contract + .call("transfer", &[ + pair_address.as_token(), + uint_token_from_dec_str("100000000000000000000") + ], &alice) + .unwrap(); + assert_eq!(ret, bool_token(true)); + + //---------------------Mint alice liquidity tokens--------------------- + // Since we have sent 200 of token0 and 100 of token1, + // value of token0 is 1/2 that of token1 + let alice_liquidity = pair_contract + .call("mint", &[alice.as_token()], &bob) + .unwrap(); + + let alice_lp_tkn_balance = pair_contract + .call("balanceOf",&[alice.as_token()], &bob) + .unwrap(); + assert_eq!(alice_liquidity, alice_lp_tkn_balance); + + // ---------------------Check Min Liquidity--------------------- + + let locked_liquidity = pair_contract.call( + "balanceOf", + &[address_token_from_str("0")], + &alice + ).unwrap(); + assert_eq!(locked_liquidity, uint_token(1000)); + + // ---------------------Validate reserves--------------------- + + let reserves = pair_contract.call( + "get_reserves", + &[], + &alice + ).unwrap(); + assert_eq!(reserves, tuple_token(&[ + uint_token_from_dec_str("200000000000000000000"), + uint_token_from_dec_str("100000000000000000000"), + uint_token_from_dec_str("1"), + ])); + + +// -------------------------------BOB PERFORMS SWAP------------------------------- + + //--------------------- Give bob some token1 to swap with--------------------- + token1_contract.call( + "transfer", + &[bob.as_token(), uint_token(1000)], + &deployer, + ); + + // ---------------------Actual Swap--------------------- + // Bob performs a swap by depositing to 1000 smallest units of token 1 to + // the pair contract + // Since token1 price = 1tk1/2tk0, we should expect to receive + // roughly 2000 tk0 + token1_contract.call( + "transfer", + &[pair_address.as_token(), uint_token(1000)], + &bob + ); + + pair_contract.call( + "swap", + &[uint_token(1993), uint_token(0), bob.as_token()], + &bob + ); + + // ---------------------Validate Swap--------------------- + // Check that bob's token0 balance has increase to 1993 (accounting for 0.3% fee) + let bob_bal = token0_contract.call( + "balanceOf", + &[bob.as_token()], + &bob + ).unwrap(); + + assert_eq!(bob_bal, uint_token_from_dec_str("1993")); + + + // -------------------------------Validate Reserves------------------------------- + let reserves_post_swap = pair_contract.call( + "get_reserves", + &[], + &bob + ).unwrap(); + + assert_eq!(reserves_post_swap, + tuple_token(&[ + uint_token_from_dec_str("199999999999999998007"), + uint_token_from_dec_str("100000000000000001000"), + uint_token_from_dec_str("1"), + ]) + ); + +// -------------------------------ALICE REMOVES LIQUIDITY------------------------------- + pair_contract.call( + "transfer", + &[pair_address.as_token(), alice_liquidity], + &alice + ); + + // Alice burn liquidity she sent back + let burned = pair_contract.call( + "burn", + &[alice.as_token()], + &alice + ).unwrap(); + assert_eq!( + burned, + tuple_token(&[ + uint_token_from_dec_str("199999999999999996592"), + uint_token_from_dec_str("100000000000000000292"), + ] + ) + ); + +// -------------------------------FINAL CHECK OF TOKEN BALANCES------------------------------- + + //---------------------Validate Token 0 Balances--------------------- + + let bob_tkn0 = token0_contract.call( + "balanceOf", + &[bob.as_token()], + &deployer + ).unwrap(); + + assert_eq!(bob_tkn0, uint_token_from_dec_str("1993")); + + let alice_tkn0 = token0_contract.call( + "balanceOf", + &[alice.as_token()], + &deployer + ).unwrap(); + + assert_eq!(alice_tkn0, uint_token_from_dec_str("499999999999999999996592")); + + let pair_tkn0 = token0_contract.call( + "balanceOf", + &[pair_address.as_token()], + &deployer + ).unwrap(); + + assert_eq!(pair_tkn0, uint_token_from_dec_str("1415")); + + let deployer_tkn0 = token0_contract.call( + "balanceOf", + &[address_token(deployer.0.clone())], + &deployer + ).unwrap(); + assert_eq!(deployer_tkn0, uint_token_from_dec_str("500000000000000000000000")); + + + + //---------------------Validate Token1 Balances--------------------- + + let bob_tkn1 = token1_contract.call( + "balanceOf", + &[bob.as_token()], + &deployer + ).unwrap(); + + assert_eq!(bob_tkn1, uint_token_from_dec_str("0")); + + let alice_tkn1 = token1_contract.call( + "balanceOf", + &[alice.as_token()], + &deployer + ).unwrap(); + + assert_eq!(alice_tkn1, uint_token_from_dec_str("500000000000000000000292")); + + let pair_tkn1 = token1_contract.call( + "balanceOf", + &[pair_address.as_token()], + &deployer + ).unwrap(); + + assert_eq!(pair_tkn1, uint_token_from_dec_str("708")); + + let deployer_tkn1 = token1_contract.call( + "balanceOf", + &[address_token(deployer.0.clone())], + &deployer + ).unwrap(); + assert_eq!(deployer_tkn1, uint_token_from_dec_str("499999999999999999999000")); + +} \ No newline at end of file diff --git a/crates/tests/src/differential.rs b/crates/tests/src/differential.rs index 5e5c5f739b..ff5a868df4 100644 --- a/crates/tests/src/differential.rs +++ b/crates/tests/src/differential.rs @@ -2,71 +2,151 @@ #![cfg(feature = "solc-backend")] use proptest::prelude::*; -use fe_compiler_test_utils::*; -use fe_compiler_test_utils::{self as test_utils}; - -struct DualHarness { - fe_harness: ContractHarness, - solidity_harness: ContractHarness, +// use fe_compiler_test_utils::*; +// use fe_compiler_test_utils::{self as test_utils}; +use fevm::{Caller, Contract, CallResult, Return, Fevm, ethabi, revm::TransactOut, conversion::*}; +use crate::{DIFF_CONTRACTS, DIFF_VM}; +// struct DualHarness { +// fe_harness: ContractHarness, +// solidity_harness: ContractHarness, +// } + +struct Harness<'a> { + pub fe: Contract<'a>, + pub sol: Contract<'a> } +impl<'a, 'b: 'a> Harness<'b> { + pub fn capture_call( + &self, + name: &'a str, + input: &'a [ethabi::Token], + caller: &Caller, + ) -> CaptureResult<'a> { + let fe_result = self.fe.capture_call(name, input, caller); + + let sol_result = self.sol.capture_call(name, input, caller); + + + CaptureResult::<'a> { + fe_result, + sol_result, + name, + input, + } + } +} struct CaptureResult<'a> { - fe_capture: evm::Capture<(evm::ExitReason, Vec), std::convert::Infallible>, - fe_used_gas: u64, - solidity_capture: evm::Capture<(evm::ExitReason, Vec), std::convert::Infallible>, - solidity_used_gas: u64, + fe_result: CallResult, + sol_result: CallResult, name: &'a str, input: &'a [ethabi::Token], } impl<'a> CaptureResult<'a> { + + pub fn fe_used_gas(&self) -> u64 { + self.fe_result.2 + } + + pub fn solidity_used_gas(&self) -> u64 { + self.sol_result.2 + } + + + pub fn ret_types_match(&self) -> bool { + self.fe_result.0 == self.sol_result.0 + } + + pub fn ret_data_match(&self) -> bool { + match &self.fe_result.1 { + TransactOut::None => { + if let TransactOut::None = &self.sol_result.1 { + return true; + } + return false; + }, + TransactOut::Call(data) => { + if let TransactOut::Call(sol_data) = &self.sol_result.1 { + return data == sol_data; + } + return false; + + }, + _ => { + return false; + } + } + } pub fn assert_fe_max_percentage_more_gas(&self, max_percentage: i64) -> &Self { - let fe_percentage: i64 = (self.fe_used_gas as i64 - self.solidity_used_gas as i64) * 100 - / self.solidity_used_gas as i64; + let fe_percentage: i64 = (self.fe_used_gas() as i64 - self.solidity_used_gas() as i64) * 100 + / self.solidity_used_gas() as i64; - assert!(fe_percentage <= max_percentage, "Fe used gas: {}, Solidity used gas: {}, Fe used {}% more gas. Called {} with input: {:?}", self.fe_used_gas, self.solidity_used_gas, fe_percentage, self.name, self.input); + assert!(fe_percentage <= max_percentage, "Fe used gas: {}, Solidity used gas: {}, Fe used {}% more gas. Called {} with input: {:?}", self.fe_used_gas(), self.solidity_used_gas(), fe_percentage, self.name, self.input); + self + } + pub fn assert_gas_equal(&self) -> &Self { + assert_eq!(&self.fe_result.2, &self.sol_result.2); self } pub fn assert_perfomed_equal(&self) -> &Self { - assert_eq!( - self.fe_capture, self.solidity_capture, - "Called {} with input: {:?}", - self.name, self.input - ); - self + self.assert_return_data_equal().assert_both_fail_or_success() } pub fn assert_return_data_equal(&self) -> &Self { - if let (evm::Capture::Exit((_, fe_data)), evm::Capture::Exit((_, sol_data))) = - (&self.fe_capture, &self.solidity_capture) - { - assert_eq!( - fe_data, sol_data, - "Called {} with input: {:?}", - self.name, self.input - ) - } + assert!(self.ret_data_match()); self } - #[allow(dead_code)] - pub fn assert_reverted(&self) -> &Self { - if !matches!( - (self.fe_capture.clone(), self.solidity_capture.clone()), - ( - evm::Capture::Exit((evm::ExitReason::Revert(_), _)), - evm::Capture::Exit((evm::ExitReason::Revert(_), _)) - ) - ) { - panic!( - "Asserted both revert but was: Fe: {:?} Solidity: {:?}", - self.fe_capture, self.solidity_capture - ) + pub fn fe_success(&self) -> bool { + match &self.fe_result.0 { + Return::Continue | + Return::Stop | + Return::Return | + Return::SelfDestruct => { + true + }, + _ => { + false + } } - self } + pub fn sol_success(&self) -> bool { + match &self.sol_result.0 { + Return::Continue | + Return::Stop | + Return::Return | + Return::SelfDestruct => { + true + }, + _ => { + false + } + } + } + + pub fn both_succeeded(&self) -> bool { + let is_fe_success = self.fe_success(); + + let is_sol_success = self.sol_success(); + + return is_sol_success && is_fe_success; + } + + pub fn both_reverted(&self) -> bool { + let is_fe_success = self.fe_success(); + + let is_sol_success = self.sol_success(); + + return (!is_sol_success && !is_fe_success) + } + + pub fn assert_both_fail_or_success(&self) -> &Self { + assert!(self.both_reverted() || self.both_succeeded()); + self + } pub fn assert_any_success_with_equal_return_data(&self) -> &Self { self.assert_any_success().assert_return_data_equal(); self @@ -76,7 +156,7 @@ impl<'a> CaptureResult<'a> { if !(self.both_succeeded() || self.both_reverted()) { panic!( "Asserted both succeeded or reverted but was: Fe: {:?} Solidity: {:?}", - self.fe_capture, self.solidity_capture + self.fe_result, self.sol_result ) } else { self.assert_return_data_equal() @@ -84,179 +164,128 @@ impl<'a> CaptureResult<'a> { } pub fn assert_any_success(&self) -> &Self { - if !matches!( - (self.fe_capture.clone(), self.solidity_capture.clone()), - ( - evm::Capture::Exit((evm::ExitReason::Succeed(_), _)), - evm::Capture::Exit((evm::ExitReason::Succeed(_), _)) - ) - ) { + if !(self.sol_success() || self.fe_success()) { panic!( "Asserted both succeeded but was: Fe: {:?} Solidity: {:?}", - self.fe_capture, self.solidity_capture + self.fe_result, self.sol_result ) } self } - - pub fn both_succeeded(&self) -> bool { - matches!( - (self.fe_capture.clone(), self.solidity_capture.clone()), - ( - evm::Capture::Exit((evm::ExitReason::Succeed(_), _)), - evm::Capture::Exit((evm::ExitReason::Succeed(_), _)) - ) - ) - } - - pub fn both_reverted(&self) -> bool { - matches!( - (self.fe_capture.clone(), self.solidity_capture.clone()), - ( - evm::Capture::Exit((evm::ExitReason::Revert(_), _)), - evm::Capture::Exit((evm::ExitReason::Revert(_), _)) - ) - ) - } - - #[allow(dead_code)] - pub fn performed_equal(&self) -> bool { - self.fe_capture == self.solidity_capture - } } -impl<'a> DualHarness { - pub fn from_fixture( - executor: &mut Executor, - fixture: &str, - contract_name: &str, - init_params: &[ethabi::Token], - ) -> DualHarness { - let fe_harness = test_utils::deploy_contract( - executor, - &format!("differential/{}.fe", fixture), - contract_name, - init_params, - ); - let solidity_harness = test_utils::deploy_solidity_contract( - executor, - &format!("differential/{}.sol", fixture), - contract_name, - init_params, - true, - ); - DualHarness { - fe_harness, - solidity_harness, - } - } - - pub fn capture_call( - &self, - executor: &mut Executor, - name: &'a str, - input: &'a [ethabi::Token], - ) -> CaptureResult<'a> { - let initially_used = executor.used_gas(); - let fe_capture = self.fe_harness.capture_call(executor, name, input); - let fe_used_gas = executor.used_gas() - initially_used; - let solidity_capture = self.solidity_harness.capture_call(executor, name, input); - let solidity_used_gas = executor.used_gas() - fe_used_gas - initially_used; - - CaptureResult { - fe_capture, - fe_used_gas, - solidity_capture, - solidity_used_gas, - name, - input, - } - } -} proptest! { #[test] - #[ignore] fn math_u8(val in 0u8..=255, val2 in 0u8..=255) { - with_executor(&|mut executor| { - - let harness = DualHarness::from_fixture(&mut executor, "math_u8", "Foo", &[]); - - harness.capture_call(&mut executor, "add", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(5); - harness.capture_call(&mut executor, "subtract", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(5); - harness.capture_call(&mut executor, "divide", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(100); - harness.capture_call(&mut executor, "multiply", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(5); - harness.capture_call(&mut executor, "pow", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(15); - harness.capture_call(&mut executor, "modulo", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(25); - harness.capture_call(&mut executor, "leftshift", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(25); - harness.capture_call(&mut executor, "rightshift", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(25); - harness.capture_call(&mut executor, "order_of_operation", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(50); - harness.capture_call(&mut executor, "invert", &[uint_token(val.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(60); - harness.capture_call(&mut executor, "bit_and", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(15); - harness.capture_call(&mut executor, "bit_or", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(50); - harness.capture_call(&mut executor, "bit_xor", &[uint_token(val.into()), uint_token(val2.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(30); - harness.capture_call(&mut executor, "cast1", &[uint_token(val.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(50); - harness.capture_call(&mut executor, "cast2", &[uint_token(val.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(60); - harness.capture_call(&mut executor, "cast3", &[uint_token(val.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(70); - harness.capture_call(&mut executor, "sqrt", &[uint_token(val.into())]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(120); - }); + + let alice = Caller::random(); + let fevm = &DIFF_VM; + fevm.create_account(&alice, 2000_u64); + let fe_contract = DIFF_CONTRACTS[1].0.clone(); + let fe_contract = fe_contract.deploy(&alice, &[]); + let sol_contract = DIFF_CONTRACTS[1].1.clone(); + let sol_contract = sol_contract.deploy(&alice, &[]); + let harness = Harness { + fe: fe_contract, + sol: sol_contract, + }; + + harness.capture_call("add", &[uint_token(val.into()), uint_token(val2.into())], &alice) + .assert_return_data_equal() + .assert_fe_max_percentage_more_gas(5); + + + harness.capture_call("add", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(5); + harness.capture_call("subtract", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(5); + harness.capture_call("divide", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(100); + harness.capture_call("multiply", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(5); + harness.capture_call("pow", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(15); + harness.capture_call("modulo", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(25); + harness.capture_call("leftshift", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(25); + harness.capture_call("rightshift", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(25); + harness.capture_call("order_of_operation", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(50); + harness.capture_call("invert", &[uint_token(val.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(60); + harness.capture_call( "bit_and", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(15); + harness.capture_call( "bit_or", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(50); + harness.capture_call( "bit_xor", &[uint_token(val.into()), uint_token(val2.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(30); + harness.capture_call( "cast1", &[uint_token(val.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(50); + harness.capture_call( "cast2", &[uint_token(val.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(60); + harness.capture_call( "cast3", &[uint_token(val.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(70); + harness.capture_call( "sqrt", &[uint_token(val.into())], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(120); } #[test] - #[ignore] fn math_i8(val in -128i8..=127i8, val2 in -128i8..=127i8, val3 in 0u8..=255) { - with_executor(&|mut executor| { - let harness = DualHarness::from_fixture(&mut executor, "math_i8", "Foo", &[]); - - harness.capture_call(&mut executor, "add", &[int_token(val.into()), int_token(val2.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "subtract", &[int_token(val.into()), int_token(val2.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "divide", &[int_token(val.into()), int_token(val2.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "multiply", &[int_token(val.into()), int_token(val2.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "modulo", &[int_token(val.into()), int_token(val2.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "leftshift", &[int_token(val.into()), uint_token(val3.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "rightshift", &[int_token(val.into()), uint_token(val3.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "order_of_operation", &[int_token(val.into()), int_token(val2.into()), uint_token(val3.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "invert", &[int_token(val.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "cast1", &[int_token(val.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "cast2", &[int_token(val.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "cast3", &[int_token(val.into())]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "negate", &[int_token(val.into())]).assert_perfomed_equal(); - }); + let alice = Caller::random(); + let fevm = &DIFF_VM; + fevm.create_account(&alice, 2000_u64); + let fe_contract = DIFF_CONTRACTS[0].0.clone(); + let fe_contract = fe_contract.deploy(&alice, &[]); + let sol_contract = DIFF_CONTRACTS[0].1.clone(); + let sol_contract = sol_contract.deploy(&alice, &[]); + let harness = Harness { + fe: fe_contract, + sol: sol_contract, + }; + + harness.capture_call("add", &[int_token(val.into()), int_token(val2.into())], &alice).assert_perfomed_equal(); + harness.capture_call("subtract", &[int_token(val.into()), int_token(val2.into())], &alice).assert_perfomed_equal(); + harness.capture_call("divide", &[int_token(val.into()), int_token(val2.into())], &alice).assert_perfomed_equal(); + harness.capture_call("multiply", &[int_token(val.into()), int_token(val2.into())], &alice).assert_perfomed_equal(); + harness.capture_call("modulo", &[int_token(val.into()), int_token(val2.into())], &alice).assert_perfomed_equal(); + harness.capture_call("leftshift", &[int_token(val.into()), uint_token(val3.into())], &alice).assert_perfomed_equal(); + harness.capture_call("rightshift", &[int_token(val.into()), uint_token(val3.into())], &alice).assert_perfomed_equal(); + harness.capture_call("order_of_operation", &[int_token(val.into()), int_token(val2.into()), uint_token(val3.into())], &alice).assert_perfomed_equal(); + harness.capture_call("invert", &[int_token(val.into())], &alice).assert_perfomed_equal(); + harness.capture_call("cast1", &[int_token(val.into())], &alice).assert_perfomed_equal(); + harness.capture_call("cast2", &[int_token(val.into())], &alice).assert_perfomed_equal(); + harness.capture_call("cast3", &[int_token(val.into())], &alice).assert_perfomed_equal(); + harness.capture_call("negate", &[int_token(val.into())], &alice).assert_perfomed_equal(); } #[test] - #[ignore] fn storage_and_memory(my_num in 0u64..=100000, my_num2 in 0u8..=255, my_bool in any::(), my_str in "[0-9]{20}", my_long_string in ".{0,40}", my_num3 in -128i8..=127i8) { - with_executor(&|mut executor| { - - - let harness = DualHarness::from_fixture(&mut executor, "storage_and_memory", "Foo", &[]); + + + let alice = Caller::random(); + let fevm = &DIFF_VM; + fevm.create_account(&alice, 2000_u64); + let fe_contract = DIFF_CONTRACTS[2].0.clone(); + let fe_contract = fe_contract.deploy(&alice, &[]); + let sol_contract = DIFF_CONTRACTS[2].1.clone(); + let sol_contract = sol_contract.deploy(&alice, &[]); + let harness = Harness { + fe: fe_contract, + sol: sol_contract, + }; let data = ethabi::Token::Tuple(vec![ uint_token(my_num), uint_token(my_num2.into()), bool_token(my_bool), - address_token(&my_str), + address_token_from_str(&my_str), int_token(my_num3.into()) ]); - harness.capture_call(&mut executor, "set_data", &[data]).assert_any_success_with_equal_return_data().assert_fe_max_percentage_more_gas(200); - harness.capture_call(&mut executor, "get_data", &[]).assert_perfomed_equal().assert_fe_max_percentage_more_gas(150); + harness.capture_call("set_data", &[data], &alice).assert_any_success_with_equal_return_data().assert_fe_max_percentage_more_gas(200); + harness.capture_call("get_data", &[], &alice).assert_perfomed_equal().assert_fe_max_percentage_more_gas(150); - harness.capture_call(&mut executor, "set_item", &[uint_token(my_num2.into()), int_token(my_num3.into())]).assert_any_success_or_revert_with_equal_return_data(); - harness.capture_call(&mut executor, "get_items", &[]).assert_perfomed_equal(); + harness.capture_call("set_item", &[uint_token(my_num2.into()), int_token(my_num3.into())], &alice).assert_any_success_or_revert_with_equal_return_data(); + // Waiting on a fix for https://github.com/ethereum/fe/pull/581 + //harness.capture_call(&mut executor, "get_items", &[]).assert_perfomed_equal(); - harness.capture_call(&mut executor, "set_string", &[string_token(&my_long_string)]).assert_any_success_with_equal_return_data(); - harness.capture_call(&mut executor, "get_string", &[]).assert_perfomed_equal(); + harness.capture_call("set_string", &[string_token(&my_long_string)], &alice).assert_any_success_with_equal_return_data(); + harness.capture_call("get_string", &[], &alice).assert_perfomed_equal(); - harness.capture_call(&mut executor, "set_range", &[uint_token(my_num2.into()), uint_token(my_num)]).assert_any_success_or_revert_with_equal_return_data(); - harness.capture_call(&mut executor, "get_range", &[]).assert_perfomed_equal().assert_any_success_or_revert_with_equal_return_data(); + harness.capture_call("set_range", &[uint_token(my_num2.into()), uint_token(my_num)], &alice).assert_any_success_or_revert_with_equal_return_data(); + harness.capture_call("get_range", &[], &alice).assert_perfomed_equal().assert_any_success_or_revert_with_equal_return_data(); - }); + } } diff --git a/crates/tests/src/lib.rs b/crates/tests/src/lib.rs index 88e524f638..ac702382d9 100644 --- a/crates/tests/src/lib.rs +++ b/crates/tests/src/lib.rs @@ -1,3 +1,4 @@ + #[cfg(test)] mod crashes; #[cfg(test)] @@ -18,3 +19,29 @@ mod runtime; mod solidity; #[cfg(test)] mod stress; + +#[cfg(test)] +pub mod test_prebuilds { + use fevm::{Contract, ContractBuilder, Fevm}; + use once_cell::sync::Lazy; + use std::sync::Arc; + pub static DIFF_VM: Lazy>> = Lazy::new(|| { + Arc::new(Fevm::new()) + }); + + pub static DIFF_CONTRACTS: Lazy, Contract<'static>)>>> = Lazy::new(|| { + let differential_fe = vec!["math_i8", "math_u8", "storage_and_memory"]; + Arc::new(differential_fe.into_iter().map(|name| { + let fe_contract = ContractBuilder::new(&DIFF_VM) + .fixture(format!("differential/{}.fe", name).as_str(), format!("Foo{}Fe", &name).as_str()); + let sol_contract = ContractBuilder::new(&DIFF_VM) + .sol_fixture(format!("differential/{}.sol", name).as_str(), format!("Foo{}Sol", &name).as_str()); + (fe_contract, sol_contract) + }).collect::>()) + }); + + +} + +#[cfg(test)] +pub use test_prebuilds::*;