diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d83edf7a..2e1ab882 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,7 @@ jobs: - uses: cachix/cachix-action@v10 with: name: espresso-systems-private - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - uses: actions/checkout@v2 name: Checkout Repository @@ -68,6 +68,9 @@ jobs: - name: Generate Docs run: nix-shell --run "prepend-timestamps make-doc" + - name: Build all executables + run: nix-shell --run "cargo build --release" + - name: Generate Wallet run: ./target/release/export-wallet-api-docs --api ./wallet/api/api.toml --assets ./wallet/public/ ./doc/mdbook/book/wallet @@ -79,9 +82,6 @@ jobs: publish_dir: ./doc/mdbook/book/ cname: cape.docs.espressosys.com - - name: Build all executables - run: nix-shell --run "cargo build --release" - - name: Build demo geth data dir run: nix-shell --run "demo/initialize-demo-geth" diff --git a/Cargo.lock b/Cargo.lock index 2408ebe3..3bff882b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1126,7 +1126,7 @@ dependencies = [ "serde_json", "sha3 0.9.1", "snafu", - "strum_macros", + "strum_macros 0.20.1", "tagged-base64 0.2.0 (git+https://github.com/EspressoSystems/tagged-base64.git?tag=0.2.0)", "tokio", ] @@ -1188,7 +1188,7 @@ dependencies = [ "snafu", "structopt", "strum 0.20.0", - "strum_macros", + "strum_macros 0.20.1", "surf", "tagged-base64 0.2.0 (git+https://github.com/EspressoSystems/tagged-base64.git?tag=0.2.0)", "tempdir", @@ -1220,7 +1220,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.6", + "semver 1.0.9", "serde", "serde_json", ] @@ -2159,7 +2159,7 @@ dependencies = [ "snafu", "structopt", "strum 0.20.0", - "strum_macros", + "strum_macros 0.20.1", "surf", "tagged-base64 0.2.0 (git+https://github.com/EspressoSystems/tagged-base64.git?tag=0.2.0)", "tide", @@ -2302,8 +2302,8 @@ dependencies = [ [[package]] name = "ethers" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.6.2" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "ethers-addressbook", "ethers-contract", @@ -2318,7 +2318,7 @@ dependencies = [ [[package]] name = "ethers-addressbook" version = "0.1.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "ethers-core", "once_cell", @@ -2328,8 +2328,8 @@ dependencies = [ [[package]] name = "ethers-contract" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.6.2" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "ethers-contract-abigen", "ethers-contract-derive", @@ -2346,8 +2346,8 @@ dependencies = [ [[package]] name = "ethers-contract-abigen" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.6.3" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "Inflector", "cfg-if 1.0.0", @@ -2356,7 +2356,6 @@ dependencies = [ "eyre", "getrandom 0.2.5", "hex", - "once_cell", "proc-macro2", "quote", "reqwest", @@ -2369,8 +2368,8 @@ dependencies = [ [[package]] name = "ethers-contract-derive" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.6.3" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "ethers-contract-abigen", "ethers-core", @@ -2383,14 +2382,14 @@ dependencies = [ [[package]] name = "ethers-core" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.6.3" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "arrayvec 0.7.2", "bytes 1.1.0", "cargo_metadata", + "chrono", "convert_case 0.5.0", - "ecdsa", "elliptic-curve", "ethabi", "generic-array 0.14.5", @@ -2398,35 +2397,39 @@ dependencies = [ "k256", "once_cell", "proc-macro2", - "quote", "rand 0.8.5", "rlp", "rlp-derive", + "rust_decimal", "serde", "serde_json", + "strum 0.24.0", "syn", "thiserror", "tiny-keccak", + "unicode-xid", ] [[package]] name = "ethers-etherscan" -version = "0.2.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.2.2" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "ethers-core", "ethers-solc", "reqwest", + "semver 1.0.9", "serde", "serde-aux", "serde_json", "thiserror", + "tracing", ] [[package]] name = "ethers-middleware" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.6.2" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "async-trait", "ethers-contract", @@ -2434,6 +2437,7 @@ dependencies = [ "ethers-etherscan", "ethers-providers", "ethers-signers", + "futures-locks", "futures-util", "instant", "reqwest", @@ -2448,25 +2452,27 @@ dependencies = [ [[package]] name = "ethers-providers" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.6.2" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "async-trait", "auto_impl", "base64 0.13.0", "ethers-core", - "futures-channel", "futures-core", "futures-timer", "futures-util", + "hashers", "hex", "http", + "once_cell", "parking_lot 0.11.2", "pin-project", "reqwest", "serde", "serde_json", "thiserror", + "tokio", "tracing", "tracing-futures", "url", @@ -2479,8 +2485,8 @@ dependencies = [ [[package]] name = "ethers-signers" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +version = "0.6.2" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ "async-trait", "coins-bip32", @@ -2488,12 +2494,8 @@ dependencies = [ "elliptic-curve", "eth-keystore", "ethers-core", - "futures-executor", - "futures-util", "hex", - "home", "rand 0.8.5", - "semver 1.0.6", "sha2 0.9.9", "thiserror", ] @@ -2501,8 +2503,9 @@ dependencies = [ [[package]] name = "ethers-solc" version = "0.3.0" -source = "git+https://github.com/gakonst/ethers-rs#4f1a2352f7df48597224df777d9e77c1a56776e2" +source = "git+https://github.com/gakonst/ethers-rs#1a699ad72edddca9cb4601e115a2ff3e7f8c2ee6" dependencies = [ + "cfg-if 1.0.0", "colored", "dunce", "ethers-core", @@ -2513,16 +2516,17 @@ dependencies = [ "md-5", "num_cpus", "once_cell", + "path-slash", "rayon", "regex", - "semver 1.0.6", + "semver 1.0.9", "serde", "serde_json", - "sha2 0.9.9", "solang-parser", "svm-rs", "thiserror", "tiny-keccak", + "tokio", "tracing", "walkdir", ] @@ -2715,6 +2719,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -2796,6 +2810,17 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-locks" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb42d4fb72227be5778429f9ef5240a38a358925a49f05b5cf702ce7c7e558a" +dependencies = [ + "futures-channel", + "futures-task", + "tokio", +] + [[package]] name = "futures-macro" version = "0.3.21" @@ -2843,6 +2868,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -2976,6 +3010,15 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + [[package]] name = "heck" version = "0.3.3" @@ -3609,9 +3652,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc5937366afd3b38071f400d1ce5bd8b1d40b5083cc14e6f8dbcc4032a7f5bb" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" dependencies = [ "cfg-if 1.0.0", "ecdsa", @@ -4034,7 +4077,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ "autocfg", - "num-bigint 0.4.3", "num-integer", "num-traits", ] @@ -4075,9 +4117,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "oorandom" @@ -4233,6 +4275,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" +[[package]] +name = "path-slash" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cacbb3c4ff353b534a67fb8d7524d00229da4cb1dc8c79f4db96e375ab5b619" + [[package]] name = "paw" version = "1.0.0" @@ -4591,11 +4639,11 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -4774,9 +4822,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ "autocfg", "crossbeam-deque", @@ -4786,14 +4834,13 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] @@ -4841,14 +4888,14 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "snafu", - "strum_macros", + "strum_macros 0.20.1", ] [[package]] name = "regex" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -4866,9 +4913,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "relayer" @@ -5031,6 +5078,17 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rust_decimal" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ee7337df68898256ad0d4af4aad178210d9e44d2ff900ce44064a97cd86530" +dependencies = [ + "arrayvec 0.7.2", + "num-traits", + "serde", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -5067,7 +5125,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.6", + "semver 1.0.9", ] [[package]] @@ -5266,7 +5324,7 @@ dependencies = [ "snafu", "structopt", "strum 0.24.0", - "strum_macros", + "strum_macros 0.20.1", "surf", "tagged-base64 0.2.0 (git+https://github.com/EspressoSystems/tagged-base64.git?tag=0.2.0)", "tempdir", @@ -5306,9 +5364,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" dependencies = [ "serde", ] @@ -5649,15 +5707,13 @@ dependencies = [ [[package]] name = "solang-parser" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06b8bfb6c910adbada563211b876b91a058791505e4cb646591b205fa817d01" +checksum = "395b6e1ec5af117bd08f963c7cd80f8efd4eed51c5a332aed42b13e3f9bc860b" dependencies = [ + "itertools 0.10.3", "lalrpop", "lalrpop-util", - "num-bigint 0.4.3", - "num-rational 0.4.0", - "num-traits", "phf", "unicode-xid", ] @@ -5827,6 +5883,9 @@ name = "strum" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e96acfc1b70604b8b2f1ffa4c57e59176c7dbb05d556c71ecd2f5498a1dee7f8" +dependencies = [ + "strum_macros 0.24.0", +] [[package]] name = "strum_macros" @@ -5840,6 +5899,19 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef" +dependencies = [ + "heck 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "subtle" version = "2.4.1" @@ -5877,14 +5949,15 @@ checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08" [[package]] name = "svm-rs" -version = "0.2.9" -source = "git+https://github.com/roynalnaruto/svm-rs#ae79a29f5bde08f1991f981456253fa5b6859047" +version = "0.2.10" +source = "git+https://github.com/roynalnaruto/svm-rs#70fe9d9c43689e311753ce7a94f4618dd219bfda" dependencies = [ "anyhow", "cfg-if 1.0.0", "clap 3.1.6", "console 0.14.1", "dialoguer", + "fs2", "hex", "home", "indicatif", @@ -5892,7 +5965,7 @@ dependencies = [ "once_cell", "rand 0.8.5", "reqwest", - "semver 1.0.6", + "semver 1.0.9", "serde", "serde_json", "sha2 0.9.9", @@ -5905,13 +5978,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.87" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e59d925cf59d8151f25a3bedf97c9c157597c9df7324d32d68991cc399ed08b" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -6035,18 +6108,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -6208,9 +6281,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" dependencies = [ "bytes 1.1.0", "libc", @@ -6279,9 +6352,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ "cfg-if 1.0.0", "log", @@ -6450,6 +6523,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -6473,9 +6552,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "universal-hash" diff --git a/contracts/contracts.svg b/contracts/contracts.svg index 7aea65d9..3796a8fd 100644 --- a/contracts/contracts.svg +++ b/contracts/contracts.svg @@ -4,966 +4,986 @@ - - + + UmlClassDiagram - + 0 - -AssetRegistry - -Public: -   DOM_SEP_FOREIGN_ASSET: bytes13 -   DOM_SEP_DOMESTIC_ASSET: bytes14 -   CAP_NATIVE_ASSET_CODE: uint256 -   assets: mapping(bytes32=>address) - -Public: -    <<event>> AssetSponsored(erc20Address: address, assetDefinitionCode: uint256) -    nativeDomesticAsset(): (assetDefinition: AssetDefinition) -    lookup(assetDefinition: AssetDefinition): address -    isCapeAssetRegistered(assetDefinition: AssetDefinition): bool -    sponsorCapeAsset(erc20Address: address, newAsset: AssetDefinition) - - - -6 - -<<Library>> -BN254 - -Public: -   P_MOD: uint256 -   R_MOD: uint256 - - - - - -0->6 - - + +AssetRegistry + +Public: +   DOM_SEP_FOREIGN_ASSET: bytes13 +   DOM_SEP_DOMESTIC_ASSET: bytes14 +   CAP_NATIVE_ASSET_CODE: uint256 +   assets: mapping(bytes32=>address) + +Public: +    <<event>> AssetSponsored(erc20Address: address, assetDefinitionCode: uint256) +    nativeDomesticAsset(): (assetDefinition: AssetDefinition) +    lookup(assetDefinition: AssetDefinition): address +    isCapeAssetRegistered(assetDefinition: AssetDefinition): bool +    sponsorCapeAsset(erc20Address: address, newAsset: AssetDefinition) - + 7 - -<<Library>> -EdOnBN254 - -Public: -   P_MOD: uint256 - - + +<<Library>> +BN254 + +Public: +   P_MOD: uint256 +   R_MOD: uint256 + + - + 0->7 - - + + + + + +8 + +<<Library>> +EdOnBN254 + +Public: +   P_MOD: uint256 + + + + + +0->8 + + 0struct0 - -<<struct>> -AssetDefinition - -code: uint256 -policy: AssetPolicy + +<<struct>> +AssetDefinition + +code: uint256 +policy: AssetPolicy 0struct0->0 - - + + 0struct1 - -<<struct>> -AssetPolicy - -auditorPk: EdOnBN254.EdOnBN254Point -credPk: EdOnBN254.EdOnBN254Point -freezerPk: EdOnBN254.EdOnBN254Point -revealMap: uint256 -revealThreshold: uint128 + +<<struct>> +AssetPolicy + +auditorPk: EdOnBN254.EdOnBN254Point +credPk: EdOnBN254.EdOnBN254Point +freezerPk: EdOnBN254.EdOnBN254Point +revealMap: uint256 +revealThreshold: uint128 0struct1->0 - - + + 1 - -CAPE - -Public: -   nullifiers: mapping(uint256=>bool) -   blockHeight: uint64 -   pendingDeposits: uint256[] -   deployer: address -   faucetInitialized: bool -   CAPE_BURN_MAGIC_BYTES: bytes -   CAPE_BURN_MAGIC_BYTES_SIZE: uint256 -   MAX_NUM_PENDING_DEPOSIT: uint256 - -Public: -    <<event>> FaucetInitialized(roBytes: bytes) -    <<event>> BlockCommitted(height: uint64, depositCommitments: uint256[]) -    <<event>> Erc20TokensDeposited(roBytes: bytes, erc20TokenAddress: address, from: address) -    constructor(merkleTreeHeight: uint8, nRoots: uint64, verifierAddr: address) -    faucetSetupForTestnet(faucetManagerAddress: EdOnBN254.EdOnBN254Point, faucetManagerEncKey: bytes32) -    depositErc20(ro: RecordOpening, erc20Address: address) -    submitCapeBlockWithMemos(newBlock: CapeBlock, extraData: bytes) -    submitCapeBlock(newBlock: CapeBlock) + +CAPE + +Public: +   nullifiers: mapping(uint256=>bool) +   blockHeight: uint64 +   pendingDeposits: uint256[] +   deployer: address +   faucetInitialized: bool +   CAPE_BURN_MAGIC_BYTES: bytes +   CAPE_BURN_MAGIC_BYTES_SIZE: uint256 +   MAX_NUM_PENDING_DEPOSIT: uint256 + +Public: +    <<event>> FaucetInitialized(roBytes: bytes) +    <<event>> BlockCommitted(height: uint64, depositCommitments: uint256[], minerAddr: bytes, noteTypes: bytes, transferNotes: bytes, mintNotes: bytes, freezeNotes: bytes, burnNotes: bytes) +    <<event>> Erc20TokensDeposited(roBytes: bytes, erc20TokenAddress: address, from: address) +    constructor(nRoots: uint64, verifierAddr: address, recordsMerkleTreeAddr: address) +    faucetSetupForTestnet(faucetManagerAddress: EdOnBN254.EdOnBN254Point, faucetManagerEncKey: bytes32) +    depositErc20(ro: RecordOpening, erc20Address: address) +    submitCapeBlockWithMemos(newBlock: CapeBlock, extraData: bytes) +    submitCapeBlock(newBlock: CapeBlock) +    getRootValue(): uint256 - + 1->0 - - - - - -2 - -RecordsMerkleTree - - - -Public: -    constructor(merkleTreeHeight: uint8) -    getRootValue(): uint256 - - - -1->2 - - + + 3 - -RootStore - - - -Public: -    constructor(nRoots: uint64) + +RootStore + + + +Public: +    constructor(nRoots: uint64) - + 1->3 - - + + 4 - -<<Interface>> -IPlonkVerifier - - - -External: -     batchVerify(verifyingKeys: VerifyingKey[], publicInputs: uint256[][], proofs: PlonkProof[], extraTranscriptInitMsgs: bytes[]): bool + +<<Interface>> +IPlonkVerifier + + + +External: +     batchVerify(verifyingKeys: VerifyingKey[], publicInputs: uint256[][], proofs: PlonkProof[], extraTranscriptInitMsgs: bytes[]): bool - + 1->4 - - + + 5 - -<<Library>> -AccumulatingArray - - - - + +<<Interface>> +IRecordsMerkleTree + + + +External: +     updateRecordsMerkleTree(elements: uint256[]) +     getRootValue(): uint256 +     getHeight(): uint8 +     getNumLeaves(): uint64 - + 1->5 - - + + + + + +6 + +<<Library>> +AccumulatingArray + + + + + + + +1->6 + + - + -1->7 - - +1->8 + + - - -12 - -<<Library>> -RescueLib - - - -Public: -    hash(a: uint256, b: uint256, c: uint256): (o: uint256) -    commit(inputs: uint256[]): uint256 - - + + +13 + +<<Library>> +RescueLib + + + +Public: +    hash(a: uint256, b: uint256, c: uint256): (o: uint256) +    commit(inputs: uint256[]): uint256 + + -1->12 - - +1->13 + + - - -18 - -<<Library>> -VerifyingKeys - - - -External: -    getVkById(encodedId: uint256): IPlonkVerifier.VerifyingKey -Public: -    getEncodedId(noteType: uint8, numInput: uint8, numOutput: uint8, treeDepth: uint8): (encodedId: uint256) - - + + +19 + +<<Library>> +VerifyingKeys + + + +External: +    getVkById(encodedId: uint256): IPlonkVerifier.VerifyingKey +Public: +    getEncodedId(noteType: uint8, numInput: uint8, numOutput: uint8, treeDepth: uint8): (encodedId: uint256) + + -1->18 - - +1->19 + + 1struct0 - -<<struct>> -AuditMemo - -ephemeralKey: EdOnBN254.EdOnBN254Point -data: uint256[] + +<<struct>> +AuditMemo + +ephemeralKey: EdOnBN254.EdOnBN254Point +data: uint256[] 1struct0->1 - - + + 1struct1 - -<<struct>> -TransferNote - -inputNullifiers: uint256[] -outputCommitments: uint256[] -proof: IPlonkVerifier.PlonkProof -auditMemo: AuditMemo -auxInfo: TransferAuxInfo + +<<struct>> +TransferNote + +inputNullifiers: uint256[] +outputCommitments: uint256[] +proof: IPlonkVerifier.PlonkProof +auditMemo: AuditMemo +auxInfo: TransferAuxInfo 1struct1->1 - - + + 1struct2 - -<<struct>> -BurnNote - -transferNote: TransferNote -recordOpening: RecordOpening + +<<struct>> +BurnNote + +transferNote: TransferNote +recordOpening: RecordOpening 1struct2->1 - - + + 1struct3 - -<<struct>> -MintNote - -inputNullifier: uint256 -chgComm: uint256 -mintComm: uint256 -mintAmount: uint128 -mintAssetDef: AssetDefinition -mintInternalAssetCode: uint256 -proof: IPlonkVerifier.PlonkProof -auditMemo: AuditMemo -auxInfo: MintAuxInfo + +<<struct>> +MintNote + +inputNullifier: uint256 +chgComm: uint256 +mintComm: uint256 +mintAmount: uint128 +mintAssetDef: AssetDefinition +mintInternalAssetCode: uint256 +proof: IPlonkVerifier.PlonkProof +auditMemo: AuditMemo +auxInfo: MintAuxInfo 1struct3->1 - - + + 1struct4 - -<<struct>> -FreezeNote - -inputNullifiers: uint256[] -outputCommitments: uint256[] -proof: IPlonkVerifier.PlonkProof -auxInfo: FreezeAuxInfo + +<<struct>> +FreezeNote + +inputNullifiers: uint256[] +outputCommitments: uint256[] +proof: IPlonkVerifier.PlonkProof +auxInfo: FreezeAuxInfo 1struct4->1 - - + + 1struct5 - -<<struct>> -TransferAuxInfo - -merkleRoot: uint256 -fee: uint128 -validUntil: uint64 -txnMemoVerKey: EdOnBN254.EdOnBN254Point -extraProofBoundData: bytes + +<<struct>> +TransferAuxInfo + +merkleRoot: uint256 +fee: uint128 +validUntil: uint64 +txnMemoVerKey: EdOnBN254.EdOnBN254Point +extraProofBoundData: bytes 1struct5->1 - - + + 1struct6 - -<<struct>> -MintAuxInfo - -merkleRoot: uint256 -fee: uint128 -txnMemoVerKey: EdOnBN254.EdOnBN254Point + +<<struct>> +MintAuxInfo + +merkleRoot: uint256 +fee: uint128 +txnMemoVerKey: EdOnBN254.EdOnBN254Point 1struct6->1 - - + + 1struct7 - -<<struct>> -FreezeAuxInfo - -merkleRoot: uint256 -fee: uint128 -txnMemoVerKey: EdOnBN254.EdOnBN254Point + +<<struct>> +FreezeAuxInfo + +merkleRoot: uint256 +fee: uint128 +txnMemoVerKey: EdOnBN254.EdOnBN254Point 1struct7->1 - - + + 1struct8 - -<<struct>> -RecordOpening - -amount: uint128 -assetDef: AssetDefinition -userAddr: EdOnBN254.EdOnBN254Point -encKey: bytes32 -freezeFlag: bool -blind: uint256 + +<<struct>> +RecordOpening + +amount: uint128 +assetDef: AssetDefinition +userAddr: EdOnBN254.EdOnBN254Point +encKey: bytes32 +freezeFlag: bool +blind: uint256 1struct8->1 - - + + 1struct9 - -<<struct>> -CapeBlock - -minerAddr: EdOnBN254.EdOnBN254Point -noteTypes: NoteType[] -transferNotes: TransferNote[] -mintNotes: MintNote[] -freezeNotes: FreezeNote[] -burnNotes: BurnNote[] + +<<struct>> +CapeBlock + +minerAddr: EdOnBN254.EdOnBN254Point +noteTypes: NoteType[] +transferNotes: TransferNote[] +mintNotes: MintNote[] +freezeNotes: FreezeNote[] +burnNotes: BurnNote[] 1struct9->1 - - + + 1enum0 - -<<enum>> -NoteType - -TRANSFER: 0 -MINT: 1 -FREEZE: 2 -BURN: 3 + +<<enum>> +NoteType + +TRANSFER: 0 +MINT: 1 +FREEZE: 2 +BURN: 3 1enum0->1 - - + + - + + +2 + +RecordsMerkleTree + + + +External: +    updateRecordsMerkleTree(elements: uint256[]) +Public: +    constructor(merkleTreeHeight: uint8) +    getRootValue(): uint256 +    getHeight(): uint8 +    getNumLeaves(): uint64 + + -2->12 - - +2->13 + + 2struct0 - -<<struct>> -Node - -val: uint256 -left: uint64 -middle: uint64 -right: uint64 + +<<struct>> +Node + +val: uint256 +left: uint64 +middle: uint64 +right: uint64 2struct0->2 - - + + 2enum0 - -<<enum>> -Position - -LEFT: 0 -MIDDLE: 1 -RIGHT: 2 + +<<enum>> +Position + +LEFT: 0 +MIDDLE: 1 +RIGHT: 2 2enum0->2 - - + + - + -4->6 - - +4->7 + + 4struct0 - -<<struct>> -PlonkProof - -wire0: BN254.G1Point -wire1: BN254.G1Point -wire2: BN254.G1Point -wire3: BN254.G1Point -wire4: BN254.G1Point -prodPerm: BN254.G1Point -split0: BN254.G1Point -split1: BN254.G1Point -split2: BN254.G1Point -split3: BN254.G1Point -split4: BN254.G1Point -zeta: BN254.G1Point -zetaOmega: BN254.G1Point -wireEval0: uint256 -wireEval1: uint256 -wireEval2: uint256 -wireEval3: uint256 -wireEval4: uint256 -sigmaEval0: uint256 -sigmaEval1: uint256 -sigmaEval2: uint256 -sigmaEval3: uint256 -prodPermZetaOmegaEval: uint256 + +<<struct>> +PlonkProof + +wire0: BN254.G1Point +wire1: BN254.G1Point +wire2: BN254.G1Point +wire3: BN254.G1Point +wire4: BN254.G1Point +prodPerm: BN254.G1Point +split0: BN254.G1Point +split1: BN254.G1Point +split2: BN254.G1Point +split3: BN254.G1Point +split4: BN254.G1Point +zeta: BN254.G1Point +zetaOmega: BN254.G1Point +wireEval0: uint256 +wireEval1: uint256 +wireEval2: uint256 +wireEval3: uint256 +wireEval4: uint256 +sigmaEval0: uint256 +sigmaEval1: uint256 +sigmaEval2: uint256 +sigmaEval3: uint256 +prodPermZetaOmegaEval: uint256 4struct0->4 - - + + 4struct1 - -<<struct>> -VerifyingKey - -domainSize: uint256 -numInputs: uint256 -sigma0: BN254.G1Point -sigma1: BN254.G1Point -sigma2: BN254.G1Point -sigma3: BN254.G1Point -sigma4: BN254.G1Point -q1: BN254.G1Point -q2: BN254.G1Point -q3: BN254.G1Point -q4: BN254.G1Point -qM12: BN254.G1Point -qM34: BN254.G1Point -qO: BN254.G1Point -qC: BN254.G1Point -qH1: BN254.G1Point -qH2: BN254.G1Point -qH3: BN254.G1Point -qH4: BN254.G1Point -qEcc: BN254.G1Point + +<<struct>> +VerifyingKey + +domainSize: uint256 +numInputs: uint256 +sigma0: BN254.G1Point +sigma1: BN254.G1Point +sigma2: BN254.G1Point +sigma3: BN254.G1Point +sigma4: BN254.G1Point +q1: BN254.G1Point +q2: BN254.G1Point +q3: BN254.G1Point +q4: BN254.G1Point +qM12: BN254.G1Point +qM34: BN254.G1Point +qO: BN254.G1Point +qC: BN254.G1Point +qH1: BN254.G1Point +qH2: BN254.G1Point +qH3: BN254.G1Point +qH4: BN254.G1Point +qEcc: BN254.G1Point 4struct1->4 - - - - - -5struct0 - -<<struct>> -Data - -items: uint256[] -index: uint256 - - - -5struct0->5 - - - - - -17 - -<<Library>> -Utils - - - - - - - -6->17 - - + + - + 6struct0 - -<<struct>> -G1Point - -x: uint256 -y: uint256 + +<<struct>> +Data + +items: uint256[] +index: uint256 - + 6struct0->6 - - + + - - -6struct1 - -<<struct>> -G2Point - -x0: uint256 -x1: uint256 -y0: uint256 -y1: uint256 - - - -6struct1->6 - - - - - -7->7 - - - - - -7->17 - - + + +18 + +<<Library>> +Utils + + + + + + + +7->18 + + - + 7struct0 - -<<struct>> -EdOnBN254Point - -x: uint256 -y: uint256 + +<<struct>> +G1Point + +x: uint256 +y: uint256 - + 7struct0->7 - - + + - + + +7struct1 + +<<struct>> +G2Point + +x0: uint256 +x1: uint256 +y0: uint256 +y1: uint256 + + + +7struct1->7 + + + + + +8->8 + + + + + +8->18 + + + + -8 - -<<Library>> -Freeze2In2Out24DepthVk - - - - - - - -8->4 - - +8struct0 + +<<struct>> +EdOnBN254Point + +x: uint256 +y: uint256 + + + +8struct0->8 + + 9 - -<<Library>> -Freeze3In3Out24DepthVk - - - - + +<<Library>> +Freeze2In2Out24DepthVk + + + + - + 9->4 - - + + 10 - -<<Library>> -Mint1In2Out24DepthVk - - - - + +<<Library>> +Freeze3In3Out24DepthVk + + + + - + 10->4 - - + + 11 - -<<Library>> -PolynomialEval - - - - - - - -11->6 - - + +<<Library>> +Mint1In2Out24DepthVk + + + + + + + +11->4 + + - + -11struct0 - -<<struct>> -EvalDomain - -logSize: uint256 -size: uint256 -sizeInv: uint256 -groupGen: uint256 -groupGenInv: uint256 - - - -11struct0->11 - - +12 + +<<Library>> +PolynomialEval + + + + + + + +12->7 + + - + -11struct1 - -<<struct>> -EvalData - -vanishEval: uint256 -lagrangeOne: uint256 -piEval: uint256 - - - -11struct1->11 - - +12struct0 + +<<struct>> +EvalDomain + +logSize: uint256 +size: uint256 +sizeInv: uint256 +groupGen: uint256 +groupGenInv: uint256 + + + +12struct0->12 + + - - -13 - -<<Library>> -Transfer1In2Out24DepthVk - - - - - - - -13->4 - - + + +12struct1 + +<<struct>> +EvalData + +vanishEval: uint256 +lagrangeOne: uint256 +piEval: uint256 + + + +12struct1->12 + + 14 - -<<Library>> -Transfer2In2Out24DepthVk - - - - + +<<Library>> +Transfer1In2Out24DepthVk + + + + - + 14->4 - - + + 15 - -<<Library>> -Transfer2In3Out24DepthVk - - - - + +<<Library>> +Transfer2In2Out24DepthVk + + + + - + 15->4 - - + + 16 - -<<Library>> -Transfer3In3Out24DepthVk - - - - + +<<Library>> +Transfer2In3Out24DepthVk + + + + - + 16->4 - - + + - + + +17 + +<<Library>> +Transfer3In3Out24DepthVk + + + + + + + +17->4 + + + + -18->4 - - +19->4 + + - + -18->13 - - +19->14 + + - - -19 - -PlonkVerifier - - - -External: -    batchVerify(verifyingKeys: VerifyingKey[], publicInputs: uint256[][], proofs: PlonkProof[], extraTranscriptInitMsgs: bytes[]): bool + + +20 + +PlonkVerifier + + + +External: +    batchVerify(verifyingKeys: VerifyingKey[], publicInputs: uint256[][], proofs: PlonkProof[], extraTranscriptInitMsgs: bytes[]): bool - + -19->4 - - +20->4 + + - + -19->6 - - +20->7 + + - - -20 - -<<Library>> -Transcript - - - - - - + + +21 + +<<Library>> +Transcript + + + + + + -19->20 - - +20->21 + + - - -19struct0 - -<<struct>> -PcsInfo - -u: uint256 -evalPoint: uint256 -nextEvalPoint: uint256 -eval: uint256 -commScalars: uint256[] -commBases: BN254.G1Point[] -openingProof: BN254.G1Point -shiftedOpeningProof: BN254.G1Point - - + + +20struct0 + +<<struct>> +PcsInfo + +u: uint256 +evalPoint: uint256 +nextEvalPoint: uint256 +eval: uint256 +commScalars: uint256[] +commBases: BN254.G1Point[] +openingProof: BN254.G1Point +shiftedOpeningProof: BN254.G1Point + + -19struct0->19 - - +20struct0->20 + + - - -19struct1 - -<<struct>> -Challenges - -alpha: uint256 -alpha2: uint256 -alpha3: uint256 -beta: uint256 -gamma: uint256 -zeta: uint256 -v: uint256 -u: uint256 - - + + +20struct1 + +<<struct>> +Challenges + +alpha: uint256 +alpha2: uint256 +alpha3: uint256 +beta: uint256 +gamma: uint256 +zeta: uint256 +v: uint256 +u: uint256 + + -19struct1->19 - - +20struct1->20 + + - + -20->4 - - +21->4 + + - + -20->6 - - +21->7 + + - + -20->17 - - - - - -20struct0 - -<<struct>> -TranscriptData - -transcript: bytes -state: bytes32[] - - +21->18 + + + + + +21struct0 + +<<struct>> +TranscriptData + +transcript: bytes +state: bytes32[] + + -20struct0->20 - - +21struct0->21 + + diff --git a/contracts/contracts/CAPE.sol b/contracts/contracts/CAPE.sol index e217a419..e8eff92a 100644 --- a/contracts/contracts/CAPE.sol +++ b/contracts/contracts/CAPE.sol @@ -24,16 +24,17 @@ import "./libraries/EdOnBN254.sol"; import "./libraries/RescueLib.sol"; import "./libraries/VerifyingKeys.sol"; import "./interfaces/IPlonkVerifier.sol"; +import "./interfaces/IRecordsMerkleTree.sol"; import "./AssetRegistry.sol"; -import "./RecordsMerkleTree.sol"; import "./RootStore.sol"; -contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { +contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { using AccumulatingArray for AccumulatingArray.Data; mapping(uint256 => bool) public nullifiers; uint64 public blockHeight; IPlonkVerifier private _verifier; + IRecordsMerkleTree internal _recordsMerkleTree; uint256[] public pendingDeposits; // NOTE: used for faucet in testnet only, will be removed for mainnet @@ -49,7 +50,22 @@ contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { uint256 public constant MAX_NUM_PENDING_DEPOSIT = 10; event FaucetInitialized(bytes roBytes); - event BlockCommitted(uint64 indexed height, uint256[] depositCommitments); + + event BlockCommitted( + uint64 indexed height, + uint256[] depositCommitments, + // What follows is a `CapeBlock` struct split up into fields. + // This may no longer be necessary once + // https://github.com/gakonst/ethers-rs/issues/1220 + // is fixed. + bytes minerAddr, + bytes noteTypes, + bytes transferNotes, + bytes mintNotes, + bytes freezeNotes, + bytes burnNotes + ); + event Erc20TokensDeposited(bytes roBytes, address erc20TokenAddress, address from); struct AuditMemo { @@ -144,15 +160,15 @@ contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { } /// @notice CAPE contract constructor method. - /// @param merkleTreeHeight height of the merkle tree that stores the asset record commitments /// @param nRoots number of the most recent roots of the records merkle tree to be stored /// @param verifierAddr address of the Plonk Verifier contract constructor( - uint8 merkleTreeHeight, uint64 nRoots, - address verifierAddr - ) RecordsMerkleTree(merkleTreeHeight) RootStore(nRoots) { + address verifierAddr, + address recordsMerkleTreeAddr + ) RootStore(nRoots) { _verifier = IPlonkVerifier(verifierAddr); + _recordsMerkleTree = IRecordsMerkleTree(recordsMerkleTreeAddr); // NOTE: used for faucet in testnet only, will be removed for mainnet deployer = msg.sender; @@ -183,8 +199,8 @@ contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { recordCommitments[0] = _deriveRecordCommitment(ro); // insert the record into record accumulator - _updateRecordsMerkleTree(recordCommitments); - _addRoot(_rootValue); + _recordsMerkleTree.updateRecordsMerkleTree(recordCommitments); + _addRoot(_recordsMerkleTree.getRootValue()); emit FaucetInitialized(abi.encode(ro)); faucetInitialized = true; @@ -349,20 +365,34 @@ contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { // Only update the merkle tree and add the root if the list of records commitments is non empty if (!commitments.isEmpty()) { - _updateRecordsMerkleTree(commitments.items); - _addRoot(_rootValue); + _recordsMerkleTree.updateRecordsMerkleTree(commitments.items); + _addRoot(_recordsMerkleTree.getRootValue()); } // In all cases (the block is empty or not), the height is incremented. blockHeight += 1; // Inform clients about the new block and the processed deposits. - emit BlockCommitted(blockHeight, pendingDeposits); + _emitBlockEvent(newBlock); // Empty the queue now that the record commitments have been inserted delete pendingDeposits; } + /// @notice This function only exists to avoid a stack too deep compilation error. + function _emitBlockEvent(CapeBlock memory newBlock) internal { + emit BlockCommitted( + blockHeight, + pendingDeposits, + abi.encode(newBlock.minerAddr), + abi.encode(newBlock.noteTypes), + abi.encode(newBlock.transferNotes), + abi.encode(newBlock.mintNotes), + abi.encode(newBlock.freezeNotes), + abi.encode(newBlock.burnNotes) + ); + } + /// @dev send the ERC-20 tokens equivalent to the asset records being burnt. Recall that the burned record opening is contained inside the note. /// @param note note of type *BURN* function _handleWithdrawal(BurnNote memory note) internal { @@ -494,7 +524,7 @@ contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { uint8(NoteType.TRANSFER), uint8(note.inputNullifiers.length), uint8(note.outputCommitments.length), - uint8(_merkleTreeHeight) + uint8(_recordsMerkleTree.getHeight()) ) ); // prepare public inputs @@ -575,7 +605,7 @@ contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { uint8(NoteType.MINT), 1, // num of input 2, // num of output - uint8(_merkleTreeHeight) + uint8(_recordsMerkleTree.getHeight()) ) ); @@ -636,7 +666,7 @@ contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { uint8(NoteType.FREEZE), uint8(note.inputNullifiers.length), uint8(note.outputCommitments.length), - uint8(_merkleTreeHeight) + uint8(_recordsMerkleTree.getHeight()) ) ); @@ -665,4 +695,8 @@ contract CAPE is RecordsMerkleTree, RootStore, AssetRegistry, ReentrancyGuard { // prepare transcript init messages transcriptInitMsg = EdOnBN254.serialize(note.auxInfo.txnMemoVerKey); } + + function getRootValue() public view returns (uint256) { + return _recordsMerkleTree.getRootValue(); + } } diff --git a/contracts/contracts/RecordsMerkleTree.sol b/contracts/contracts/RecordsMerkleTree.sol index 3291a7b5..bca6628a 100644 --- a/contracts/contracts/RecordsMerkleTree.sol +++ b/contracts/contracts/RecordsMerkleTree.sol @@ -11,8 +11,9 @@ pragma solidity ^0.8.0; import "hardhat/console.sol"; import "./libraries/RescueLib.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; -contract RecordsMerkleTree { +contract RecordsMerkleTree is Ownable { enum Position { LEFT, MIDDLE, @@ -311,7 +312,7 @@ contract RecordsMerkleTree { /// @dev Update the state of the record merkle tree by inserting new elements. /// @param elements The list of elements to be appended to the current merkle tree described by the frontier. - function _updateRecordsMerkleTree(uint256[] memory elements) internal { + function updateRecordsMerkleTree(uint256[] memory elements) external onlyOwner { // The total number of nodes is bounded by 3*height+1 + 3*N*height = 3*(N+1)*height + 1 // where N is the number of new records uint256 numElements = elements.length; @@ -337,6 +338,16 @@ contract RecordsMerkleTree { return _rootValue; } + /// @notice Returns the height of the Merkle tree. + function getHeight() public view returns (uint8) { + return _merkleTreeHeight; + } + + /// @notice Returns the number of leaves of the Merkle tree. + function getNumLeaves() public view returns (uint64) { + return _numLeaves; + } + /// @dev Update the tree by hashing the children of each node. /// @param nodes The tree. Note that the nodes are updated by this function. /// @param rootNodePos The index of the root node in the list of nodes. diff --git a/contracts/contracts/interfaces/IRecordsMerkleTree.sol b/contracts/contracts/interfaces/IRecordsMerkleTree.sol new file mode 100644 index 00000000..5ffbaefd --- /dev/null +++ b/contracts/contracts/interfaces/IRecordsMerkleTree.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// +// Copyright (c) 2022 Espresso Systems (espressosys.com) +// This file is part of the Configurable Asset Privacy for Ethereum (CAPE) library. +// +// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// You should have received a copy of the GNU General Public License along with this program. If not, see . + +pragma solidity ^0.8.0; + +interface IRecordsMerkleTree { + /// @param elements The list of elements to be appended to the current merkle tree described by the frontier. + function updateRecordsMerkleTree(uint256[] memory elements) external; + + /// @notice Returns the root value of the Merkle tree. + function getRootValue() external view returns (uint256); + + /// @notice Returns the height of the Merkle tree. + function getHeight() external view returns (uint8); + + /// @notice Returns the number of leaves of the Merkle tree. + function getNumLeaves() external view returns (uint64); +} diff --git a/contracts/contracts/mocks/TestCAPE.sol b/contracts/contracts/mocks/TestCAPE.sol index 54d0a8b1..c4db5a2c 100644 --- a/contracts/contracts/mocks/TestCAPE.sol +++ b/contracts/contracts/mocks/TestCAPE.sol @@ -13,19 +13,19 @@ import "../CAPE.sol"; contract TestCAPE is CAPE { constructor( - uint8 merkleTreeHeight, uint64 nRoots, - address verifierAddr - ) CAPE(merkleTreeHeight, nRoots, verifierAddr) {} + address verifierAddr, + address recordsMerkleTreeAddr + ) CAPE(nRoots, verifierAddr, recordsMerkleTreeAddr) {} function getNumLeaves() public view returns (uint256) { - return _numLeaves; + return _recordsMerkleTree.getNumLeaves(); } function setInitialRecordCommitments(uint256[] memory elements) public { - require(_rootValue == 0, "Merkle tree is nonempty"); - _updateRecordsMerkleTree(elements); - addRoot(_rootValue); + require(_recordsMerkleTree.getRootValue() == 0, "Merkle tree is nonempty"); + _recordsMerkleTree.updateRecordsMerkleTree(elements); + addRoot(_recordsMerkleTree.getRootValue()); } function publish(uint256 nullifier) public { diff --git a/contracts/contracts/mocks/TestRecordsMerkleTree.sol b/contracts/contracts/mocks/TestRecordsMerkleTree.sol index 3dbc73a1..240222b4 100644 --- a/contracts/contracts/mocks/TestRecordsMerkleTree.sol +++ b/contracts/contracts/mocks/TestRecordsMerkleTree.sol @@ -10,15 +10,13 @@ pragma solidity ^0.8.0; import "hardhat/console.sol"; -import "../RecordsMerkleTree.sol"; +import {RecordsMerkleTree as R} from "../RecordsMerkleTree.sol"; import "../libraries/RescueLib.sol"; -contract TestRecordsMerkleTree is RecordsMerkleTree { - constructor(uint8 height) RecordsMerkleTree(height) {} - - function testUpdateRecordsMerkleTree(uint256[] memory elements) public { - _updateRecordsMerkleTree(elements); - } +// This contract is only used in a javascript benchmark and +// could be removed. +contract TestRecordsMerkleTree is R { + constructor(uint8 height) R(height) {} function doNothing() public {} } diff --git a/contracts/deploy/00_cape.ts b/contracts/deploy/00_cape.ts index bb8f8522..ee4c07c5 100644 --- a/contracts/deploy/00_cape.ts +++ b/contracts/deploy/00_cape.ts @@ -9,6 +9,12 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import { DeployFunction } from "hardhat-deploy/types"; import { BigNumber } from "ethers"; +const treeDepth = 24; + +// Enough so that a wallet CAP transaction can make it to the CAPE contract, +// but not too much in order to free the records of a rejected/lost transaction after a reasonable amount of time. +const nRoots = 40; + const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployments, getNamedAccounts } = hre; const { deploy, execute } = deployments; @@ -19,6 +25,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { args: [], log: true, }); + let verifyingKeys = await deploy("VerifyingKeys", { from: deployer, args: [], @@ -31,11 +38,14 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { log: true, }); - const treeDepth = 24; - - // Enough so that a wallet CAP transaction can make it to the CAPE contract, - // but not too much in order to free the records of a rejected/lost transaction after a reasonable amount of time. - const nRoots = 40; + let recordsMerkleTreeContract = await deploy("RecordsMerkleTree", { + from: deployer, + args: [treeDepth], + log: true, + libraries: { + RescueLib: rescueLib.address, + }, + }); // To change, update change FAUCET_MANAGER_ENCRYPTION_KEY in rust/src/cape/faucet.rs // @@ -68,15 +78,26 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { }; } - await deploy("CAPE", { + const CAPE = await deploy("CAPE", { from: deployer, - args: [treeDepth, nRoots, plonkVerifierContract.address], + args: [nRoots, plonkVerifierContract.address, recordsMerkleTreeContract.address], log: true, libraries: { RescueLib: rescueLib.address, VerifyingKeys: verifyingKeys.address, }, }); + + await execute( + "RecordsMerkleTree", + { + log: true, + from: deployer, + }, + "transferOwnership", + CAPE.address + ); + await execute( "CAPE", { diff --git a/contracts/rust/src/cape/events.rs b/contracts/rust/src/cape/events.rs index 1691d0ee..eec01dbd 100644 --- a/contracts/rust/src/cape/events.rs +++ b/contracts/rust/src/cape/events.rs @@ -5,11 +5,27 @@ // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // You should have received a copy of the GNU General Public License along with this program. If not, see . +use crate::{cape::CapeBlock, types::BlockCommittedFilter}; +use ethers::{abi::AbiDecode, prelude::AbiError}; + +pub fn decode_cape_block_from_event(block: BlockCommittedFilter) -> Result { + Ok(crate::types::CapeBlock { + miner_addr: AbiDecode::decode(block.miner_addr)?, + note_types: AbiDecode::decode(block.note_types)?, + transfer_notes: AbiDecode::decode(block.transfer_notes)?, + mint_notes: AbiDecode::decode(block.mint_notes)?, + freeze_notes: AbiDecode::decode(block.freeze_notes)?, + burn_notes: AbiDecode::decode(block.burn_notes)?, + } + .into()) +} + #[cfg(test)] mod tests { use crate::{ cape::{ - submit_block::{fetch_cape_block, submit_cape_block_with_memos}, + events::decode_cape_block_from_event, + submit_block::{fetch_cape_memos, submit_cape_block_with_memos}, BlockWithMemos, CapeBlock, }, ethereum::EthConnection, @@ -32,11 +48,11 @@ mod tests { use std::iter::repeat_with; #[tokio::test] - async fn test_fetch_cape_block_from_event() -> Result<()> { + async fn test_fetch_cape_memos_from_event() -> Result<()> { let connection = EthConnection::for_test().await; let mut rng = ChaChaRng::from_seed([0x42u8; 32]); - let params = TxnsParams::generate_txns(&mut rng, 1, 0, 0, CapeLedger::merkle_height()); + let params = TxnsParams::generate_txns(&mut rng, 1, 1, 1, CapeLedger::merkle_height()); let miner = UserPubKey::default(); let root = params.txns[0].merkle_root(); @@ -98,13 +114,15 @@ mod tests { .query_with_meta() .await?; - let (_, meta) = events[0].clone(); + let (data, meta) = events[0].clone(); - let fetched_block_with_memos = fetch_cape_block(&query_connection, meta.transaction_hash) + let fetched_memos = fetch_cape_memos(&query_connection, meta.transaction_hash) .await? .unwrap(); + assert_eq!(fetched_memos, memos_with_sigs); - assert_eq!(fetched_block_with_memos, block_with_memos); + let event_cape_block = decode_cape_block_from_event(data)?; + assert_eq!(cape_block, event_cape_block); Ok(()) } diff --git a/contracts/rust/src/cape/mod.rs b/contracts/rust/src/cape/mod.rs index f0918dbd..98a61321 100644 --- a/contracts/rust/src/cape/mod.rs +++ b/contracts/rust/src/cape/mod.rs @@ -6,7 +6,7 @@ // You should have received a copy of the GNU General Public License along with this program. If not, see . #![deny(warnings)] -mod events; +pub mod events; pub mod faucet; mod note_types; mod reentrancy; @@ -305,25 +305,44 @@ impl From for NoteType { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct CAPEConstructorArgs { - height: u8, n_roots: u64, verifier_addr: Address, + records_merkle_tree_addr: Address, } -#[allow(dead_code)] impl CAPEConstructorArgs { - pub fn new(height: u8, n_roots: u64, verifier_addr: Address) -> Self { + pub fn new(n_roots: u64, verifier_addr: Address, records_merkle_tree_addr: Address) -> Self { Self { - height, n_roots, verifier_addr, + records_merkle_tree_addr, } } + + /// We need to pass a tuple when we deploy the contract. The function that + /// deploys the contract is not aware of the exact type of the tuple. It's + /// convenient to "fix" this type in one place. + pub fn to_tuple(&self) -> (u64, Address, Address) { + ( + self.n_roots, + self.verifier_addr, + self.records_merkle_tree_addr, + ) + } } -impl From for (u8, u64, Address) { - fn from(args: CAPEConstructorArgs) -> (u8, u64, Address) { - (args.height, args.n_roots, args.verifier_addr) +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct RecordsMerkleTreeConstructorArgs { + height: u8, +} + +impl RecordsMerkleTreeConstructorArgs { + pub fn new(height: u8) -> Self { + Self { height } + } + + pub fn to_tuple(&self) -> (u8,) { + (self.height,) } } diff --git a/contracts/rust/src/cape/submit_block.rs b/contracts/rust/src/cape/submit_block.rs index 01a33089..b8d3144c 100644 --- a/contracts/rust/src/cape/submit_block.rs +++ b/contracts/rust/src/cape/submit_block.rs @@ -5,7 +5,6 @@ // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // You should have received a copy of the GNU General Public License along with this program. If not, see . -use crate::cape::CapeBlock; use crate::deploy::EthMiddleware; use crate::ethereum::EthConnection; use crate::types::{self as sol, CAPE}; @@ -21,10 +20,10 @@ use super::{BlockMemos, BlockWithMemos}; /// Fetch a cape block given the (Ethereum) tx hash of the tx in which the block /// was submitted. -pub async fn fetch_cape_block( +pub async fn fetch_cape_memos( connection: &EthConnection, tx_hash: TxHash, -) -> Result, Error> { +) -> Result, Error> { // Fetch Ethereum transaction that emitted event let tx = if let Some(tx) = connection.provider.get_transaction(tx_hash).await? { tx @@ -33,16 +32,14 @@ pub async fn fetch_cape_block( }; // Decode the calldata (tx.input) into the function input types - let (decoded_calldata_block, fetched_memos_bytes) = - connection - .contract - .decode::<(sol::CapeBlock, Bytes), _>("submitCapeBlockWithMemos", tx.input)?; + let (_, fetched_memos_bytes) = connection + .contract + .decode::<(sol::CapeBlock, Bytes), _>("submitCapeBlockWithMemos", tx.input)?; - let decoded_cape_block = CapeBlock::from(decoded_calldata_block); let decoded_memos: BlockMemos = CanonicalDeserialize::deserialize(&fetched_memos_bytes.to_vec()[..])?; - Ok(Some(BlockWithMemos::new(decoded_cape_block, decoded_memos))) + Ok(Some(decoded_memos)) } pub async fn submit_cape_block_with_memos( @@ -107,7 +104,8 @@ pub async fn submit_cape_block_with_memos( mod tests { use super::*; use crate::{ - assertion::Matcher, + assertion::{EnsureMined, Matcher}, + cape::CapeBlock, deploy::deploy_test_cape, ledger::CapeLedger, test_utils::PrintGas, @@ -352,13 +350,15 @@ mod tests { .add_root(root.generic_into::().0) .send() .await? - .await?; + .await? + .ensure_mined(); contract .submit_cape_block(cape_block.into()) .send() .await? - .await?; + .await? + .ensure_mined(); assert_eq!(contract.block_height().call().await?, 1u64); Ok(()) diff --git a/contracts/rust/src/deploy.rs b/contracts/rust/src/deploy.rs index 428728b0..aef3442b 100644 --- a/contracts/rust/src/deploy.rs +++ b/contracts/rust/src/deploy.rs @@ -5,16 +5,17 @@ // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // You should have received a copy of the GNU General Public License along with this program. If not, see . -use crate::cape::CAPEConstructorArgs; +use crate::assertion::EnsureMined; +use crate::cape::{CAPEConstructorArgs, RecordsMerkleTreeConstructorArgs}; use crate::ethereum::{deploy, get_funded_client}; -use crate::model::CAPE_MERKLE_HEIGHT; +use crate::model::{CAPE_MERKLE_HEIGHT, CAPE_NUM_ROOTS}; use crate::test_utils::contract_abi_path; use crate::types::{ - AssetRegistry, GenericInto, MaliciousToken, SimpleToken, TestBN254, TestCAPE, TestCapeTypes, - TestEdOnBN254, TestPlonkVerifier, TestPolynomialEval, TestRecordsMerkleTree, TestRescue, - TestRootStore, TestTranscript, TestVerifyingKeys, CAPE, + AssetRegistry, MaliciousToken, RecordsMerkleTree, SimpleToken, TestBN254, TestCAPE, + TestCapeTypes, TestEdOnBN254, TestPlonkVerifier, TestPolynomialEval, TestRescue, TestRootStore, + TestTranscript, TestVerifyingKeys, CAPE, }; -use ethers::prelude::{k256::ecdsa::SigningKey, Address, Http, Provider, SignerMiddleware, Wallet}; +use ethers::prelude::{k256::ecdsa::SigningKey, Http, Provider, SignerMiddleware, Wallet}; use std::sync::Arc; // Middleware used for locally signing transactions @@ -42,16 +43,38 @@ pub async fn deploy_test_cape_with_deployer( .await .unwrap(); + let records_merkle_tree = deploy( + deployer.clone(), + &contract_abi_path("RecordsMerkleTree.sol/RecordsMerkleTree"), + RecordsMerkleTreeConstructorArgs::new(CAPE_MERKLE_HEIGHT).to_tuple(), + ) + .await + .unwrap(); + // deploy TestCAPE.sol - let contract = deploy( + let cape = deploy( deployer.clone(), &contract_abi_path("mocks/TestCAPE.sol/TestCAPE"), - CAPEConstructorArgs::new(CAPE_MERKLE_HEIGHT, 1000, verifier.address()) - .generic_into::<(u8, u64, Address)>(), + CAPEConstructorArgs::new( + CAPE_NUM_ROOTS, + verifier.address(), + records_merkle_tree.address(), + ) + .to_tuple(), ) .await .unwrap(); - TestCAPE::new(contract.address(), deployer) + + RecordsMerkleTree::new(records_merkle_tree.address(), deployer.clone()) + .transfer_ownership(cape.address()) + .send() + .await + .unwrap() + .await + .unwrap() + .ensure_mined(); + + TestCAPE::new(cape.address(), deployer) } pub async fn deploy_cape_with_deployer(deployer: Arc) -> CAPE { @@ -64,16 +87,38 @@ pub async fn deploy_cape_with_deployer(deployer: Arc) -> CAPE(), + CAPEConstructorArgs::new( + CAPE_NUM_ROOTS, + verifier.address(), + records_merkle_tree.address(), + ) + .to_tuple(), ) .await .unwrap(); - CAPE::new(contract.address(), deployer) + + RecordsMerkleTree::new(records_merkle_tree.address(), deployer.clone()) + .transfer_ownership(cape.address()) + .send() + .await + .unwrap() + .await + .unwrap() + .ensure_mined(); + + CAPE::new(cape.address(), deployer) } macro_rules! mk_deploy_fun { @@ -164,18 +209,16 @@ pub async fn deploy_test_transcript_contract() -> TestTranscript TestTranscript::new(contract.address(), client) } -pub async fn deploy_test_records_merkle_tree_contract( - height: u8, -) -> TestRecordsMerkleTree { +pub async fn deploy_records_merkle_tree_contract(height: u8) -> RecordsMerkleTree { let client = get_funded_client().await.unwrap(); let contract = deploy( client.clone(), - &contract_abi_path("mocks/TestRecordsMerkleTree.sol/TestRecordsMerkleTree"), + &contract_abi_path("RecordsMerkleTree.sol/RecordsMerkleTree"), height, ) .await .unwrap(); - TestRecordsMerkleTree::new(contract.address(), client) + RecordsMerkleTree::new(contract.address(), client) } #[cfg(test)] @@ -185,7 +228,7 @@ mod test { ensure_connected_to_contract, get_provider, has_code_at_block, is_connected_to_contract, }; use anyhow::Result; - use ethers::prelude::Middleware; + use ethers::prelude::{Address, Middleware}; #[tokio::test] async fn test_is_connected_to_contract() -> Result<()> { diff --git a/contracts/rust/src/model.rs b/contracts/rust/src/model.rs index dc0912a3..ee870786 100644 --- a/contracts/rust/src/model.rs +++ b/contracts/rust/src/model.rs @@ -31,6 +31,7 @@ use std::sync::Arc; // can be changed later. pub const CAPE_MERKLE_HEIGHT: u8 = 24 /*H*/; pub const CAPE_BURN_MAGIC_BYTES: &str = "EsSCAPE burn"; +pub const CAPE_NUM_ROOTS: u64 = 40; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum CapeModelTxn { diff --git a/contracts/rust/src/records_merkle_tree/mod.rs b/contracts/rust/src/records_merkle_tree/mod.rs index cb7759e0..fcf23e83 100644 --- a/contracts/rust/src/records_merkle_tree/mod.rs +++ b/contracts/rust/src/records_merkle_tree/mod.rs @@ -117,7 +117,7 @@ fn parse_flattened_frontier(flattened_frontier: &[Fr254], uid: u64) -> MerkleFro #[cfg(test)] mod tests { use super::*; - use crate::deploy::deploy_test_records_merkle_tree_contract; + use crate::deploy::deploy_records_merkle_tree_contract; use crate::helpers::convert_fr254_to_u256; use crate::test_utils::compare_roots_records_merkle_tree_contract; use ark_ed_on_bn254::Fq as Fr254; @@ -231,7 +231,7 @@ mod tests { ) { // Check that we can insert values in the Merkle tree - let contract = deploy_test_records_merkle_tree_contract(height).await; + let contract = deploy_records_merkle_tree_contract(height).await; let mut mt = MerkleTree::::new(height).unwrap(); // At beginning (no leaf inserted) both roots are the same. @@ -240,7 +240,7 @@ mod tests { // We insert the first set of leaves let elems_u256 = insert_elements_into_jellyfish_mt(&mut mt, n_leaves_before); contract - .test_update_records_merkle_tree(elems_u256) + .update_records_merkle_tree(elems_u256) .legacy() .send() .await @@ -253,7 +253,7 @@ mod tests { // We insert the second set of leaves let elems_u256 = insert_elements_into_jellyfish_mt(&mut mt, n_leaves_after); contract - .test_update_records_merkle_tree(elems_u256) + .update_records_merkle_tree(elems_u256) .legacy() .send() .await diff --git a/contracts/rust/src/test_utils.rs b/contracts/rust/src/test_utils.rs index 190712cd..577e1d69 100644 --- a/contracts/rust/src/test_utils.rs +++ b/contracts/rust/src/test_utils.rs @@ -9,8 +9,8 @@ use crate::cape::{BurnNote, DOM_SEP_CAPE_BURN}; use crate::deploy::EthMiddleware; use crate::helpers::compare_merkle_root_from_contract_and_jf_tree; use crate::ledger::CapeLedger; +use crate::types::{RecordsMerkleTree, CAPE}; use crate::types::{SimpleToken, TestCAPE}; -use crate::types::{TestRecordsMerkleTree, CAPE}; use crate::universal_param::UNIVERSAL_PARAM; use ethers::prelude::TransactionReceipt; use ethers::prelude::{Address, H160, U256}; @@ -222,12 +222,14 @@ pub fn generate_burn_tx( BurnNote::generate(note, burn_ro).unwrap() } -/// Compare the roots of a local merkle tree and the TestRecordsMerkleTree contract merkle tree. -/// By calling the CAPE contract `get_root_value` and comparing it to the root of the merkle tree passed as argument, -/// one can check that the CAPE contract updates the root value correctly after inserting new records commitments. +/// Compare the roots of a local merkle tree and the RecordsMerkleTree contract +/// merkle tree. By calling the CAPE contract `get_root_value` and comparing it +/// to the root of the merkle tree passed as argument, one can check that the +/// CAPE contract updates the root value correctly after inserting new records +/// commitments. pub async fn compare_roots_records_merkle_tree_contract( mt: &MerkleTree, - contract: &TestRecordsMerkleTree, + contract: &RecordsMerkleTree, should_be_equal: bool, ) { let root_fr254 = mt.commitment().root_value; diff --git a/contracts/rust/src/types.rs b/contracts/rust/src/types.rs index cde34bcd..b1cc6080 100644 --- a/contracts/rust/src/types.rs +++ b/contracts/rust/src/types.rs @@ -26,13 +26,13 @@ use jf_primitives::elgamal::{self, EncKey}; use std::convert::TryInto; pub use crate::bindings::{ - AssetDefinition, AssetPolicy, AssetRegistry, AuditMemo, BurnNote, CAPEEvents, CapeBlock, - Challenges, EdOnBN254Point, EvalData, EvalDomain, FreezeAuxInfo, FreezeNote, G1Point, G2Point, - Greeter, MaliciousToken, MintAuxInfo, MintNote, PcsInfo, PlonkProof, RecordOpening, - SimpleToken, TestBN254, TestCAPE, TestCAPEEvents, TestCapeTypes, TestEdOnBN254, - TestPlonkVerifier, TestPolynomialEval, TestRecordsMerkleTree, TestRescue, TestRootStore, - TestTranscript, TestVerifyingKeys, TranscriptData, TransferAuxInfo, TransferNote, VerifyingKey, - CAPE, ERC20, + cape_mod::BlockCommittedFilter, AssetDefinition, AssetPolicy, AssetRegistry, AuditMemo, + BurnNote, CAPEEvents, CapeBlock, Challenges, EdOnBN254Point, EvalData, EvalDomain, + FreezeAuxInfo, FreezeNote, G1Point, G2Point, Greeter, MaliciousToken, MintAuxInfo, MintNote, + PcsInfo, PlonkProof, RecordOpening, RecordsMerkleTree, SimpleToken, TestBN254, TestCAPE, + TestCAPEEvents, TestCapeTypes, TestEdOnBN254, TestPlonkVerifier, TestPolynomialEval, + TestRescue, TestRootStore, TestTranscript, TestVerifyingKeys, TranscriptData, TransferAuxInfo, + TransferNote, VerifyingKey, CAPE, ERC20, }; // The number of input wires of TurboPlonk. diff --git a/contracts/rust/tests/hardhat_deploy.rs b/contracts/rust/tests/hardhat_deploy.rs index becf86f6..f539385c 100644 --- a/contracts/rust/tests/hardhat_deploy.rs +++ b/contracts/rust/tests/hardhat_deploy.rs @@ -6,11 +6,15 @@ // You should have received a copy of the GNU General Public License along with this program. If not, see . use anyhow::Result; use cap_rust_sandbox::{ + assertion::Matcher, cape::faucet::FAUCET_MANAGER_ENCRYPTION_KEY, ethereum::get_funded_client, - types::{self as sol, GenericInto, CAPE}, + types::{self as sol, GenericInto, RecordsMerkleTree, CAPE}, +}; +use ethers::{ + abi::AbiDecode, + prelude::{Address, U256}, }; -use ethers::{abi::AbiDecode, prelude::Address}; use jf_cap::{keys::UserPubKey, structs::RecordOpening}; use regex::Regex; use std::{process::Command, str::FromStr}; @@ -39,7 +43,7 @@ async fn test_hardhat_deploy() -> Result<()> { // Get the address out of // deploying "CAPE" (tx: 0x64...211)...: deployed at 0x8A791620dd6260079BF849Dc5567aDC3F2FdC318 with 7413790 gas let re = Regex::new(r#""CAPE".*(0x[0-9a-fA-F]{40})"#).unwrap(); - let address = re + let cape_address = re .captures_iter(&text) .next() .unwrap_or_else(|| panic!("Address not found in {}", text))[1] @@ -47,8 +51,8 @@ async fn test_hardhat_deploy() -> Result<()> { .unwrap_or_else(|_| panic!("Address not found in {}", text)); let client = get_funded_client().await.unwrap(); - let contract = CAPE::new(address, client.clone()); - let event = contract + let cape = CAPE::new(cape_address, client.clone()); + let event = cape .faucet_initialized_filter() .from_block(0u64) .query() @@ -63,5 +67,26 @@ async fn test_hardhat_deploy() -> Result<()> { ro_sol.generic_into::().pub_key, ); + let re = Regex::new(r#""RecordsMerkleTree".*(0x[0-9a-fA-F]{40})"#).unwrap(); + let merkle_tree_address = re + .captures_iter(&text) + .next() + .unwrap_or_else(|| panic!("Address not found in {}", text))[1] + .parse::
() + .unwrap_or_else(|_| panic!("Address not found in {}", text)); + + let merkle_tree = RecordsMerkleTree::new(merkle_tree_address, client.clone()); + + // Check that the cape contract owns the records merkle tree contract. + assert_eq!(merkle_tree.owner().call().await?, cape.address()); + + // Check that the deployer is no longer able to operate the + // records merkle tree contract. + merkle_tree + .update_records_merkle_tree(vec![U256::from(0)]) + .call() + .await + .should_revert_with_message("Ownable: caller is not the owner"); + Ok(()) } diff --git a/contracts/test/benchmarks/test-records-merkle-tree.js b/contracts/test/benchmarks/test-records-merkle-tree.js index f4010211..2cf160b8 100644 --- a/contracts/test/benchmarks/test-records-merkle-tree.js +++ b/contracts/test/benchmarks/test-records-merkle-tree.js @@ -33,11 +33,11 @@ describe("Records Merkle Tree Benchmarks", function () { it("shows how much gas is spent by updateRecordsMerkleTree", async function () { let elems = [1, 2, 3, 4, 5]; - const txEmpty = await rmtContract.testUpdateRecordsMerkleTree([]); + const txEmpty = await rmtContract.updateRecordsMerkleTree([]); const txEmptyReceipt = await txEmpty.wait(); let emptyGasUsed = txEmptyReceipt.gasUsed; - tx = await rmtContract.testUpdateRecordsMerkleTree(elems); + tx = await rmtContract.updateRecordsMerkleTree(elems); const txReceipt = await tx.wait(); let totalGasUsed = txReceipt.gasUsed; diff --git a/contracts/test/cape.spec.ts b/contracts/test/cape.spec.ts index dd8188df..88b41b04 100644 --- a/contracts/test/cape.spec.ts +++ b/contracts/test/cape.spec.ts @@ -8,6 +8,9 @@ import { expect } from "chai"; import { ethers } from "hardhat"; +const TREE_HEIGHT = 24; +const N_ROOTS = 1000; + describe("CAPE", function () { describe("Handling of nullifiers", async function () { let cape: any; @@ -16,6 +19,15 @@ describe("CAPE", function () { let rescue = await (await ethers.getContractFactory("RescueLib")).deploy(); let verifyingKeys = await (await ethers.getContractFactory("VerifyingKeys")).deploy(); let plonkVerifier = await (await ethers.getContractFactory("PlonkVerifier")).deploy(); + + let merkleTree = await ( + await ethers.getContractFactory("RecordsMerkleTree", { + libraries: { + RescueLib: rescue.address, + }, + }) + ).deploy(TREE_HEIGHT); + let capeFactory = await ethers.getContractFactory("TestCAPE", { libraries: { RescueLib: rescue.address, @@ -23,9 +35,10 @@ describe("CAPE", function () { }, }); - const TREE_HEIGHT = 24; - const N_ROOTS = 1000; - cape = await capeFactory.deploy(TREE_HEIGHT, N_ROOTS, plonkVerifier.address); + cape = await capeFactory.deploy(N_ROOTS, plonkVerifier.address, merkleTree.address); + + let tx = await merkleTree.transferOwnership(cape.address); + await tx.wait(); }); it("is possible to check for non-membership", async function () { diff --git a/contracts/test/records-merkle-tree.spec.ts b/contracts/test/records-merkle-tree.spec.ts index eab60f17..b7f7fa2a 100644 --- a/contracts/test/records-merkle-tree.spec.ts +++ b/contracts/test/records-merkle-tree.spec.ts @@ -9,7 +9,7 @@ const { expect } = require("chai"); const { ethers } = require("hardhat"); /* -import { TestRecordsMerkleTree } from "../typechain-types"; +import { RecordsMerkleTree } from "../typechain-types"; */ describe("Records Merkle Tree tests", function () { @@ -20,7 +20,7 @@ describe("Records Merkle Tree tests", function () { beforeEach(async function () { let rescue = await (await ethers.getContractFactory("RescueLib")).deploy(); - rmtFactory = await ethers.getContractFactory("TestRecordsMerkleTree", { + rmtFactory = await ethers.getContractFactory("RecordsMerkleTree", { libraries: { RescueLib: rescue.address, }, @@ -37,7 +37,7 @@ describe("Records Merkle Tree tests", function () { ]; // Insert all these elements does not trigger an error - let tx = await recordsMerkleTree.testUpdateRecordsMerkleTree(elems); + let tx = await recordsMerkleTree.updateRecordsMerkleTree(elems); await tx.wait(); }); @@ -50,7 +50,7 @@ describe("Records Merkle Tree tests", function () { 26, 27, 28, ]; - await expect(recordsMerkleTree.testUpdateRecordsMerkleTree(elems)).to.be.revertedWith( + await expect(recordsMerkleTree.updateRecordsMerkleTree(elems)).to.be.revertedWith( "The tree is full." ); }); diff --git a/demo/compose.env b/demo/compose.env index a5d74b20..150ef87e 100644 --- a/demo/compose.env +++ b/demo/compose.env @@ -1,7 +1,7 @@ -CAPE_CONTRACT_ADDRESS=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 -CAPE_TOKEN_ADDRESS_SIT=0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 -CAPE_TOKEN_ADDRESS_WETH=0x0165878A594ca255338adfa4d48449f69242Eb8F -CAPE_TOKEN_ADDRESS_DAI=0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 +CAPE_CONTRACT_ADDRESS=0x20Dc424c5fa468CbB1c702308F0cC9c14DA2825C +CAPE_TOKEN_ADDRESS_SIT=0xe6b98F104c1BEf218F3893ADab4160Dc73Eb8367 +CAPE_TOKEN_ADDRESS_WETH=0x5C7c905B505f0Cf40Ab6600d05e677F717916F6B +CAPE_TOKEN_ADDRESS_DAI=0x0D4ff719551E23185Aeb16FFbF2ABEbB90635942 CAPE_ADDRESS_BOOK_PORT=50000 CAPE_EQS_PORT=50010 CAPE_FAUCET_PORT=50030 diff --git a/eqs/src/eth_polling.rs b/eqs/src/eth_polling.rs index 21237348..a2ff6d3d 100644 --- a/eqs/src/eth_polling.rs +++ b/eqs/src/eth_polling.rs @@ -11,7 +11,7 @@ use crate::state_persistence::StatePersistence; use async_std::sync::{Arc, RwLock}; use cap_rust_sandbox::{ - cape::submit_block::fetch_cape_block, + cape::{events::decode_cape_block_from_event, submit_block::fetch_cape_memos}, ethereum::EthConnection, ledger::{CapeTransactionKind, CapeTransition}, model::{CapeModelTxn, Erc20Code, EthereumAddr}, @@ -203,23 +203,21 @@ impl EthPolling { } } match filter { - CAPEEvents::BlockCommittedFilter(_) => { - let fetched_block_with_memos = - fetch_cape_block(&self.connection, meta.transaction_hash) - .await - .unwrap() - .unwrap(); - - let model_txns = fetched_block_with_memos - .block - .clone() + CAPEEvents::BlockCommittedFilter(filter_data) => { + let memos = fetch_cape_memos(&self.connection, meta.transaction_hash) + .await + .unwrap() + .unwrap(); + + let model_txns = decode_cape_block_from_event(filter_data) + .unwrap() .into_cape_transactions() .unwrap() .0; // TODO Instead of panicking here we need to handle cases of missing memos gracefully let num_txn = model_txns.len(); - let num_txn_memo = fetched_block_with_memos.memos.len(); + let num_txn_memo = memos.len(); if num_txn != num_txn_memo { panic!( "Different number of txns and txn memos: {} vs {}", @@ -276,7 +274,7 @@ impl EthPolling { let memos_sig_valid: Vec<_> = model_txns .iter() - .zip(fetched_block_with_memos.memos.iter()) + .zip(memos.iter()) .map(|(tx, (recv_memos, sig))| { match tx { CapeModelTxn::CAP(note) => note.clone(), @@ -298,8 +296,7 @@ impl EthPolling { // Create LedgerEvent::Memos if memo signature is valid, skip otherwise let mut memo_events = Vec::new(); let mut index = 0; - fetched_block_with_memos - .memos + memos .iter() .enumerate() .filter_map(|(txn_id, (txn_memo, _))| match memos_sig_valid[txn_id] { diff --git a/flake.nix b/flake.nix index 27574e2c..6009d222 100644 --- a/flake.nix +++ b/flake.nix @@ -216,8 +216,7 @@ SOLCX_BINARY_PATH = "${mySolc}/bin"; SOLC_VERSION = mySolc.version; SOLC_PATH = "${mySolc}/bin/solc"; - # TODO: increase this when contract size limit is not a problem - SOLC_OPTIMIZER_RUNS = "20"; + SOLC_OPTIMIZER_RUNS = "1000"; shellHook = '' echo "Ensuring node dependencies are installed" @@ -231,7 +230,7 @@ echo "Exporting all vars in .env file" set -a; source .env; set +a; - # on mac os `bin/pwd -P` returns the canonical path on case insenstive file-systems + # on mac os `bin/pwd -P` returns the canonical path on case insensitive file-systems my_pwd=$(/bin/pwd -P 2> /dev/null || pwd) export CONTRACTS_DIR=''${my_pwd}/contracts @@ -265,8 +264,7 @@ SOLCX_BINARY_PATH = "${mySolc}/bin"; SOLC_VERSION = mySolc.version; SOLC_PATH = "${mySolc}/bin/solc"; - # TODO: increase this when contract size limit is not a problem - SOLC_OPTIMIZER_RUNS = "20"; + SOLC_OPTIMIZER_RUNS = "1000"; CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER = "${muslPkgs.llvmPackages_latest.lld}/bin/lld"; RUSTFLAGS = "-C target-feature=+crt-static -L${opensslMusl.out}/lib/"; OPENSSL_STATIC = "true"; @@ -286,7 +284,7 @@ echo "Exporting all vars in .env file" set -a; source .env; set +a; - # on mac os `bin/pwd -P` returns the canonical path on case insenstive file-systems + # on mac os `bin/pwd -P` returns the canonical path on case insensitive file-systems my_pwd=$(/bin/pwd -P 2> /dev/null || pwd) export CONTRACTS_DIR=''${my_pwd}/contracts diff --git a/relayer/README.md b/relayer/README.md index e82c0398..347c5dec 100644 --- a/relayer/README.md +++ b/relayer/README.md @@ -28,5 +28,5 @@ The CAPE contract address shown in the terminal and an Ethereum wallet mnemonic need to be passed to relayer executable, for example: ```console -cargo run --release --bin minimal-relayer -- 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 "$TEST_MNEMONIC" +cargo run --release --bin minimal-relayer -- 0x20Dc424c5fa468CbB1c702308F0cC9c14DA2825C "$TEST_MNEMONIC" ``` diff --git a/relayer/src/lib.rs b/relayer/src/lib.rs index 0c36c8d7..c03f78d1 100644 --- a/relayer/src/lib.rs +++ b/relayer/src/lib.rs @@ -379,6 +379,8 @@ mod test { use super::*; use async_std::sync::{Arc, Mutex}; use cap_rust_sandbox::assertion::{EnsureMined, EnsureRejected}; + use cap_rust_sandbox::cape::RecordsMerkleTreeConstructorArgs; + use cap_rust_sandbox::model::CAPE_MERKLE_HEIGHT; use cap_rust_sandbox::test_utils::upcast_test_cape_to_cape; use cap_rust_sandbox::{ cape::CAPEConstructorArgs, @@ -386,10 +388,10 @@ mod test { ledger::CapeLedger, model::CapeModelTxn, test_utils::contract_abi_path, - types::{GenericInto, CAPE}, + types::CAPE, universal_param::UNIVERSAL_PARAM, }; - use ethers::{prelude::PendingTransaction, providers::Middleware, types::Address}; + use ethers::{prelude::PendingTransaction, providers::Middleware}; use jf_cap::{ keys::UserKeyPair, sign_receiver_memos, @@ -590,8 +592,11 @@ mod test { let hash = response_body::(&mut res).await.unwrap(); let receipt = PendingTransaction::new(hash, &provider); receipt.await.unwrap().ensure_mined(); - assert_eq!(contract.get_num_leaves().call().await.unwrap(), 3.into()); + assert_eq!(contract.get_num_leaves().call().await.unwrap(), 3u64.into()); + // TODO (mathis) check validity of comment below. Should we update test + // to do a sucessful txn? Or is it no longer useful? + // // Test with the non-mock CAPE contract. We can't generate any valid transactions for this // contract, since there's no faucet yet and it doesn't have the // `set_initial_record_commitments` method, but we can at least check that our transaction @@ -605,15 +610,22 @@ mod test { ) .await .unwrap(); + let records_merkle_tree = deploy( + deployer.clone(), + &contract_abi_path("RecordsMerkleTree.sol/RecordsMerkleTree"), + RecordsMerkleTreeConstructorArgs::new(CAPE_MERKLE_HEIGHT).to_tuple(), + ) + .await + .unwrap(); let address = deploy( deployer.clone(), &contract_abi_path("CAPE.sol/CAPE"), CAPEConstructorArgs::new( - CapeLedger::merkle_height(), CapeLedger::record_root_history() as u64, verifier.address(), + records_merkle_tree.address(), ) - .generic_into::<(u8, u64, Address)>(), + .to_tuple(), ) .await .unwrap()