diff --git a/Cargo.lock b/Cargo.lock index 216ba5792ba7..17332cf526e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.5", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -289,28 +300,16 @@ dependencies = [ "radium 0.3.0", ] -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" -dependencies = [ - "funty 1.1.0", - "radium 0.6.2", - "tap", - "wyz 0.2.0", -] - [[package]] name = "bitvec" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" dependencies = [ - "funty 2.0.0", + "funty", "radium 0.7.0", "tap", - "wyz 0.5.0", + "wyz", ] [[package]] @@ -474,7 +473,7 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cast" -version = "0.1.0" +version = "0.2.0" dependencies = [ "chrono 0.2.25", "ethers-core", @@ -689,7 +688,7 @@ dependencies = [ "indenter", "once_cell", "owo-colors", - "tracing-error", + "tracing-error 0.1.2", ] [[package]] @@ -701,7 +700,7 @@ dependencies = [ "once_cell", "owo-colors", "tracing-core", - "tracing-error", + "tracing-error 0.1.2", ] [[package]] @@ -998,17 +997,6 @@ dependencies = [ "const-oid", ] -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "dialoguer" version = "0.8.0" @@ -1184,12 +1172,6 @@ dependencies = [ "syn", ] -[[package]] -name = "environmental" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" - [[package]] name = "eth-keystore" version = "0.4.1" @@ -1237,31 +1219,11 @@ checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" dependencies = [ "crunchy", "fixed-hash", - "impl-codec", "impl-rlp", "impl-serde", - "scale-info", "tiny-keccak", ] -[[package]] -name = "ethereum" -version = "0.12.0" -source = "git+https://github.com/rust-blockchain/ethereum#a9f735271098f9de949dca8a6ac9282592468d21" -dependencies = [ - "bytes", - "ethereum-types", - "hash-db", - "hash256-std-hasher", - "parity-scale-codec 3.0.0", - "rlp", - "rlp-derive", - "scale-info", - "serde", - "sha3 0.10.1", - "triehash", -] - [[package]] name = "ethereum-types" version = "0.13.1" @@ -1270,11 +1232,9 @@ checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" dependencies = [ "ethbloom", "fixed-hash", - "impl-codec", "impl-rlp", "impl-serde", "primitive-types", - "scale-info", "uint", ] @@ -1511,83 +1471,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "evm" -version = "0.33.1" -source = "git+https://github.com/gakonst/evm?branch=bump-primitive-types#7df668d1e53a8ca212fe5fe5362eb9b74839363c" -dependencies = [ - "auto_impl", - "environmental", - "ethereum", - "evm-core", - "evm-gasometer", - "evm-runtime", - "log", - "primitive-types", - "rlp", - "serde", - "sha3 0.8.2", -] - -[[package]] -name = "evm-adapters" -version = "0.1.0" -dependencies = [ - "ansi_term", - "bytes", - "comfy-table", - "ethers", - "ethers-core", - "evm", - "eyre", - "foundry-utils", - "futures", - "hex", - "once_cell", - "parking_lot 0.11.2", - "proptest", - "revm_precompiles", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "evm-core" -version = "0.33.0" -source = "git+https://github.com/gakonst/evm?branch=bump-primitive-types#7df668d1e53a8ca212fe5fe5362eb9b74839363c" -dependencies = [ - "funty 1.1.0", - "parity-scale-codec 2.3.1", - "primitive-types", - "serde", -] - -[[package]] -name = "evm-gasometer" -version = "0.33.0" -source = "git+https://github.com/gakonst/evm?branch=bump-primitive-types#7df668d1e53a8ca212fe5fe5362eb9b74839363c" -dependencies = [ - "environmental", - "evm-core", - "evm-runtime", - "primitive-types", -] - -[[package]] -name = "evm-runtime" -version = "0.33.0" -source = "git+https://github.com/gakonst/evm?branch=bump-primitive-types#7df668d1e53a8ca212fe5fe5362eb9b74839363c" -dependencies = [ - "auto_impl", - "environmental", - "evm-core", - "primitive-types", - "sha3 0.8.2", -] - [[package]] name = "eyre" version = "0.6.7" @@ -1692,15 +1575,16 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "forge" -version = "0.1.0" +version = "0.2.0" dependencies = [ + "comfy-table", "ethers", - "evm", - "evm-adapters", "eyre", + "foundry-evm", "foundry-utils", "glob", "hex", + "once_cell", "proptest", "rayon", "regex", @@ -1710,12 +1594,12 @@ dependencies = [ "serde_json", "tokio", "tracing", - "tracing-subscriber 0.2.25", + "tracing-subscriber 0.3.9", ] [[package]] name = "forge-fmt" -version = "0.1.0" +version = "0.2.0" dependencies = [ "indent_write", "pretty_assertions", @@ -1735,7 +1619,7 @@ dependencies = [ [[package]] name = "foundry-cli" -version = "0.1.0" +version = "0.2.0" dependencies = [ "ansi_term", "atty", @@ -1746,8 +1630,6 @@ dependencies = [ "console 0.15.0", "dunce", "ethers", - "evm", - "evm-adapters", "eyre", "forge", "forge-fmt", @@ -1772,7 +1654,8 @@ dependencies = [ "tokio", "toml", "tracing", - "tracing-subscriber 0.2.25", + "tracing-error 0.2.0", + "tracing-subscriber 0.3.9", "ui", "vergen", "walkdir", @@ -1793,7 +1676,7 @@ dependencies = [ [[package]] name = "foundry-config" -version = "0.1.0" +version = "0.2.0" dependencies = [ "Inflector", "dirs-next", @@ -1802,15 +1685,43 @@ dependencies = [ "eyre", "figment", "pretty_assertions", + "regex", "semver", "serde", "serde_json", "toml", ] +[[package]] +name = "foundry-evm" +version = "0.2.0" +dependencies = [ + "ansi_term", + "bytes", + "ethers", + "eyre", + "foundry-utils", + "futures", + "hashbrown 0.12.0", + "hex", + "once_cell", + "parking_lot 0.12.0", + "proptest", + "revm", + "serde", + "serde_json", + "tempfile", + "thiserror", + "tokio", + "tracing", + "tracing-error 0.2.0", + "tracing-subscriber 0.3.9", + "url", +] + [[package]] name = "foundry-utils" -version = "0.1.0" +version = "0.2.0" dependencies = [ "ethers", "ethers-addressbook", @@ -1844,12 +1755,6 @@ dependencies = [ "libc", ] -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "funty" version = "2.0.0" @@ -2075,26 +1980,20 @@ dependencies = [ ] [[package]] -name = "hash-db" -version = "0.15.2" +name = "hashbrown" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] -name = "hash256-std-hasher" -version = "0.15.2" +name = "hashbrown" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" dependencies = [ - "crunchy", + "ahash", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - [[package]] name = "heck" version = "0.3.3" @@ -2124,6 +2023,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hidapi-rusb" @@ -2284,7 +2186,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", ] [[package]] @@ -2335,7 +2237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", ] [[package]] @@ -2568,15 +2470,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "matchers" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" -dependencies = [ - "regex-automata", -] - [[package]] name = "matchers" version = "0.1.0" @@ -2891,6 +2784,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -2983,49 +2897,23 @@ checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" [[package]] name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec 0.7.2", - "bitvec 0.20.4", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 2.3.1", - "serde", -] - -[[package]] -name = "parity-scale-codec" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a7f3fcf5e45fc28b84dcdab6b983e77f197ec01f325a33f404ba6855afd1070" +checksum = "8483b84fb12de1dc23bf95d26030d16cea56391d136db0db37f749508104e3e6" dependencies = [ "arrayvec 0.7.2", "bitvec 1.0.0", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive 3.0.0", + "parity-scale-codec-derive", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6e626dc84025ff56bf1476ed0e30d10c84d7f89a475ef46ebabee1095a8fba" +checksum = "7259388ceb4c23bc09caef272c9e7a732b3b8f9fbd0b41f0009a91d6548cc1d9" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3348,7 +3236,6 @@ dependencies = [ "impl-codec", "impl-rlp", "impl-serde", - "scale-info", "uint", ] @@ -3467,12 +3354,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - [[package]] name = "radium" version = "0.7.0" @@ -3689,10 +3570,28 @@ dependencies = [ "winreg", ] +[[package]] +name = "revm" +version = "1.2.0" +source = "git+https://github.com/bluealloy/revm#0437dcdc658f8a950e4c652d587d266a4bec35ff" +dependencies = [ + "arrayref", + "auto_impl", + "bytes", + "hashbrown 0.12.0", + "hex", + "num_enum", + "primitive-types", + "revm_precompiles", + "rlp", + "serde", + "sha3 0.10.1", +] + [[package]] name = "revm_precompiles" version = "0.4.0" -source = "git+https://github.com/bluealloy/revm#858ae0837657ee446ef422032969b00a0ce0c8be" +source = "git+https://github.com/bluealloy/revm#0437dcdc658f8a950e4c652d587d266a4bec35ff" dependencies = [ "bytes", "k256", @@ -3875,31 +3774,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scale-info" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0563970d79bcbf3c537ce3ad36d859b30d36fc5b190efd227f1f7a84d7cf0d42" -dependencies = [ - "bitvec 1.0.0", - "cfg-if 1.0.0", - "derive_more", - "parity-scale-codec 3.0.0", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7805950c36512db9e3251c970bb7ac425f326716941862205d612ab3b5e46e2" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "schannel" version = "0.1.19" @@ -4100,19 +3974,6 @@ dependencies = [ "cc", ] -[[package]] -name = "sha3" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -dependencies = [ - "block-buffer 0.7.3", - "byte-tools", - "digest 0.8.1", - "keccak", - "opaque-debug 0.2.3", -] - [[package]] name = "sha3" version = "0.9.1" @@ -4652,6 +4513,16 @@ dependencies = [ "tracing-subscriber 0.2.25", ] +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber 0.3.9", +] + [[package]] name = "tracing-futures" version = "0.2.5" @@ -4673,36 +4544,15 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - [[package]] name = "tracing-subscriber" version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ - "ansi_term", - "chrono 0.4.19", - "lazy_static", - "matchers 0.0.1", - "regex", - "serde", - "serde_json", "sharded-slab", - "smallvec", "thread_local", - "tracing", "tracing-core", - "tracing-log", - "tracing-serde", ] [[package]] @@ -4711,13 +4561,16 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce" dependencies = [ + "ansi_term", "lazy_static", - "matchers 0.1.0", + "matchers", "regex", "sharded-slab", + "smallvec", "thread_local", "tracing", "tracing-core", + "tracing-log", ] [[package]] @@ -4735,16 +4588,6 @@ dependencies = [ "rusb", ] -[[package]] -name = "triehash" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1631b201eb031b563d2e85ca18ec8092508e262a3196ce9bd10a67ec87b9f5c" -dependencies = [ - "hash-db", - "rlp", -] - [[package]] name = "try-lock" version = "0.2.3" @@ -4794,12 +4637,12 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ui" -version = "0.1.0" +version = "0.2.0" dependencies = [ "crossterm 0.22.1", "ethers", - "evm-adapters", "eyre", + "forge", "hex", "tui", ] @@ -5241,12 +5084,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "wyz" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index a01019069676..859f67895514 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "evm-adapters", "utils", "cast", "forge", @@ -8,6 +7,8 @@ members = [ "cli/test-utils", "config", "fmt", + "ui", + "evm" ] [profile.test] @@ -27,11 +28,6 @@ panic = "abort" # We end up stripping away these symbols anyway debug = 0 -## Patch sputnik with more recent primitive types -# https://github.com/rust-blockchain/evm/pulls -[patch."https://github.com/rust-blockchain/evm"] -evm = { git = "https://github.com/gakonst/evm", branch = "bump-primitive-types" } - ## Patch ethers-rs with a local checkout then run `cargo update -p ethers` #[patch."https://github.com/gakonst/ethers-rs"] #ethers = { path = "../ethers-rs" } diff --git a/cast/Cargo.toml b/cast/Cargo.toml index 2ea38ea4153c..f23b98eece04 100644 --- a/cast/Cargo.toml +++ b/cast/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cast" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a3748e9468ee..30fceb2941ec 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "foundry-cli" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" @@ -26,7 +26,6 @@ foundry-utils = { path = "../utils" } forge = { path = "../forge" } foundry-config = { path = "../config" } cast = { path = "../cast" } -evm-adapters = { path = "../evm-adapters" } ui = { path = "../ui" } dunce = "1.0.2" # ethers = "0.5" @@ -39,16 +38,14 @@ tokio = { version = "1.11.0", features = ["macros"] } regex = { version = "1.5.4", default-features = false } ansi_term = "0.12.1" rpassword = "5.0.1" -tracing-subscriber = "0.2.20" +tracing-error = "0.2.0" +tracing-subscriber = { version = "0.3", features = ["registry", "env-filter", "fmt"] } tracing = "0.1.26" hex = "0.4.3" rayon = "1.5.1" serde = "1.0.133" futures = "0.3.17" -## EVM Implementations -# evm = { version = "0.30.1" } -sputnik = { package = "evm", git = "https://github.com/rust-blockchain/evm", default-features = false, features = ["std"], optional = true } proptest = "1.0.0" glob = "0.3.0" semver = "1.0.5" @@ -67,17 +64,11 @@ pretty_assertions = "1.0.0" toml = "0.5" [features] -default = ["sputnik-evm", "rustls"] +default = ["rustls"] solc-asm = ["ethers/solc-sha2-asm"] rustls = ["ethers/rustls"] openssl = ["ethers/openssl"] -sputnik-evm = [ - "sputnik", - "evm-adapters/sputnik", - "evm-adapters/sputnik-helpers", -] - integration-tests = [] [[bin]] diff --git a/cli/src/cast.rs b/cli/src/cast.rs index 103f2aa5bea3..5c8c82211e6c 100644 --- a/cli/src/cast.rs +++ b/cli/src/cast.rs @@ -15,7 +15,7 @@ use ethers::{ }, providers::{Middleware, Provider}, signers::{LocalWallet, Signer}, - types::{Address, Chain, NameOrAddress, Signature, U256, U64}, + types::{Address, Chain, NameOrAddress, Signature, U256}, utils::get_contract_address, }; use opts::{ @@ -36,9 +36,8 @@ use std::{ use clap::{IntoApp, Parser}; use clap_complete::generate; -use crate::utils::read_secret; +use crate::{cmd::Cmd, utils::read_secret}; use eyre::WrapErr; -use futures::join; #[tokio::main] async fn main() -> eyre::Result<()> { @@ -542,64 +541,7 @@ async fn main() -> eyre::Result<()> { let selector = contract.abi().functions().last().unwrap().short_signature(); println!("0x{}", hex::encode(selector)); } - Subcommands::FindBlock { timestamp, rpc_url } => { - let ts_target = U256::from(timestamp); - let provider = Provider::try_from(rpc_url)?; - let last_block_num = provider.get_block_number().await?; - let cast_provider = Cast::new(provider); - - let res = join!(cast_provider.timestamp(last_block_num), cast_provider.timestamp(1)); - let ts_block_latest = res.0.unwrap(); - let ts_block_1 = res.1.unwrap(); - - let block_num = if ts_block_latest.lt(&ts_target) { - // If the most recent block's timestamp is below the target, return it - last_block_num - } else if ts_block_1.gt(&ts_target) { - // If the target timestamp is below block 1's timestamp, return that - U64::from(1) - } else { - // Otherwise, find the block that is closest to the timestamp - let mut low_block = U64::from(1); // block 0 has a timestamp of 0: https://github.com/ethereum/go-ethereum/issues/17042#issuecomment-559414137 - let mut high_block = last_block_num; - let mut matching_block: Option = None; - while high_block.gt(&low_block) && matching_block.is_none() { - // Get timestamp of middle block (this approach approach to avoids overflow) - let high_minus_low_over_2 = high_block - .checked_sub(low_block) - .ok_or_else(|| eyre::eyre!("unexpected underflow")) - .unwrap() - .checked_div(U64::from(2)) - .unwrap(); - let mid_block = high_block.checked_sub(high_minus_low_over_2).unwrap(); - let ts_mid_block = cast_provider.timestamp(mid_block).await?; - - // Check if we've found a match or should keep searching - if ts_mid_block.eq(&ts_target) { - matching_block = Some(mid_block) - } else if high_block.checked_sub(low_block).unwrap().eq(&U64::from(1)) { - // The target timestamp is in between these blocks. This rounds to the - // highest block if timestamp is equidistant between blocks - let res = join!( - cast_provider.timestamp(high_block), - cast_provider.timestamp(low_block) - ); - let ts_high = res.0.unwrap(); - let ts_low = res.1.unwrap(); - let high_diff = ts_high.checked_sub(ts_target).unwrap(); - let low_diff = ts_target.checked_sub(ts_low).unwrap(); - let is_low = low_diff.lt(&high_diff); - matching_block = if is_low { Some(low_block) } else { Some(high_block) } - } else if ts_mid_block.lt(&ts_target) { - low_block = mid_block; - } else { - high_block = mid_block; - } - } - matching_block.unwrap_or(low_block) - }; - println!("{}", block_num); - } + Subcommands::FindBlock(cmd) => cmd.run()?, Subcommands::Wallet { command } => match command { WalletSubcommands::New { path, password, unsafe_password } => { let mut rng = thread_rng(); diff --git a/cli/src/cmd/cast/find_block.rs b/cli/src/cmd/cast/find_block.rs new file mode 100644 index 000000000000..8daf2d4bb0bd --- /dev/null +++ b/cli/src/cmd/cast/find_block.rs @@ -0,0 +1,90 @@ +//! cast find-block subcommand + +use crate::cmd::Cmd; +use cast::Cast; +use clap::Parser; +use ethers::prelude::*; +use eyre::Result; +use futures::join; + +#[derive(Debug, Clone, Parser)] +pub struct FindBlockArgs { + #[clap(help = "The UNIX timestamp to search for (in seconds)")] + timestamp: u64, + #[clap(long, env = "ETH_RPC_URL")] + rpc_url: String, +} + +impl Cmd for FindBlockArgs { + type Output = (); + + fn run(self) -> Result { + let FindBlockArgs { timestamp, rpc_url } = self; + let rt = tokio::runtime::Runtime::new().expect("could not start tokio rt"); + rt.block_on(Self::query_block(timestamp, rpc_url))?; + Ok(()) + } +} + +impl FindBlockArgs { + async fn query_block(timestamp: u64, rpc_url: String) -> Result<()> { + let ts_target = U256::from(timestamp); + let provider = Provider::try_from(rpc_url)?; + let last_block_num = provider.get_block_number().await?; + let cast_provider = Cast::new(provider); + + let res = join!(cast_provider.timestamp(last_block_num), cast_provider.timestamp(1)); + let ts_block_latest = res.0.unwrap(); + let ts_block_1 = res.1.unwrap(); + + let block_num = if ts_block_latest.lt(&ts_target) { + // If the most recent block's timestamp is below the target, return it + last_block_num + } else if ts_block_1.gt(&ts_target) { + // If the target timestamp is below block 1's timestamp, return that + U64::from(1_u64) + } else { + // Otherwise, find the block that is closest to the timestamp + let mut low_block = U64::from(1_u64); // block 0 has a timestamp of 0: https://github.com/ethereum/go-ethereum/issues/17042#issuecomment-559414137 + let mut high_block = last_block_num; + let mut matching_block: Option = None; + while high_block.gt(&low_block) && matching_block.is_none() { + // Get timestamp of middle block (this approach approach to avoids overflow) + let high_minus_low_over_2 = high_block + .checked_sub(low_block) + .ok_or_else(|| eyre::eyre!("unexpected underflow")) + .unwrap() + .checked_div(U64::from(2_u64)) + .unwrap(); + let mid_block = high_block.checked_sub(high_minus_low_over_2).unwrap(); + let ts_mid_block = cast_provider.timestamp(mid_block).await?; + + // Check if we've found a match or should keep searching + if ts_mid_block.eq(&ts_target) { + matching_block = Some(mid_block) + } else if high_block.checked_sub(low_block).unwrap().eq(&U64::from(1_u64)) { + // The target timestamp is in between these blocks. This rounds to the + // highest block if timestamp is equidistant between blocks + let res = join!( + cast_provider.timestamp(high_block), + cast_provider.timestamp(low_block) + ); + let ts_high = res.0.unwrap(); + let ts_low = res.1.unwrap(); + let high_diff = ts_high.checked_sub(ts_target).unwrap(); + let low_diff = ts_target.checked_sub(ts_low).unwrap(); + let is_low = low_diff.lt(&high_diff); + matching_block = if is_low { Some(low_block) } else { Some(high_block) } + } else if ts_mid_block.lt(&ts_target) { + low_block = mid_block; + } else { + high_block = mid_block; + } + } + matching_block.unwrap_or(low_block) + }; + println!("{}", block_num); + + Ok(()) + } +} diff --git a/cli/src/cmd/cast/mod.rs b/cli/src/cmd/cast/mod.rs new file mode 100644 index 000000000000..3799246cfede --- /dev/null +++ b/cli/src/cmd/cast/mod.rs @@ -0,0 +1,8 @@ +//! Subcommands for cast +//! +//! All subcommands should respect the `foundry_config::Config`. +//! If a subcommand accepts values that are supported by the `Config`, then the subcommand should +//! implement `figment::Provider` which allows the subcommand to override the config's defaults, see +//! [`foundry_config::Config`]. + +pub mod find_block; diff --git a/cli/src/cmd/bind.rs b/cli/src/cmd/forge/bind.rs similarity index 99% rename from cli/src/cmd/bind.rs rename to cli/src/cmd/forge/bind.rs index 73cf6783d2d3..4956d46025d3 100644 --- a/cli/src/cmd/bind.rs +++ b/cli/src/cmd/forge/bind.rs @@ -1,4 +1,4 @@ -use crate::cmd::Cmd; +use crate::cmd::utils::Cmd; use clap::{Parser, ValueHint}; use ethers::contract::MultiAbigen; diff --git a/cli/src/cmd/build.rs b/cli/src/cmd/forge/build.rs similarity index 98% rename from cli/src/cmd/build.rs rename to cli/src/cmd/forge/build.rs index bf6d5155c778..e47b58745a36 100644 --- a/cli/src/cmd/build.rs +++ b/cli/src/cmd/forge/build.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use crate::{cmd::Cmd, opts::forge::CompilerArgs}; -use crate::cmd::watch::WatchArgs; +use crate::cmd::forge::watch::WatchArgs; use clap::{Parser, ValueHint}; use ethers::solc::remappings::Remapping; use foundry_config::{ @@ -191,7 +191,7 @@ impl Cmd for BuildArgs { type Output = ProjectCompileOutput; fn run(self) -> eyre::Result { let project = self.project()?; - super::compile(&project, self.names, self.sizes) + crate::cmd::utils::compile(&project, self.names, self.sizes) } } @@ -214,7 +214,7 @@ impl BuildArgs { /// Returns the [`watchexec::InitConfig`] and [`watchexec::RuntimeConfig`] necessary to /// bootstrap a new [`watchexe::Watchexec`] loop. pub(crate) fn watchexec_config(&self) -> eyre::Result<(InitConfig, RuntimeConfig)> { - use crate::cmd::watch; + use crate::cmd::forge::watch; let init = watch::init()?; let mut runtime = watch::runtime(&self.watch)?; diff --git a/cli/src/cmd/config.rs b/cli/src/cmd/forge/config.rs similarity index 96% rename from cli/src/cmd/config.rs rename to cli/src/cmd/forge/config.rs index 060c33376520..05ef67e5755e 100644 --- a/cli/src/cmd/config.rs +++ b/cli/src/cmd/forge/config.rs @@ -1,7 +1,7 @@ //! config command use crate::{ - cmd::{build::BuildArgs, Cmd}, + cmd::{forge::build::BuildArgs, utils::Cmd}, opts::evm::EvmArgs, }; use clap::Parser; diff --git a/cli/src/cmd/create.rs b/cli/src/cmd/forge/create.rs similarity index 96% rename from cli/src/cmd/create.rs rename to cli/src/cmd/forge/create.rs index a4bfa51a2463..fd4c9e1147f1 100644 --- a/cli/src/cmd/create.rs +++ b/cli/src/cmd/forge/create.rs @@ -1,7 +1,7 @@ //! Create command use crate::{ - cmd::{build::BuildArgs, Cmd}, + cmd::{forge::build::BuildArgs, Cmd}, opts::{EthereumOpts, WalletType}, utils::parse_u256, }; @@ -70,10 +70,11 @@ impl Cmd for CreateArgs { fn run(self) -> Result { // Find Project & Compile let project = self.opts.project()?; - let compiled = super::compile(&project, self.opts.names, self.opts.sizes)?; + let compiled = crate::cmd::utils::compile(&project, self.opts.names, self.opts.sizes)?; // Get ABI and BIN - let (abi, bin, _) = super::read_artifact(&project, compiled, self.contract.clone())?; + let (abi, bin, _) = + crate::cmd::utils::read_artifact(&project, compiled, self.contract.clone())?; let bin = match bin.object { BytecodeObject::Bytecode(_) => bin.object, diff --git a/cli/src/cmd/flatten.rs b/cli/src/cmd/forge/flatten.rs similarity index 98% rename from cli/src/cmd/flatten.rs rename to cli/src/cmd/forge/flatten.rs index b0dae09561a4..c56668f70a52 100644 --- a/cli/src/cmd/flatten.rs +++ b/cli/src/cmd/forge/flatten.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use ethers::solc::remappings::Remapping; -use crate::cmd::{build::BuildArgs, Cmd}; +use crate::cmd::{forge::build::BuildArgs, Cmd}; use clap::{Parser, ValueHint}; use foundry_config::Config; diff --git a/cli/src/cmd/fmt.rs b/cli/src/cmd/forge/fmt.rs similarity index 100% rename from cli/src/cmd/fmt.rs rename to cli/src/cmd/forge/fmt.rs diff --git a/cli/src/cmd/init.rs b/cli/src/cmd/forge/init.rs similarity index 95% rename from cli/src/cmd/init.rs rename to cli/src/cmd/forge/init.rs index 02c6e7c65abb..4e8aabdd3f3d 100644 --- a/cli/src/cmd/init.rs +++ b/cli/src/cmd/forge/init.rs @@ -1,14 +1,14 @@ //! init command use crate::{ - cmd::{install::install, Cmd}, + cmd::{forge::install::install, Cmd}, opts::forge::Dependency, utils::p_println, }; use clap::{Parser, ValueHint}; use foundry_config::Config; -use crate::cmd::{install::DependencyInstallOpts, remappings}; +use crate::cmd::forge::{install::DependencyInstallOpts, remappings}; use ansi_term::Colour; use ethers::solc::remappings::Remapping; use std::{ @@ -102,10 +102,13 @@ impl Cmd for InitArgs { // write the contract file let contract_path = src.join("Contract.sol"); - std::fs::write(contract_path, include_str!("../../../assets/ContractTemplate.sol"))?; + std::fs::write(contract_path, include_str!("../../../../assets/ContractTemplate.sol"))?; // write the tests let contract_path = test.join("Contract.t.sol"); - std::fs::write(contract_path, include_str!("../../../assets/ContractTemplate.t.sol"))?; + std::fs::write( + contract_path, + include_str!("../../../../assets/ContractTemplate.t.sol"), + )?; let dest = root.join(Config::FILE_NAME); if !dest.exists() { @@ -159,7 +162,7 @@ fn init_git_repo(root: &Path, no_commit: bool) -> eyre::Result<()> { if !is_git.success() { let gitignore_path = root.join(".gitignore"); - std::fs::write(gitignore_path, include_str!("../../../assets/.gitignoreTemplate"))?; + std::fs::write(gitignore_path, include_str!("../../../../assets/.gitignoreTemplate"))?; Command::new("git") .arg("init") diff --git a/cli/src/cmd/inspect.rs b/cli/src/cmd/forge/inspect.rs similarity index 98% rename from cli/src/cmd/inspect.rs rename to cli/src/cmd/forge/inspect.rs index aa9c80905880..3a6c01db28e9 100644 --- a/cli/src/cmd/inspect.rs +++ b/cli/src/cmd/forge/inspect.rs @@ -2,7 +2,7 @@ use std::{fmt, str::FromStr}; use crate::{ cmd::{ - build::{self, BuildArgs}, + forge::build::{self, BuildArgs}, Cmd, }, opts::forge::CompilerArgs, @@ -156,7 +156,7 @@ impl Cmd for InspectArgs { // Build the project let project = modified_build_args.project()?; - let outcome = super::suppress_compile(&project)?; + let outcome = super::super::suppress_compile(&project)?; // Find the artifact let found_artifact = outcome.find(&contract); diff --git a/cli/src/cmd/install.rs b/cli/src/cmd/forge/install.rs similarity index 100% rename from cli/src/cmd/install.rs rename to cli/src/cmd/forge/install.rs diff --git a/cli/src/cmd/forge/mod.rs b/cli/src/cmd/forge/mod.rs new file mode 100644 index 000000000000..6f0cf893d46b --- /dev/null +++ b/cli/src/cmd/forge/mod.rs @@ -0,0 +1,55 @@ +//! Subcommands for forge +//! +//! All subcommands should respect the `foundry_config::Config`. +//! If a subcommand accepts values that are supported by the `Config`, then the subcommand should +//! implement `figment::Provider` which allows the subcommand to override the config's defaults, see +//! [`foundry_config::Config`]. +//! +//! See [`BuildArgs`] for a reference implementation. +//! And [`RunArgs`] for how to merge `Providers`. +//! +//! # Example +//! +//! create a `clap` subcommand into a `figment::Provider` and integrate it in the +//! `foundry_config::Config`: +//! +//! ```rust +//! use crate::{cmd::build::BuildArgs, opts::evm::EvmArgs}; +//! use clap::Parser; +//! use foundry_config::{figment::Figment, *}; +//! +//! // A new clap subcommand that accepts both `EvmArgs` and `BuildArgs` +//! #[derive(Debug, Clone, Parser)] +//! pub struct MyArgs { +//! #[clap(flatten)] +//! evm_opts: EvmArgs, +//! #[clap(flatten)] +//! opts: BuildArgs, +//! } +//! +//! // add `Figment` and `Config` converters +//! foundry_config::impl_figment_convert!(MyArgs, opts, evm_opts); +//! let args = MyArgs::parse_from(["build"]); +//! +//! let figment: Figment = From::from(&args); +//! let evm_opts = figment.extract::().unwrap(); +//! +//! let config: Config = From::from(&args); +//! ``` + +pub mod bind; +pub mod build; +pub mod config; +pub mod create; +pub mod flatten; +pub mod fmt; +pub mod init; +pub mod inspect; +pub mod install; +pub mod remappings; +pub mod run; +pub mod snapshot; +pub mod test; +pub mod tree; +pub mod verify; +pub mod watch; diff --git a/cli/src/cmd/remappings.rs b/cli/src/cmd/forge/remappings.rs similarity index 100% rename from cli/src/cmd/remappings.rs rename to cli/src/cmd/forge/remappings.rs diff --git a/cli/src/cmd/forge/run.rs b/cli/src/cmd/forge/run.rs new file mode 100644 index 000000000000..931be7beb41e --- /dev/null +++ b/cli/src/cmd/forge/run.rs @@ -0,0 +1,441 @@ +use crate::{ + cmd::{compile_files, forge::build::BuildArgs, Cmd}, + opts::evm::EvmArgs, + utils, +}; +use ansi_term::Colour; +use clap::{Parser, ValueHint}; +use ethers::{ + abi::{Abi, RawLog}, + solc::{ + artifacts::{CompactContractBytecode, ContractBytecode, ContractBytecodeSome}, + Project, + }, + types::{Address, Bytes, U256}, +}; +use forge::{ + debug::DebugArena, + decode::decode_console_logs, + executor::{ + opts::EvmOpts, CallResult, DatabaseRef, DeployResult, EvmError, Executor, ExecutorBuilder, + RawCallResult, + }, + trace::{identifier::LocalTraceIdentifier, CallTraceArena, CallTraceDecoder, TraceKind}, + CALLER, +}; +use foundry_config::{figment::Figment, Config}; +use foundry_utils::{encode_args, IntoFunction, PostLinkInput}; +use std::{collections::BTreeMap, path::PathBuf}; +use ui::{TUIExitReason, Tui, Ui}; + +// Loads project's figment and merges the build cli arguments into it +foundry_config::impl_figment_convert!(RunArgs, opts, evm_opts); + +#[derive(Debug, Clone, Parser)] +pub struct RunArgs { + /// The path of the contract to run. + /// + /// If multiple contracts exist in the same file you must specify the target contract with + /// --target-contract. + #[clap(value_hint = ValueHint::FilePath)] + pub path: PathBuf, + + /// Arguments to pass to the script function. + pub args: Vec, + + /// The name of the contract you want to run. + #[clap(long, short)] + pub target_contract: Option, + + /// The signature of the function you want to call in the contract, or raw calldata. + #[clap(long, short, default_value = "run()")] + pub sig: String, + + /// Open the script in the debugger. + #[clap(long)] + pub debug: bool, + + #[clap(flatten, next_help_heading = "BUILD OPTIONS")] + pub opts: BuildArgs, + + #[clap(flatten, next_help_heading = "EVM OPTIONS")] + pub evm_opts: EvmArgs, +} + +impl Cmd for RunArgs { + type Output = (); + fn run(self) -> eyre::Result { + let figment: Figment = From::from(&self); + let evm_opts = figment.extract::()?; + let verbosity = evm_opts.verbosity; + let config = Config::from_provider(figment).sanitized(); + + let BuildOutput { + project, + contract, + highlevel_known_contracts, + sources, + predeploy_libraries, + } = self.build(&config, &evm_opts)?; + + let known_contracts = highlevel_known_contracts + .iter() + .map(|(name, c)| { + ( + name.clone(), + ( + c.abi.clone(), + c.deployed_bytecode.clone().into_bytes().expect("not bytecode").to_vec(), + ), + ) + }) + .collect::)>>(); + + let CompactContractBytecode { abi, bytecode, .. } = contract; + let abi = abi.expect("no ABI for contract"); + let bytecode = bytecode.expect("no bytecode for contract").object.into_bytes().unwrap(); + let needs_setup = abi.functions().any(|func| func.name == "setUp"); + + let mut builder = ExecutorBuilder::new() + .with_cheatcodes(evm_opts.ffi) + .with_config(evm_opts.evm_env()) + .with_spec(crate::utils::evm_spec(&config.evm_version)) + .with_fork(utils::get_fork(&evm_opts, &config.rpc_storage_caching)); + if verbosity >= 3 { + builder = builder.with_tracing(); + } + if self.debug { + builder = builder.with_tracing().with_debugger(); + } + + let mut result = { + let mut runner = + Runner::new(builder.build(), evm_opts.initial_balance, evm_opts.sender); + let (address, mut result) = + runner.setup(&predeploy_libraries, bytecode, needs_setup)?; + + let RunResult { + success, gas, logs, traces, debug: run_debug, labeled_addresses, .. + } = runner.run( + address, + if let Some(calldata) = self.sig.strip_prefix("0x") { + hex::decode(calldata)?.into() + } else { + encode_args(&IntoFunction::into(self.sig), &self.args)?.into() + }, + )?; + + result.success &= success; + + result.gas = gas; + result.logs.extend(logs); + result.traces.extend(traces); + result.debug = run_debug; + result.labeled_addresses.extend(labeled_addresses); + + result + }; + + // Identify addresses in each trace + let local_identifier = LocalTraceIdentifier::new(&known_contracts); + let mut decoder = CallTraceDecoder::new_with_labels(result.labeled_addresses.clone()); + for (_, trace) in &mut result.traces { + decoder.identify(trace, &local_identifier); + } + + if self.debug { + let source_code: BTreeMap = sources + .iter() + .map(|(id, path)| { + let resolved = project + .paths + .resolve_library_import(&PathBuf::from(path)) + .unwrap_or_else(|| PathBuf::from(path)); + ( + *id, + std::fs::read_to_string(resolved).expect(&*format!( + "Something went wrong reading the source file: {:?}", + path + )), + ) + }) + .collect(); + + let calls: Vec = result.debug.expect("we should have collected debug info"); + let flattened = calls.last().expect("we should have collected debug info").flatten(0); + let tui = + Tui::new(flattened, 0, decoder.contracts, highlevel_known_contracts, source_code)?; + match tui.start().expect("Failed to start tui") { + TUIExitReason::CharExit => return Ok(()), + } + } else { + if verbosity >= 3 { + if result.traces.is_empty() { + eyre::bail!("Unexpected error: No traces despite verbosity level. Please report this as a bug: https://github.com/gakonst/foundry/issues/new?assignees=&labels=T-bug&template=BUG-FORM.yml"); + } + + if !result.success && verbosity == 3 || verbosity > 3 { + println!("Traces:"); + for (kind, trace) in &mut result.traces { + let should_include = match kind { + TraceKind::Setup => { + (verbosity >= 5) || (verbosity == 4 && !result.success) + } + TraceKind::Execution => verbosity > 3 || !result.success, + _ => false, + }; + + if should_include { + decoder.decode(trace); + println!("{}", trace); + } + } + println!(); + } + } + + if result.success { + println!("{}", Colour::Green.paint("Script ran successfully.")); + } else { + println!("{}", Colour::Red.paint("Script failed.")); + } + + println!("Gas used: {}", result.gas); + println!("== Logs =="); + let console_logs = decode_console_logs(&result.logs); + if !console_logs.is_empty() { + for log in console_logs { + println!(" {}", log); + } + } + } + Ok(()) + } +} + +struct ExtraLinkingInfo<'a> { + no_target_name: bool, + target_fname: String, + contract: &'a mut CompactContractBytecode, + dependencies: &'a mut Vec, + matched: bool, +} + +pub struct BuildOutput { + pub project: Project, + pub contract: CompactContractBytecode, + pub highlevel_known_contracts: BTreeMap, + pub sources: BTreeMap, + pub predeploy_libraries: Vec, +} + +impl RunArgs { + /// Compiles the file with auto-detection and compiler params. + pub fn build(&self, config: &Config, evm_opts: &EvmOpts) -> eyre::Result { + let target_contract = dunce::canonicalize(&self.path)?; + let project = config.ephemeral_no_artifacts_project()?; + let output = compile_files(&project, vec![target_contract])?; + + let (sources, all_contracts) = output.output().split(); + + let contracts: BTreeMap = all_contracts + .contracts_with_files() + .map(|(file, name, contract)| (format!("{}:{}", file, name), contract.clone().into())) + .collect(); + + let mut run_dependencies = vec![]; + let mut contract = + CompactContractBytecode { abi: None, bytecode: None, deployed_bytecode: None }; + let mut highlevel_known_contracts = BTreeMap::new(); + + let mut target_fname = dunce::canonicalize(&self.path) + .expect("Couldn't convert contract path to absolute path") + .to_str() + .expect("Bad path to string") + .to_string(); + + let no_target_name = if let Some(target_name) = &self.target_contract { + target_fname = target_fname + ":" + target_name; + false + } else { + true + }; + + foundry_utils::link( + &contracts, + &mut highlevel_known_contracts, + evm_opts.sender, + &mut ExtraLinkingInfo { + no_target_name, + target_fname, + contract: &mut contract, + dependencies: &mut run_dependencies, + matched: false, + }, + |file, key| (format!("{}:{}", file, key), file, key), + |post_link_input| { + let PostLinkInput { + contract, + known_contracts: highlevel_known_contracts, + fname, + extra, + dependencies, + } = post_link_input; + let split = fname.split(':').collect::>(); + + // if its the target contract, grab the info + if extra.no_target_name && split[0] == extra.target_fname { + if extra.matched { + eyre::bail!("Multiple contracts in the target path. Please specify the contract name with `-t ContractName`") + } + *extra.dependencies = dependencies; + *extra.contract = contract.clone(); + extra.matched = true; + } else if extra.target_fname == fname { + *extra.dependencies = dependencies; + *extra.contract = contract.clone(); + extra.matched = true; + } + + let tc: ContractBytecode = contract.into(); + let contract_name = if split.len() > 1 { split[1] } else { split[0] }; + highlevel_known_contracts.insert(contract_name.to_string(), tc.unwrap()); + Ok(()) + }, + )?; + + Ok(BuildOutput { + project, + contract, + highlevel_known_contracts, + sources: sources.into_ids().collect(), + predeploy_libraries: run_dependencies, + }) + } +} + +struct RunResult { + pub success: bool, + pub logs: Vec, + pub traces: Vec<(TraceKind, CallTraceArena)>, + pub debug: Option>, + pub gas: u64, + pub labeled_addresses: BTreeMap, +} + +struct Runner { + pub executor: Executor, + pub initial_balance: U256, + pub sender: Address, +} + +impl Runner { + pub fn new(executor: Executor, initial_balance: U256, sender: Address) -> Self { + Self { executor, initial_balance, sender } + } + + pub fn setup( + &mut self, + libraries: &[Bytes], + code: Bytes, + setup: bool, + ) -> eyre::Result<(Address, RunResult)> { + // We max out their balance so that they can deploy and make calls. + self.executor.set_balance(self.sender, U256::MAX); + self.executor.set_balance(*CALLER, U256::MAX); + + // We set the nonce of the deployer accounts to 1 to get the same addresses as DappTools + self.executor.set_nonce(self.sender, 1); + + // Deploy libraries + let mut traces: Vec<(TraceKind, CallTraceArena)> = libraries + .iter() + .filter_map(|code| { + let DeployResult { traces, .. } = self + .executor + .deploy(self.sender, code.0.clone(), 0u32.into()) + .expect("couldn't deploy library"); + + traces + }) + .map(|traces| (TraceKind::Deployment, traces)) + .collect(); + + // Deploy an instance of the contract + let DeployResult { + address, + mut logs, + traces: constructor_traces, + debug: constructor_debug, + .. + } = self.executor.deploy(self.sender, code.0, 0u32.into()).expect("couldn't deploy"); + traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces)).into_iter()); + self.executor.set_balance(address, self.initial_balance); + + // Optionally call the `setUp` function + Ok(if setup { + match self.executor.setup(address) { + Ok(CallResult { + reverted, + traces: setup_traces, + labels, + logs: setup_logs, + debug, + gas, + .. + }) | + Err(EvmError::Execution { + reverted, + traces: setup_traces, + labels, + logs: setup_logs, + debug, + gas, + .. + }) => { + traces + .extend(setup_traces.map(|traces| (TraceKind::Setup, traces)).into_iter()); + logs.extend_from_slice(&setup_logs); + + ( + address, + RunResult { + logs, + traces, + labeled_addresses: labels, + success: !reverted, + debug: vec![constructor_debug, debug].into_iter().collect(), + gas, + }, + ) + } + Err(e) => return Err(e.into()), + } + } else { + ( + address, + RunResult { + logs, + traces, + success: true, + debug: vec![constructor_debug].into_iter().collect(), + gas: 0, + labeled_addresses: Default::default(), + }, + ) + }) + } + + pub fn run(&mut self, address: Address, calldata: Bytes) -> eyre::Result { + let RawCallResult { reverted, gas, stipend, logs, traces, labels, debug, .. } = + self.executor.call_raw(self.sender, address, calldata.0, 0.into())?; + Ok(RunResult { + success: !reverted, + gas: gas.overflowing_sub(stipend).0, + logs, + traces: traces.map(|traces| vec![(TraceKind::Execution, traces)]).unwrap_or_default(), + debug: vec![debug].into_iter().collect(), + labeled_addresses: labels, + }) + } +} diff --git a/cli/src/cmd/snapshot.rs b/cli/src/cmd/forge/snapshot.rs similarity index 99% rename from cli/src/cmd/snapshot.rs rename to cli/src/cmd/forge/snapshot.rs index de09ae3bc400..bafa2f4af8be 100644 --- a/cli/src/cmd/snapshot.rs +++ b/cli/src/cmd/forge/snapshot.rs @@ -1,8 +1,10 @@ //! Snapshot command use crate::cmd::{ - test, - test::{Test, TestOutcome}, + forge::{ + test, + test::{Test, TestOutcome}, + }, Cmd, }; use ansi_term::Colour; diff --git a/cli/src/cmd/forge/test.rs b/cli/src/cmd/forge/test.rs new file mode 100644 index 000000000000..904c5f62f2b0 --- /dev/null +++ b/cli/src/cmd/forge/test.rs @@ -0,0 +1,467 @@ +//! Test command +use crate::{ + cmd::{ + forge::{build::BuildArgs, run::RunArgs}, + Cmd, + }, + opts::evm::EvmArgs, + utils, +}; +use ansi_term::Colour; +use clap::{AppSettings, Parser}; +use forge::{ + decode::decode_console_logs, + executor::opts::EvmOpts, + gas_report::GasReport, + trace::{identifier::LocalTraceIdentifier, CallTraceDecoder, TraceKind}, + MultiContractRunner, MultiContractRunnerBuilder, TestFilter, TestKind, TestResult, +}; +use foundry_config::{figment::Figment, Config}; +use regex::Regex; +use std::{collections::BTreeMap, path::PathBuf, str::FromStr, sync::mpsc::channel, thread}; + +#[derive(Debug, Clone, Parser)] +pub struct Filter { + /// Only run test functions matching the specified pattern. + /// + /// Deprecated: See --match-test + #[clap(long = "match", short = 'm')] + pub pattern: Option, + + /// Only run test functions matching the specified pattern. + #[clap(long = "match-test", alias = "mt", conflicts_with = "pattern")] + pub test_pattern: Option, + + /// Only run test functions that do not match the specified pattern. + #[clap(long = "no-match-test", alias = "nmt", conflicts_with = "pattern")] + pub test_pattern_inverse: Option, + + /// Only run tests in contracts matching the specified pattern. + #[clap(long = "match-contract", alias = "mc", conflicts_with = "pattern")] + pub contract_pattern: Option, + + /// Only run tests in contracts that do not match the specified pattern. + #[clap(long = "no-match-contract", alias = "nmc", conflicts_with = "pattern")] + contract_pattern_inverse: Option, + + /// Only run tests in source files matching the specified pattern. + #[clap(long = "match-path", alias = "mp", conflicts_with = "pattern")] + pub path_pattern: Option, + + /// Only run tests in source files that do not match the specified pattern. + #[clap(long = "no-match-path", alias = "nmp", conflicts_with = "pattern")] + pub path_pattern_inverse: Option, +} + +impl TestFilter for Filter { + fn matches_test(&self, test_name: impl AsRef) -> bool { + let mut ok = true; + let test_name = test_name.as_ref(); + // Handle the deprecated option match + if let Some(re) = &self.pattern { + ok &= re.is_match(test_name); + } + if let Some(re) = &self.test_pattern { + ok &= re.is_match(test_name); + } + if let Some(re) = &self.test_pattern_inverse { + ok &= !re.is_match(test_name); + } + ok + } + + fn matches_contract(&self, contract_name: impl AsRef) -> bool { + let mut ok = true; + let contract_name = contract_name.as_ref(); + if let Some(re) = &self.contract_pattern { + ok &= re.is_match(contract_name); + } + if let Some(re) = &self.contract_pattern_inverse { + ok &= !re.is_match(contract_name); + } + ok + } + + fn matches_path(&self, path: impl AsRef) -> bool { + let mut ok = true; + let path = path.as_ref(); + if let Some(re) = &self.path_pattern { + let re = Regex::from_str(&format!("^{}", re.as_str())).unwrap(); + ok &= re.is_match(path); + } + if let Some(re) = &self.path_pattern_inverse { + let re = Regex::from_str(&format!("^{}", re.as_str())).unwrap(); + ok &= !re.is_match(path); + } + ok + } +} + +// Loads project's figment and merges the build cli arguments into it +foundry_config::impl_figment_convert!(TestArgs, opts, evm_opts); + +#[derive(Debug, Clone, Parser)] +#[clap(global_setting = AppSettings::DeriveDisplayOrder)] +pub struct TestArgs { + #[clap(flatten)] + filter: Filter, + + /// Run a test in the debugger. + /// + /// The argument passed to this flag is the name of the test function you want to run, and it + /// works the same as --match-test. + /// + /// If more than one test matches your specified criteria, you must add additional filters + /// until only one test is found (see --match-contract and --match-path). + /// + /// The matching test will be opened in the debugger regardless of the outcome of the test. + /// + /// If the matching test is a fuzz test, then it will open the debugger on the first failure + /// case. + /// If the fuzz test does not fail, it will open the debugger on the last fuzz case. + /// + /// For more fine-grained control of which fuzz case is run, see forge run. + #[clap(long, value_name = "TEST FUNCTION")] + debug: Option, + + /// Print a gas report. + #[clap(long = "gas-report")] + gas_report: bool, + + /// Force the process to exit with code 0, even if the tests fail. + #[clap(long, env = "FORGE_ALLOW_FAILURE")] + allow_failure: bool, + + /// Output test results in JSON format. + #[clap(long, short)] + json: bool, + + #[clap(flatten, next_help_heading = "EVM OPTIONS")] + evm_opts: EvmArgs, + + #[clap(flatten, next_help_heading = "BUILD OPTIONS")] + opts: BuildArgs, +} + +impl TestArgs { + /// Returns the flattened [`BuildArgs`] + pub fn build_args(&self) -> &BuildArgs { + &self.opts + } + + /// Returns the flattened [`Filter`] arguments + pub fn filter(&self) -> &Filter { + &self.filter + } +} + +impl Cmd for TestArgs { + type Output = TestOutcome; + + fn run(mut self) -> eyre::Result { + // Merge all configs + let figment: Figment = From::from(&self); + let mut evm_opts = figment.extract::()?; + let config = Config::from_provider(figment).sanitized(); + + // Setup the fuzzer + // TODO: Add CLI Options to modify the persistence + let cfg = proptest::test_runner::Config { + failure_persistence: None, + cases: config.fuzz_runs, + max_local_rejects: config.fuzz_max_local_rejects, + max_global_rejects: config.fuzz_max_global_rejects, + ..Default::default() + }; + let fuzzer = proptest::test_runner::TestRunner::new(cfg); + + // Set up the project + let project = config.project()?; + let output = crate::cmd::compile(&project, false, false)?; + + // Determine print verbosity and executor verbosity + let verbosity = evm_opts.verbosity; + if self.gas_report && evm_opts.verbosity < 3 { + evm_opts.verbosity = 3; + } + + // Prepare the test builder + let evm_spec = crate::utils::evm_spec(&config.evm_version); + let mut runner = MultiContractRunnerBuilder::default() + .fuzzer(fuzzer) + .initial_balance(evm_opts.initial_balance) + .evm_spec(evm_spec) + .sender(evm_opts.sender) + .with_fork(utils::get_fork(&evm_opts, &config.rpc_storage_caching)) + .build(output, evm_opts)?; + + if self.debug.is_some() { + self.filter.test_pattern = self.debug; + match runner.count_filtered_tests(&self.filter) { + 1 => { + // Run the test + let results = runner.test(&self.filter, None)?; + + // Get the result of the single test + let (id, sig, test_kind, counterexample) = results.iter().map(|(id, results)| { + let (sig, result) = results.iter().next().unwrap(); + + (id.clone(), sig.clone(), result.kind.clone(), result.counterexample.clone()) + }).next().unwrap(); + + // Build debugger args if this is a fuzz test + let sig = match test_kind { + TestKind::Fuzz(cases) => { + if let Some(counterexample) = counterexample { + counterexample.calldata.to_string() + } else { + cases.cases().first().expect("no fuzz cases run").calldata.to_string() + } + }, + _ => sig, + }; + + // Run the debugger + let debugger = RunArgs { + path: PathBuf::from(runner.source_paths.get(&id).unwrap()), + target_contract: Some(utils::get_contract_name(&id).to_string()), + sig, + args: Vec::new(), + debug: true, + opts: self.opts, + evm_opts: self.evm_opts, + }; + debugger.run()?; + + Ok(TestOutcome::new(results, self.allow_failure)) + } + n => + Err( + eyre::eyre!("{} tests matched your criteria, but exactly 1 test must match in order to run the debugger.\n + \n + Use --match-contract and --match-path to further limit the search.", n)) + } + } else { + let TestArgs { filter, .. } = self; + test( + runner, + verbosity, + filter, + self.json, + self.allow_failure, + (self.gas_report, config.gas_reports), + ) + } + } +} + +/// The result of a single test +#[derive(Debug, Clone)] +pub struct Test { + /// The identifier of the artifact/contract in the form of `:` + pub artifact_id: String, + /// The signature of the solidity test + pub signature: String, + /// Result of the executed solidity test + pub result: forge::TestResult, +} + +impl Test { + pub fn gas_used(&self) -> u64 { + self.result.kind.gas_used().gas() + } + + /// Returns the contract name of the artifact id + pub fn contract_name(&self) -> &str { + utils::get_contract_name(&self.artifact_id) + } + + /// Returns the file name of the artifact id + pub fn file_name(&self) -> &str { + utils::get_file_name(&self.artifact_id) + } +} + +/// Represents the bundled results of all tests +pub struct TestOutcome { + /// Whether failures are allowed + allow_failure: bool, + /// All test results `contract -> (test name -> TestResult)` + pub results: BTreeMap>, +} + +impl TestOutcome { + fn new( + results: BTreeMap>, + allow_failure: bool, + ) -> Self { + Self { results, allow_failure } + } + + /// Iterator over all succeeding tests and their names + pub fn successes(&self) -> impl Iterator { + self.tests().filter(|(_, t)| t.success) + } + + /// Iterator over all failing tests and their names + pub fn failures(&self) -> impl Iterator { + self.tests().filter(|(_, t)| !t.success) + } + + /// Iterator over all tests and their names + pub fn tests(&self) -> impl Iterator { + self.results.values().flat_map(|tests| tests.iter()) + } + + /// Returns an iterator over all `Test` + pub fn into_tests(self) -> impl Iterator { + self.results + .into_iter() + .flat_map(|(file, tests)| tests.into_iter().map(move |t| (file.clone(), t))) + .map(|(artifact_id, (signature, result))| Test { artifact_id, signature, result }) + } + + /// Checks if there are any failures and failures are disallowed + pub fn ensure_ok(&self) -> eyre::Result<()> { + if !self.allow_failure { + let failures = self.failures().count(); + if failures > 0 { + println!("Failed tests:"); + for (name, result) in self.failures() { + short_test_result(name, result); + } + println!(); + + let successes = self.successes().count(); + println!( + "Encountered a total of {} failing tests, {} tests succeeded", + Colour::Red.paint(failures.to_string()), + Colour::Green.paint(successes.to_string()) + ); + std::process::exit(1); + } + } + Ok(()) + } +} + +fn short_test_result(name: &str, result: &forge::TestResult) { + let status = if result.success { + Colour::Green.paint("[PASS]") + } else { + let txt = match (&result.reason, &result.counterexample) { + (Some(ref reason), Some(ref counterexample)) => { + format!("[FAIL. Reason: {}. Counterexample: {}]", reason, counterexample) + } + (None, Some(ref counterexample)) => { + format!("[FAIL. Counterexample: {}]", counterexample) + } + (Some(ref reason), None) => { + format!("[FAIL. Reason: {}]", reason) + } + (None, None) => "[FAIL]".to_string(), + }; + + Colour::Red.paint(txt) + }; + + println!("{} {} {}", status, name, result.kind.gas_used()); +} + +/// Runs all the tests +fn test( + mut runner: MultiContractRunner, + verbosity: u8, + filter: Filter, + json: bool, + allow_failure: bool, + (gas_reporting, gas_reports): (bool, Vec), +) -> eyre::Result { + if json { + let results = runner.test(&filter, None)?; + println!("{}", serde_json::to_string(&results)?); + Ok(TestOutcome::new(results, allow_failure)) + } else { + let local_identifier = LocalTraceIdentifier::new(&runner.known_contracts); + let (tx, rx) = channel::<(String, BTreeMap)>(); + + thread::spawn(move || runner.test(&filter, Some(tx)).unwrap()); + + let mut results: BTreeMap> = BTreeMap::new(); + let mut gas_report = GasReport::new(gas_reports); + for (contract_name, mut tests) in rx { + println!(); + if !tests.is_empty() { + let term = if tests.len() > 1 { "tests" } else { "test" }; + println!("Running {} {} for {}", tests.len(), term, contract_name); + } + for (name, result) in &mut tests { + short_test_result(name, result); + + // We only display logs at level 2 and above + if verbosity < 2 { + continue + } + + // We only decode logs from Hardhat and DS-style console events + let console_logs = decode_console_logs(&result.logs); + if !console_logs.is_empty() { + println!("Logs:"); + for log in console_logs { + println!(" {}", log); + } + println!(); + } + + if !result.traces.is_empty() { + // We only display traces at verbosity level 3 and above + if verbosity < 3 { + continue + } + + // At verbosity level 3, we only display traces for failed tests + if verbosity == 3 && result.success { + continue + } + + // Identify addresses in each trace + let mut decoder = + CallTraceDecoder::new_with_labels(result.labeled_addresses.clone()); + + println!("Traces:"); + for (kind, trace) in &mut result.traces { + decoder.identify(trace, &local_identifier); + + let should_include = match kind { + // At verbosity level 4, we also display the setup trace for failed + // tests At verbosity level 5, we display + // all traces for all tests + TraceKind::Setup => { + (verbosity >= 5) || (verbosity == 4 && !result.success) + } + TraceKind::Execution => verbosity > 3 || !result.success, + _ => false, + }; + + if should_include { + decoder.decode(trace); + println!("{}", trace); + } + } + + if gas_reporting { + gas_report.analyze(&result.traces); + } + } + } + results.insert(contract_name, tests); + } + + if gas_reporting { + println!("{}", gas_report.finalize()); + } + + Ok(TestOutcome::new(results, allow_failure)) + } +} diff --git a/cli/src/cmd/tree.rs b/cli/src/cmd/forge/tree.rs similarity index 95% rename from cli/src/cmd/tree.rs rename to cli/src/cmd/forge/tree.rs index 49a269250c95..2e7b4b540c30 100644 --- a/cli/src/cmd/tree.rs +++ b/cli/src/cmd/forge/tree.rs @@ -1,6 +1,6 @@ //! tree command -use crate::cmd::{build::BuildArgs, Cmd}; +use crate::cmd::{forge::build::BuildArgs, Cmd}; use clap::Parser; use ethers::solc::Graph; use foundry_config::Config; diff --git a/cli/src/cmd/verify.rs b/cli/src/cmd/forge/verify.rs similarity index 98% rename from cli/src/cmd/verify.rs rename to cli/src/cmd/forge/verify.rs index 8636a124da19..dc2c6d199c49 100644 --- a/cli/src/cmd/verify.rs +++ b/cli/src/cmd/forge/verify.rs @@ -1,7 +1,7 @@ //! Verify contract source on etherscan use crate::{ - cmd::{build::BuildArgs, flatten::CoreFlattenArgs}, + cmd::forge::{build::BuildArgs, flatten::CoreFlattenArgs}, opts::forge::ContractInfo, }; use clap::Parser; diff --git a/cli/src/cmd/watch.rs b/cli/src/cmd/forge/watch.rs similarity index 99% rename from cli/src/cmd/watch.rs rename to cli/src/cmd/forge/watch.rs index fa31c26fcd47..03a0aff910f5 100644 --- a/cli/src/cmd/watch.rs +++ b/cli/src/cmd/forge/watch.rs @@ -1,7 +1,7 @@ //! Watch mode support use crate::{ - cmd::{build::BuildArgs, test::TestArgs}, + cmd::forge::{build::BuildArgs, test::TestArgs}, utils::{self, FoundryPathExt}, }; use clap::Parser; diff --git a/cli/src/cmd/mod.rs b/cli/src/cmd/mod.rs index 312c90f6290e..174119915d64 100644 --- a/cli/src/cmd/mod.rs +++ b/cli/src/cmd/mod.rs @@ -1,260 +1,13 @@ -//! Subcommands for forge +//! Subcommands //! //! All subcommands should respect the `foundry_config::Config`. //! If a subcommand accepts values that are supported by the `Config`, then the subcommand should //! implement `figment::Provider` which allows the subcommand to override the config's defaults, see //! [`foundry_config::Config`]. -//! -//! See [`BuildArgs`] for a reference implementation. -//! And [`RunArgs`] for how to merge `Providers`. -//! -//! # Example -//! -//! create a `clap` subcommand into a `figment::Provider` and integrate it in the -//! `foundry_config::Config`: -//! -//! ```rust -//! use crate::{cmd::build::BuildArgs, opts::evm::EvmArgs}; -//! use clap::Parser; -//! use foundry_config::{figment::Figment, *}; -//! -//! // A new clap subcommand that accepts both `EvmArgs` and `BuildArgs` -//! #[derive(Debug, Clone, Parser)] -//! pub struct MyArgs { -//! #[clap(flatten)] -//! evm_opts: EvmArgs, -//! #[clap(flatten)] -//! opts: BuildArgs, -//! } -//! -//! // add `Figment` and `Config` converters -//! foundry_config::impl_figment_convert!(MyArgs, opts, evm_opts); -//! let args = MyArgs::parse_from(["build"]); -//! -//! let figment: Figment = From::from(&args); -//! let evm_opts = figment.extract::().unwrap(); -//! -//! let config: Config = From::from(&args); -//! ``` - -pub mod bind; -pub mod build; -pub mod config; -pub mod create; -pub mod flatten; -pub mod fmt; -pub mod init; -pub mod inspect; -pub mod install; -pub mod remappings; -pub mod run; -pub mod snapshot; -pub mod test; -pub mod tree; -pub mod verify; -pub mod watch; - -use crate::{opts::forge::ContractInfo, term}; -use ethers::{ - abi::Abi, - prelude::{ - artifacts::{CompactBytecode, CompactDeployedBytecode}, - report::NoReporter, - }, - solc::cache::SolFilesCache, -}; -use std::{collections::BTreeMap, path::PathBuf}; - -/// Common trait for all cli commands -pub trait Cmd: clap::Parser + Sized { - type Output; - fn run(self) -> eyre::Result; -} - -use ethers::solc::{artifacts::CompactContractBytecode, Artifact, Project, ProjectCompileOutput}; - -use foundry_utils::to_table; - -/// Compiles the provided [`Project`], throws if there's any compiler error and logs whether -/// compilation was successful or if there was a cache hit. -pub fn compile( - project: &Project, - print_names: bool, - print_sizes: bool, -) -> eyre::Result { - if !project.paths.sources.exists() { - eyre::bail!( - r#"no contracts to compile, contracts folder "{}" does not exist. -Check the configured workspace settings: -{} -If you are in a subdirectory in a Git repository, try adding `--root .`"#, - project.paths.sources.display(), - project.paths - ); - } - - let output = term::with_spinner_reporter(|| project.compile())?; - - if output.has_compiler_errors() { - eyre::bail!(output.to_string()) - } else if output.is_unchanged() { - println!("No files changed, compilation skipped"); - } else { - // print the compiler output / warnings - println!("{}", output); - - // print any sizes or names - if print_names { - let compiled_contracts = output.compiled_contracts_by_compiler_version(); - for (version, contracts) in compiled_contracts.into_iter() { - println!( - " compiler version: {}.{}.{}", - version.major, version.minor, version.patch - ); - for (name, _) in contracts { - println!(" - {}", name); - } - } - } - if print_sizes { - // add extra newline if names were already printed - if print_names { - println!(); - } - let compiled_contracts = output.compiled_contracts_by_compiler_version(); - let mut sizes = BTreeMap::new(); - for (_, contracts) in compiled_contracts.into_iter() { - for (name, contract) in contracts { - let size = contract - .get_bytecode_bytes() - .map(|bytes| bytes.0.len()) - .unwrap_or_default(); - sizes.insert(name, size); - } - } - let json = serde_json::to_value(&sizes)?; - println!("name size (bytes)"); - println!("-----------------------------"); - println!("{}", to_table(json)); - } - } - - Ok(output) -} - -/// Compiles the provided [`Project`], throws if there's any compiler error and logs whether -/// compilation was successful or if there was a cache hit. -/// Doesn't print anything to stdout, thus is "suppressed". -pub fn suppress_compile(project: &Project) -> eyre::Result { - if !project.paths.sources.exists() { - eyre::bail!( - r#"no contracts to compile, contracts folder "{}" does not exist. -Check the configured workspace settings: -{} -If you are in a subdirectory in a Git repository, try adding `--root .`"#, - project.paths.sources.display(), - project.paths - ); - } - - let output = ethers::solc::report::with_scoped( - ðers::solc::report::Report::new(NoReporter::default()), - || project.compile(), - )?; - - if output.has_compiler_errors() { - eyre::bail!(output.to_string()) - } - - Ok(output) -} - -/// Compile a set of files not necessarily included in the `project`'s source dir -pub fn compile_files(project: &Project, files: Vec) -> eyre::Result { - let output = term::with_spinner_reporter(|| project.compile_files(files))?; - - if output.has_compiler_errors() { - eyre::bail!(output.to_string()) - } - println!("{}", output); - Ok(output) -} - -/// Given a project and its compiled artifacts, proceeds to return the ABI, Bytecode and -/// Runtime Bytecode of the given contract. -pub fn read_artifact( - project: &Project, - compiled: ProjectCompileOutput, - contract: ContractInfo, -) -> eyre::Result<(Abi, CompactBytecode, CompactDeployedBytecode)> { - Ok(match contract.path { - Some(path) => get_artifact_from_path(project, path, contract.name)?, - None => get_artifact_from_name(contract, compiled)?, - }) -} - -/// Helper function for finding a contract by ContractName -// TODO: Is there a better / more ergonomic way to get the artifacts given a project and a -// contract name? -fn get_artifact_from_name( - contract: ContractInfo, - compiled: ProjectCompileOutput, -) -> eyre::Result<(Abi, CompactBytecode, CompactDeployedBytecode)> { - let mut has_found_contract = false; - let mut contract_artifact = None; - - for (artifact_id, artifact) in compiled.into_artifacts() { - if artifact_id.name == contract.name { - if has_found_contract { - eyre::bail!("contract with duplicate name. pass path") - } - has_found_contract = true; - contract_artifact = Some(artifact); - } - } - - Ok(match contract_artifact { - Some(artifact) => ( - artifact - .abi - .map(Into::into) - .ok_or_else(|| eyre::Error::msg(format!("abi not found for {}", contract.name)))?, - artifact.bytecode.ok_or_else(|| { - eyre::Error::msg(format!("bytecode not found for {}", contract.name)) - })?, - artifact.deployed_bytecode.ok_or_else(|| { - eyre::Error::msg(format!("bytecode not found for {}", contract.name)) - })?, - ), - None => { - eyre::bail!("could not find artifact") - } - }) -} - -/// Find using src/ContractSource.sol:ContractName -fn get_artifact_from_path( - project: &Project, - contract_path: String, - contract_name: String, -) -> eyre::Result<(Abi, CompactBytecode, CompactDeployedBytecode)> { - // Get sources from the requested location - let abs_path = dunce::canonicalize(PathBuf::from(contract_path))?; - - let cache = SolFilesCache::read_joined(&project.paths)?; - // Read the artifact from disk - let artifact: CompactContractBytecode = cache.read_artifact(abs_path, &contract_name)?; +pub mod cast; +pub mod forge; - Ok(( - artifact - .abi - .ok_or_else(|| eyre::Error::msg(format!("abi not found for {}", contract_name)))?, - artifact - .bytecode - .ok_or_else(|| eyre::Error::msg(format!("bytecode not found for {}", contract_name)))?, - artifact - .deployed_bytecode - .ok_or_else(|| eyre::Error::msg(format!("bytecode not found for {}", contract_name)))?, - )) -} +// Re-export our shared utilities +mod utils; +pub use utils::*; diff --git a/cli/src/cmd/run.rs b/cli/src/cmd/run.rs deleted file mode 100644 index b4f0603ee13d..000000000000 --- a/cli/src/cmd/run.rs +++ /dev/null @@ -1,357 +0,0 @@ -use crate::cmd::{build::BuildArgs, compile_files, Cmd}; -use clap::{Parser, ValueHint}; -use evm_adapters::sputnik::cheatcodes::{CONSOLE_ABI, HEVMCONSOLE_ABI, HEVM_ABI}; - -use forge::ContractRunner; -use foundry_utils::IntoFunction; -use std::{collections::BTreeMap, path::PathBuf}; -use ui::{TUIExitReason, Tui, Ui}; - -use ethers::solc::Project; - -use crate::opts::evm::EvmArgs; -use ansi_term::Colour; -use ethers::{ - abi::Abi, - solc::artifacts::{CompactContractBytecode, ContractBytecode, ContractBytecodeSome}, -}; -use evm_adapters::{ - call_tracing::ExecutionInfo, - evm_opts::{BackendKind, EvmOpts}, - sputnik::{cheatcodes::debugger::DebugArena, helpers::vm}, -}; -use foundry_config::{figment::Figment, Config}; -use foundry_utils::PostLinkInput; - -// Loads project's figment and merges the build cli arguments into it -foundry_config::impl_figment_convert!(RunArgs, opts, evm_opts); - -#[derive(Debug, Clone, Parser)] -pub struct RunArgs { - #[clap(help = "the path to the contract to run", value_hint = ValueHint::FilePath)] - pub path: PathBuf, - - #[clap(flatten)] - pub evm_opts: EvmArgs, - - #[clap(flatten)] - opts: BuildArgs, - - #[clap( - long, - short, - help = "the contract you want to call and deploy, only necessary if there are more than 1 contract (Interfaces do not count) definitions on the script" - )] - pub target_contract: Option, - - #[clap( - long, - short, - help = "the function you want to call on the script contract, defaults to run()" - )] - pub sig: Option, -} - -impl Cmd for RunArgs { - type Output = (); - fn run(self) -> eyre::Result { - // Keeping it like this for simplicity. - #[cfg(not(feature = "sputnik-evm"))] - unimplemented!("`run` does not work with EVMs other than Sputnik yet"); - - let figment: Figment = From::from(&self); - let mut evm_opts = figment.extract::()?; - let config = Config::from_provider(figment).sanitized(); - let evm_version = config.evm_version; - if evm_opts.debug { - evm_opts.verbosity = 3; - } - - let func = IntoFunction::into(self.sig.as_deref().unwrap_or("run()")); - let BuildOutput { - project, - contract, - highlevel_known_contracts, - sources, - predeploy_libraries, - } = self.build(config, &evm_opts)?; - - let mut known_contracts = highlevel_known_contracts - .iter() - .map(|(name, c)| { - ( - name.clone(), - ( - c.abi.clone(), - c.deployed_bytecode.clone().into_bytes().expect("not bytecode").to_vec(), - ), - ) - }) - .collect::)>>(); - - known_contracts.insert("VM".to_string(), (HEVM_ABI.clone(), Vec::new())); - known_contracts.insert("VM_CONSOLE".to_string(), (HEVMCONSOLE_ABI.clone(), Vec::new())); - known_contracts.insert("CONSOLE".to_string(), (CONSOLE_ABI.clone(), Vec::new())); - - let CompactContractBytecode { abi, bytecode, .. } = contract; - let abi = abi.expect("No abi for contract"); - let bytecode = bytecode.expect("No bytecode").object.into_bytes().unwrap(); - let needs_setup = abi.functions().any(|func| func.name == "setUp"); - - let mut cfg = crate::utils::sputnik_cfg(&evm_version); - cfg.create_contract_limit = None; - let vicinity = evm_opts.vicinity()?; - let backend = evm_opts.backend(&vicinity)?; - - // need to match on the backend type - let result = match backend { - BackendKind::Simple(ref backend) => { - let runner = ContractRunner::new( - &evm_opts, - &cfg, - backend, - &abi, - bytecode, - Some(evm_opts.sender), - None, - &predeploy_libraries, - ); - runner.run_test(&func, needs_setup, Some(&known_contracts))? - } - BackendKind::Shared(ref backend) => { - let runner = ContractRunner::new( - &evm_opts, - &cfg, - backend, - &abi, - bytecode, - Some(evm_opts.sender), - None, - &predeploy_libraries, - ); - runner.run_test(&func, needs_setup, Some(&known_contracts))? - } - }; - - if evm_opts.debug { - // 4. Boot up debugger - let source_code: BTreeMap = sources - .iter() - .map(|(id, path)| { - if let Some(resolved) = - project.paths.resolve_library_import(&PathBuf::from(path)) - { - ( - *id, - std::fs::read_to_string(resolved).expect(&*format!( - "Something went wrong reading the source file: {:?}", - path - )), - ) - } else { - ( - *id, - std::fs::read_to_string(path).expect(&*format!( - "Something went wrong reading the source file: {:?}", - path - )), - ) - } - }) - .collect(); - - let calls: Vec = result.debug_calls.expect("Debug must be enabled by now"); - println!("debugging"); - let index = if needs_setup && calls.len() > 1 { 1 } else { 0 }; - let mut flattened = Vec::new(); - calls[index].flatten(0, &mut flattened); - flattened = flattened[1..].to_vec(); - let tui = Tui::new( - flattened, - 0, - result.identified_contracts.expect("debug but not verbosity"), - highlevel_known_contracts, - source_code, - )?; - match tui.start().expect("Failed to start tui") { - TUIExitReason::CharExit => return Ok(()), - } - } else if evm_opts.verbosity > 2 { - // support traces - if let (Some(traces), Some(identified_contracts)) = - (&result.traces, &result.identified_contracts) - { - if !result.success && evm_opts.verbosity == 3 || evm_opts.verbosity > 3 { - let mut ident = identified_contracts.clone(); - let (funcs, events, errors) = - foundry_utils::flatten_known_contracts(&known_contracts); - let mut exec_info = ExecutionInfo::new( - &known_contracts, - &mut ident, - &result.labeled_addresses, - &funcs, - &events, - &errors, - ); - let vm = vm(); - let mut trace_string = "".to_string(); - if evm_opts.verbosity > 4 || !result.success { - // print setup calls as well - traces.iter().for_each(|trace| { - trace.construct_trace_string( - 0, - &mut exec_info, - &vm, - "", - &mut trace_string, - ); - }); - } else if !traces.is_empty() { - traces.last().expect("no last but not empty").construct_trace_string( - 0, - &mut exec_info, - &vm, - "", - &mut trace_string, - ); - } - if !trace_string.is_empty() { - println!("{}", trace_string); - } - } else { - // 5. print the result nicely - if result.success { - println!("{}", Colour::Green.paint("Script ran successfully.")); - } else { - println!("{}", Colour::Red.paint("Script failed.")); - } - - println!("Gas Used: {}", result.gas_used); - println!("== Logs == "); - result.logs.iter().for_each(|log| println!("{}", log)); - } - println!(); - } else if result.traces.is_none() { - eyre::bail!("Unexpected error: No traces despite verbosity level. Please report this as a bug: https://github.com/gakonst/foundry/issues/new?assignees=&labels=T-bug&template=BUG-FORM.yml"); - } else if result.identified_contracts.is_none() { - eyre::bail!( - "Unexpected error: No identified contracts. Please report this as a bug: https://github.com/gakonst/foundry/issues/new?assignees=&labels=T-bug&template=BUG-FORM.yml" - ); - } - } else { - // 5. print the result nicely - if result.success { - println!("{}", Colour::Green.paint("Script ran successfully.")); - } else { - println!("{}", Colour::Red.paint("Script failed.")); - } - - println!("Gas Used: {}", result.gas_used); - println!("== Logs =="); - result.logs.iter().for_each(|log| println!("{}", log)); - } - - Ok(()) - } -} - -struct ExtraLinkingInfo<'a> { - no_target_name: bool, - target_fname: String, - contract: &'a mut CompactContractBytecode, - dependencies: &'a mut Vec, - matched: bool, -} - -pub struct BuildOutput { - pub project: Project, - pub contract: CompactContractBytecode, - pub highlevel_known_contracts: BTreeMap, - pub sources: BTreeMap, - pub predeploy_libraries: Vec, -} - -impl RunArgs { - /// Compiles the file with auto-detection and compiler params. - pub fn build(&self, config: Config, evm_opts: &EvmOpts) -> eyre::Result { - let target_contract = dunce::canonicalize(&self.path)?; - let project = config.ephemeral_no_artifacts_project()?; - let output = compile_files(&project, vec![target_contract])?; - - let (sources, all_contracts) = output.output().split(); - - let contracts: BTreeMap = all_contracts - .contracts_with_files() - .map(|(file, name, contract)| (format!("{}:{}", file, name), contract.clone().into())) - .collect(); - - let mut run_dependencies = vec![]; - let mut contract = - CompactContractBytecode { abi: None, bytecode: None, deployed_bytecode: None }; - let mut highlevel_known_contracts = BTreeMap::new(); - - let mut target_fname = dunce::canonicalize(&self.path) - .expect("Couldn't convert contract path to absolute path") - .to_str() - .expect("Bad path to string") - .to_string(); - - let no_target_name = if let Some(target_name) = &self.target_contract { - target_fname = target_fname + ":" + target_name; - false - } else { - true - }; - - foundry_utils::link( - &contracts, - &mut highlevel_known_contracts, - evm_opts.sender, - &mut ExtraLinkingInfo { - no_target_name, - target_fname, - contract: &mut contract, - dependencies: &mut run_dependencies, - matched: false, - }, - |file, key| (format!("{}:{}", file, key), file, key), - |post_link_input| { - let PostLinkInput { - contract, - known_contracts: highlevel_known_contracts, - fname, - extra, - dependencies, - } = post_link_input; - let split = fname.split(':').collect::>(); - - // if its the target contract, grab the info - if extra.no_target_name && split[0] == extra.target_fname { - if extra.matched { - eyre::bail!("Multiple contracts in the target path. Please specify the contract name with `-t ContractName`") - } - *extra.dependencies = dependencies; - *extra.contract = contract.clone(); - extra.matched = true; - } else if extra.target_fname == fname { - *extra.dependencies = dependencies; - *extra.contract = contract.clone(); - extra.matched = true; - } - - let tc: ContractBytecode = contract.into(); - let contract_name = if split.len() > 1 { split[1] } else { split[0] }; - highlevel_known_contracts.insert(contract_name.to_string(), tc.unwrap()); - Ok(()) - }, - )?; - - Ok(BuildOutput { - project, - contract, - highlevel_known_contracts, - sources: sources.into_ids().collect(), - predeploy_libraries: run_dependencies, - }) - } -} diff --git a/cli/src/cmd/test.rs b/cli/src/cmd/test.rs deleted file mode 100644 index f9e44f037b0e..000000000000 --- a/cli/src/cmd/test.rs +++ /dev/null @@ -1,457 +0,0 @@ -//! Test command - -use crate::{ - cmd::{build::BuildArgs, Cmd}, - opts::evm::EvmArgs, - utils, -}; -use ansi_term::Colour; -use clap::{AppSettings, Parser}; -use ethers::solc::{ArtifactOutput, ProjectCompileOutput}; -use evm_adapters::{ - call_tracing::ExecutionInfo, evm_opts::EvmOpts, gas_report::GasReport, sputnik::helpers::vm, -}; -use forge::{MultiContractRunnerBuilder, TestFilter, TestResult}; -use foundry_config::{figment::Figment, Config}; -use regex::Regex; -use std::{collections::BTreeMap, str::FromStr, sync::mpsc::channel, thread}; - -#[derive(Debug, Clone, Parser)] -pub struct Filter { - #[clap( - long = "match", - short = 'm', - help = "only run test methods matching regex (deprecated, see --match-test)" - )] - pub pattern: Option, - - #[clap( - long = "match-test", - alias = "mt", - help = "only run test methods matching regex", - conflicts_with = "pattern" - )] - pub test_pattern: Option, - - #[clap( - long = "no-match-test", - alias = "nmt", - help = "only run test methods not matching regex", - conflicts_with = "pattern" - )] - pub test_pattern_inverse: Option, - - #[clap( - long = "match-contract", - alias = "mc", - help = "only run test methods in contracts matching regex", - conflicts_with = "pattern" - )] - pub contract_pattern: Option, - - #[clap( - long = "no-match-contract", - alias = "nmc", - help = "only run test methods in contracts not matching regex", - conflicts_with = "pattern" - )] - contract_pattern_inverse: Option, - - #[clap( - long = "match-path", - alias = "mp", - help = "only run test methods in source files at path matching regex. Requires absolute path", - conflicts_with = "pattern" - )] - pub path_pattern: Option, - - #[clap( - long = "no-match-path", - alias = "nmp", - help = "only run test methods in source files at path not matching regex. Requires absolute path", - conflicts_with = "pattern" - )] - pub path_pattern_inverse: Option, -} - -impl TestFilter for Filter { - fn matches_test(&self, test_name: impl AsRef) -> bool { - let mut ok = true; - let test_name = test_name.as_ref(); - // Handle the deprecated option match - if let Some(re) = &self.pattern { - ok &= re.is_match(test_name); - } - if let Some(re) = &self.test_pattern { - ok &= re.is_match(test_name); - } - if let Some(re) = &self.test_pattern_inverse { - ok &= !re.is_match(test_name); - } - ok - } - - fn matches_contract(&self, contract_name: impl AsRef) -> bool { - let mut ok = true; - let contract_name = contract_name.as_ref(); - if let Some(re) = &self.contract_pattern { - ok &= re.is_match(contract_name); - } - if let Some(re) = &self.contract_pattern_inverse { - ok &= !re.is_match(contract_name); - } - ok - } - - fn matches_path(&self, path: impl AsRef) -> bool { - let mut ok = true; - let path = path.as_ref(); - if let Some(re) = &self.path_pattern { - let re = Regex::from_str(&format!("^{}", re.as_str())).unwrap(); - ok &= re.is_match(path); - } - if let Some(re) = &self.path_pattern_inverse { - let re = Regex::from_str(&format!("^{}", re.as_str())).unwrap(); - ok &= !re.is_match(path); - } - ok - } -} - -// Loads project's figment and merges the build cli arguments into it -foundry_config::impl_figment_convert!(TestArgs, opts, evm_opts); - -#[derive(Debug, Clone, Parser)] -// This is required to group Filter options in help output -#[clap(global_setting = AppSettings::DeriveDisplayOrder)] -pub struct TestArgs { - #[clap(help = "print the test results in json format", long, short)] - json: bool, - - #[clap(help = "print a gas report", long = "gas-report")] - gas_report: bool, - - #[clap(flatten)] - evm_opts: EvmArgs, - - #[clap(flatten)] - filter: Filter, - - #[clap(flatten)] - opts: BuildArgs, - - #[clap( - help = "if set to true, the process will exit with an exit code = 0, even if the tests fail", - long, - env = "FORGE_ALLOW_FAILURE" - )] - allow_failure: bool, -} - -impl TestArgs { - /// Returns the flattened [`BuildArgs`] - pub fn build_args(&self) -> &BuildArgs { - &self.opts - } - - /// Returns the flattened [`Filter`] arguments - pub fn filter(&self) -> &Filter { - &self.filter - } -} - -impl Cmd for TestArgs { - type Output = TestOutcome; - - fn run(self) -> eyre::Result { - // merge all configs - let figment: Figment = From::from(&self); - let evm_opts = figment.extract::()?; - let config = Config::from_provider(figment).sanitized(); - - let TestArgs { json, filter, allow_failure, .. } = self; - - // Setup the fuzzer - // TODO: Add CLI Options to modify the persistence - let cfg = proptest::test_runner::Config { - failure_persistence: None, - cases: config.fuzz_runs, - max_local_rejects: config.fuzz_max_local_rejects, - max_global_rejects: config.fuzz_max_global_rejects, - ..Default::default() - }; - let fuzzer = proptest::test_runner::TestRunner::new(cfg); - - // Set up the project - let project = config.project()?; - let output = super::compile(&project, false, false)?; - - // prepare the test builder - let mut evm_cfg = crate::utils::sputnik_cfg(&config.evm_version); - evm_cfg.create_contract_limit = None; - - let builder = MultiContractRunnerBuilder::default() - .fuzzer(fuzzer) - .initial_balance(evm_opts.initial_balance) - .evm_cfg(evm_cfg) - .sender(evm_opts.sender); - - test( - builder, - output, - evm_opts, - filter, - json, - allow_failure, - (self.gas_report, config.gas_reports), - ) - } -} - -/// The result of a single test -#[derive(Debug, Clone)] -pub struct Test { - /// The identifier of the artifact/contract in the form of `:` - pub artifact_id: String, - /// The signature of the solidity test - pub signature: String, - /// Result of the executed solidity test - pub result: forge::TestResult, -} - -impl Test { - pub fn gas_used(&self) -> u64 { - self.result.gas_used - } - - /// Returns the contract name of the artifact id - pub fn contract_name(&self) -> &str { - utils::get_contract_name(&self.artifact_id) - } - - /// Returns the file name of the artifact id - pub fn file_name(&self) -> &str { - utils::get_file_name(&self.artifact_id) - } -} - -/// Represents the bundled results of all tests -pub struct TestOutcome { - /// Whether failures are allowed - allow_failure: bool, - /// All test results `contract -> (test name -> TestResult)` - pub results: BTreeMap>, -} - -impl TestOutcome { - fn new( - results: BTreeMap>, - allow_failure: bool, - ) -> Self { - Self { results, allow_failure } - } - - /// Iterator over all succeeding tests and their names - pub fn successes(&self) -> impl Iterator { - self.tests().filter(|(_, t)| t.success) - } - - /// Iterator over all failing tests and their names - pub fn failures(&self) -> impl Iterator { - self.tests().filter(|(_, t)| !t.success) - } - - /// Iterator over all tests and their names - pub fn tests(&self) -> impl Iterator { - self.results.values().flat_map(|tests| tests.iter()) - } - - /// Returns an iterator over all `Test` - pub fn into_tests(self) -> impl Iterator { - self.results - .into_iter() - .flat_map(|(file, tests)| tests.into_iter().map(move |t| (file.clone(), t))) - .map(|(artifact_id, (signature, result))| Test { artifact_id, signature, result }) - } - - /// Checks if there are any failures and failures are disallowed - pub fn ensure_ok(&self) -> eyre::Result<()> { - if !self.allow_failure { - let failures = self.failures().count(); - if failures > 0 { - println!(); - println!("Failed tests:"); - for (name, result) in self.failures() { - short_test_result(name, result); - } - println!(); - - let successes = self.successes().count(); - println!( - "Encountered a total of {} failing tests, {} tests succeeded", - Colour::Red.paint(failures.to_string()), - Colour::Green.paint(successes.to_string()) - ); - std::process::exit(1); - } - } - Ok(()) - } -} - -fn short_test_result(name: &str, result: &forge::TestResult) { - let status = if result.success { - Colour::Green.paint("[PASS]") - } else { - let txt = match (&result.reason, &result.counterexample) { - (Some(ref reason), Some(ref counterexample)) => { - format!("[FAIL. Reason: {}. Counterexample: {}]", reason, counterexample) - } - (None, Some(ref counterexample)) => { - format!("[FAIL. Counterexample: {}]", counterexample) - } - (Some(ref reason), None) => { - format!("[FAIL. Reason: {}]", reason) - } - (None, None) => "[FAIL]".to_string(), - }; - - Colour::Red.paint(txt) - }; - - println!("{} {} {}", status, name, result.kind.gas_used()); -} - -/// Runs all the tests -fn test( - builder: MultiContractRunnerBuilder, - output: ProjectCompileOutput, - mut evm_opts: EvmOpts, - filter: Filter, - json: bool, - allow_failure: bool, - gas_reports: (bool, Vec), -) -> eyre::Result { - let verbosity = evm_opts.verbosity; - let gas_reporting = gas_reports.0; - if gas_reporting && evm_opts.verbosity < 3 { - // force evm to do tracing, but don't hit the verbosity print path - evm_opts.verbosity = 3; - } - let mut runner = builder.build(output, evm_opts)?; - - if json { - let results = runner.test(&filter, None)?; - let res = serde_json::to_string(&results)?; // TODO: Make this work normally - println!("{}", res); - Ok(TestOutcome::new(results, allow_failure)) - } else { - // Dapptools-style printing of test results - let mut gas_report = GasReport::new(gas_reports.1); - let (tx, rx) = channel::<(String, BTreeMap)>(); - let known_contracts = runner.known_contracts.clone(); - let execution_info = runner.execution_info.clone(); - - let handle = thread::spawn(move || { - while let Ok((contract_name, tests)) = rx.recv() { - println!(); - if !tests.is_empty() { - let term = if tests.len() > 1 { "tests" } else { "test" }; - println!("Running {} {} for {}", tests.len(), term, contract_name); - } - for (name, result) in tests { - short_test_result(&name, &result); - // adds a linebreak only if there were any traces or logs, so that the - // output does not look like 1 big block. - let mut add_newline = false; - if verbosity > 1 && !result.logs.is_empty() { - add_newline = true; - println!("Logs:"); - for log in &result.logs { - println!(" {}", log); - } - } - if verbosity > 2 { - if let (Some(traces), Some(identified_contracts)) = - (&result.traces, &result.identified_contracts) - { - if !result.success && verbosity == 3 || verbosity > 3 { - // add a new line if any logs were printed & to separate them from - // the traces to be printed - if !result.logs.is_empty() { - println!(); - } - let mut ident = identified_contracts.clone(); - let (funcs, events, errors) = &execution_info; - let mut exec_info = ExecutionInfo::new( - // &runner.known_contracts, - &known_contracts, - &mut ident, - &result.labeled_addresses, - funcs, - events, - errors, - ); - let vm = vm(); - let mut trace_string = "".to_string(); - if verbosity > 4 || !result.success { - add_newline = true; - println!("Traces:"); - // print setup calls as well - traces.iter().for_each(|trace| { - trace.construct_trace_string( - 0, - &mut exec_info, - &vm, - " ", - &mut trace_string, - ); - }); - } else if !traces.is_empty() { - add_newline = true; - println!("Traces:"); - traces - .last() - .expect("no last but not empty") - .construct_trace_string( - 0, - &mut exec_info, - &vm, - " ", - &mut trace_string, - ); - } - if !trace_string.is_empty() { - println!("{}", trace_string); - } - } - } - } - if add_newline { - println!(); - } - } - } - }); - - let results = runner.test(&filter, Some(tx))?; - - handle.join().unwrap(); - - if gas_reporting { - for tests in results.values() { - for result in tests.values() { - if let (Some(traces), Some(identified_contracts)) = - (&result.traces, &result.identified_contracts) - { - gas_report.analyze(traces, identified_contracts); - } - } - } - gas_report.finalize(); - println!("{}", gas_report); - } - Ok(TestOutcome::new(results, allow_failure)) - } -} diff --git a/cli/src/cmd/utils.rs b/cli/src/cmd/utils.rs new file mode 100644 index 000000000000..ad5e81cc50ff --- /dev/null +++ b/cli/src/cmd/utils.rs @@ -0,0 +1,204 @@ +use crate::{opts::forge::ContractInfo, term}; +use ethers::{ + abi::Abi, + prelude::{ + artifacts::{CompactBytecode, CompactDeployedBytecode}, + report::NoReporter, + }, + solc::cache::SolFilesCache, +}; +use std::{collections::BTreeMap, path::PathBuf}; + +/// Common trait for all cli commands +pub trait Cmd: clap::Parser + Sized { + type Output; + fn run(self) -> eyre::Result; +} + +use ethers::solc::{artifacts::CompactContractBytecode, Artifact, Project, ProjectCompileOutput}; + +use foundry_utils::to_table; + +/// Compiles the provided [`Project`], throws if there's any compiler error and logs whether +/// compilation was successful or if there was a cache hit. +pub fn compile( + project: &Project, + print_names: bool, + print_sizes: bool, +) -> eyre::Result { + if !project.paths.sources.exists() { + eyre::bail!( + r#"no contracts to compile, contracts folder "{}" does not exist. +Check the configured workspace settings: +{} +If you are in a subdirectory in a Git repository, try adding `--root .`"#, + project.paths.sources.display(), + project.paths + ); + } + + let output = term::with_spinner_reporter(|| project.compile())?; + + if output.has_compiler_errors() { + eyre::bail!(output.to_string()) + } else if output.is_unchanged() { + println!("No files changed, compilation skipped"); + } else { + // print the compiler output / warnings + println!("{}", output); + + // print any sizes or names + if print_names { + let compiled_contracts = output.compiled_contracts_by_compiler_version(); + for (version, contracts) in compiled_contracts.into_iter() { + println!( + " compiler version: {}.{}.{}", + version.major, version.minor, version.patch + ); + for (name, _) in contracts { + println!(" - {}", name); + } + } + } + if print_sizes { + // add extra newline if names were already printed + if print_names { + println!(); + } + let compiled_contracts = output.compiled_contracts_by_compiler_version(); + let mut sizes = BTreeMap::new(); + for (_, contracts) in compiled_contracts.into_iter() { + for (name, contract) in contracts { + let size = contract + .get_bytecode_bytes() + .map(|bytes| bytes.0.len()) + .unwrap_or_default(); + sizes.insert(name, size); + } + } + let json = serde_json::to_value(&sizes)?; + println!("name size (bytes)"); + println!("-----------------------------"); + println!("{}", to_table(json)); + } + } + + Ok(output) +} + +/// Compiles the provided [`Project`], throws if there's any compiler error and logs whether +/// compilation was successful or if there was a cache hit. +/// Doesn't print anything to stdout, thus is "suppressed". +pub fn suppress_compile(project: &Project) -> eyre::Result { + if !project.paths.sources.exists() { + eyre::bail!( + r#"no contracts to compile, contracts folder "{}" does not exist. +Check the configured workspace settings: +{} +If you are in a subdirectory in a Git repository, try adding `--root .`"#, + project.paths.sources.display(), + project.paths + ); + } + + let output = ethers::solc::report::with_scoped( + ðers::solc::report::Report::new(NoReporter::default()), + || project.compile(), + )?; + + if output.has_compiler_errors() { + eyre::bail!(output.to_string()) + } + + Ok(output) +} + +/// Compile a set of files not necessarily included in the `project`'s source dir +pub fn compile_files(project: &Project, files: Vec) -> eyre::Result { + let output = term::with_spinner_reporter(|| project.compile_files(files))?; + + if output.has_compiler_errors() { + eyre::bail!(output.to_string()) + } + println!("{}", output); + Ok(output) +} + +/// Given a project and its compiled artifacts, proceeds to return the ABI, Bytecode and +/// Runtime Bytecode of the given contract. +pub fn read_artifact( + project: &Project, + compiled: ProjectCompileOutput, + contract: ContractInfo, +) -> eyre::Result<(Abi, CompactBytecode, CompactDeployedBytecode)> { + Ok(match contract.path { + Some(path) => get_artifact_from_path(project, path, contract.name)?, + None => get_artifact_from_name(contract, compiled)?, + }) +} + +/// Helper function for finding a contract by ContractName +// TODO: Is there a better / more ergonomic way to get the artifacts given a project and a +// contract name? +fn get_artifact_from_name( + contract: ContractInfo, + compiled: ProjectCompileOutput, +) -> eyre::Result<(Abi, CompactBytecode, CompactDeployedBytecode)> { + let mut has_found_contract = false; + let mut contract_artifact = None; + + for (artifact_id, artifact) in compiled.into_artifacts() { + if artifact_id.name == contract.name { + if has_found_contract { + eyre::bail!("contract with duplicate name. pass path") + } + has_found_contract = true; + contract_artifact = Some(artifact); + } + } + + Ok(match contract_artifact { + Some(artifact) => ( + artifact + .abi + .map(Into::into) + .ok_or_else(|| eyre::Error::msg(format!("abi not found for {}", contract.name)))?, + artifact.bytecode.ok_or_else(|| { + eyre::Error::msg(format!("bytecode not found for {}", contract.name)) + })?, + artifact.deployed_bytecode.ok_or_else(|| { + eyre::Error::msg(format!("bytecode not found for {}", contract.name)) + })?, + ), + None => { + eyre::bail!("could not find artifact") + } + }) +} + +/// Find using src/ContractSource.sol:ContractName +fn get_artifact_from_path( + project: &Project, + contract_path: String, + contract_name: String, +) -> eyre::Result<(Abi, CompactBytecode, CompactDeployedBytecode)> { + // Get sources from the requested location + let abs_path = dunce::canonicalize(PathBuf::from(contract_path))?; + + let cache = SolFilesCache::read_joined(&project.paths)?; + + // Read the artifact from disk + let artifact: CompactContractBytecode = cache.read_artifact(abs_path, &contract_name)?; + + Ok(( + artifact + .abi + .ok_or_else(|| eyre::Error::msg(format!("abi not found for {}", contract_name)))?, + artifact + .bytecode + .ok_or_else(|| eyre::Error::msg(format!("bytecode not found for {}", contract_name)))?, + artifact + .deployed_bytecode + .ok_or_else(|| eyre::Error::msg(format!("bytecode not found for {}", contract_name)))?, + )) +} diff --git a/cli/src/forge.rs b/cli/src/forge.rs index 1b2aeb251b96..2ed1080e9959 100644 --- a/cli/src/forge.rs +++ b/cli/src/forge.rs @@ -3,7 +3,7 @@ mod opts; mod term; mod utils; -use crate::cmd::{watch, Cmd}; +use crate::cmd::{forge::watch, Cmd}; use ethers::solc::{Project, ProjectPathsConfig}; use opts::forge::{Dependency, Opts, Subcommands}; @@ -31,7 +31,7 @@ fn main() -> eyre::Result<()> { } Subcommands::Build(cmd) => { if cmd.is_watch() { - utils::block_on(crate::cmd::watch::watch_build(cmd))?; + utils::block_on(crate::cmd::forge::watch::watch_build(cmd))?; } else { cmd.run()?; } @@ -40,10 +40,10 @@ fn main() -> eyre::Result<()> { cmd.run()?; } Subcommands::VerifyContract(args) => { - utils::block_on(cmd::verify::run_verify(&args))?; + utils::block_on(cmd::forge::verify::run_verify(&args))?; } Subcommands::VerifyCheck(args) => { - utils::block_on(cmd::verify::run_verify_check(&args))?; + utils::block_on(cmd::forge::verify::run_verify_check(&args))?; } Subcommands::Create(cmd) => { cmd.run()?; diff --git a/cli/src/opts/cast.rs b/cli/src/opts/cast.rs index 12c3bb744aa6..e61805889b9b 100644 --- a/cli/src/opts/cast.rs +++ b/cli/src/opts/cast.rs @@ -7,7 +7,7 @@ use ethers::{ }; use super::{ClapChain, EthereumOpts, Wallet}; -use crate::utils::parse_u256; +use crate::{cmd::cast::find_block::FindBlockArgs, utils::parse_u256}; #[derive(Debug, Subcommand)] #[clap(about = "Perform Ethereum RPC calls from the comfort of your command line.")] @@ -506,12 +506,7 @@ pub enum Subcommands { name = "find-block", about = "Prints the block number closes to the provided timestamp" )] - FindBlock { - #[clap(help = "The UNIX timestamp to search for (in seconds)")] - timestamp: u64, - #[clap(long, env = "ETH_RPC_URL")] - rpc_url: String, - }, + FindBlock(FindBlockArgs), #[clap(about = "Generate shell completions script")] Completions { #[clap(arg_enum)] diff --git a/cli/src/opts/evm.rs b/cli/src/opts/evm.rs index deae322dfa19..8bb4066b5eb5 100644 --- a/cli/src/opts/evm.rs +++ b/cli/src/opts/evm.rs @@ -1,7 +1,6 @@ //! cli arguments for configuring the evm settings use clap::Parser; use ethers::types::{Address, U256}; -use evm_adapters::evm_opts::EvmType; use foundry_config::{ figment::{ self, @@ -27,7 +26,7 @@ use serde::Serialize; // // ```ignore // use foundry_config::Config; -// use evm_adapter::EvmOpts; +// use forge::executor::opts::EvmOpts; // # fn t(args: EvmArgs) { // let figment = Config::figment_with_root(".").merge(args); // let opts = figment.extract::().unwrap() @@ -36,55 +35,63 @@ use serde::Serialize; // See also [`BuildArgs`] #[derive(Debug, Clone, Parser, Serialize)] pub struct EvmArgs { - #[clap(flatten)] - #[serde(flatten)] - pub env: EnvArgs, - - #[clap( - long, - short, - help = "the EVM type you want to use (e.g. sputnik)", - default_value = "sputnik" - )] - pub evm_type: EvmType, - - #[clap(help = "fetch state over a remote instead of starting from empty state", long, short)] - #[clap(alias = "rpc-url")] + /// Fetch state over a remote endpoint instead of starting from an empty state. + /// + /// If you want to fetch state from a specific block number, see --fork-block-number. + #[clap(long, short, alias = "rpc-url")] #[serde(rename = "eth_rpc_url", skip_serializing_if = "Option::is_none")] pub fork_url: Option, - #[clap(help = "pins the block number for the state fork", long)] + /// Fetch state from a specific block number over a remote endpoint. + /// + /// See --fork-url. + #[clap(long, requires = "fork-url")] #[serde(skip_serializing_if = "Option::is_none")] pub fork_block_number: Option, - #[clap(help = "the initial balance of each deployed test contract", long)] + /// Disables storage caching entirely. This overrides any settings made in + /// [foundry_config::caching::StorageCachingConfig] + /// + /// See --fork-url. + #[clap( + long, + requires = "fork-url", + help = "Explicitly disables the use of storage. All storage slots are read entirely from the endpoint." + )] + #[serde(skip)] + pub no_storage_caching: bool, + + /// The initial balance of deployed test contracts. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub initial_balance: Option, - #[clap(help = "the address which will be executing all tests", long)] + /// The address which will be executing tests. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub sender: Option
, + /// Enable the FFI cheatcode. #[clap(help = "enables the FFI cheatcode", long)] #[serde(skip)] pub ffi: bool, - #[clap( - help = r#"Verbosity mode of EVM output as number of occurences of the `v` flag (-v, -vv, -vvv, etc.) - 2: print test logs for all tests - 3: print test trace for failing tests - 4: always print test trace, print setup for failing tests - 5: always print test trace and setup -"#, - long, - short, - parse(from_occurrences) - )] + /// Verbosity of the EVM. + /// + /// Pass multiple times to increase the verbosity (e.g. -v, -vv, -vvv). + /// + /// Verbosity levels: + /// 2: Print logs for all tests + /// 3: Print execution traces for failing tests + /// 4: Print execution traces for all tests, and setup traces for failing tests + /// 5: Print execution and setup traces for all tests + #[clap(long, short, parse(from_occurrences))] #[serde(skip)] pub verbosity: u8, - #[clap(help = "enable debugger", long)] - pub debug: bool, + #[clap(flatten)] + #[serde(flatten)] + pub env: EnvArgs, } // Make this set of options a `figment::Provider` so that it can be merged into the `Config` @@ -107,51 +114,65 @@ impl Provider for EvmArgs { dict.insert("ffi".to_string(), self.ffi.into()); } + if self.no_storage_caching { + dict.insert("no_storage_caching".to_string(), self.no_storage_caching.into()); + } + Ok(Map::from([(Config::selected_profile(), dict)])) } } +/// Configures the executor environment during tests. #[derive(Debug, Clone, Default, Parser, Serialize)] +#[clap(next_help_heading = "EXECUTOR ENVIRONMENT CONFIG")] pub struct EnvArgs { - // structopt does not let use `u64::MAX`: - // https://doc.rust-lang.org/std/primitive.u64.html#associatedconstant.MAX - #[clap(help = "the block gas limit", long)] + /// The block gas limit. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub gas_limit: Option, - #[clap(help = "the chainid opcode value", long)] + /// The chain ID. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub chain_id: Option, - #[clap(help = "the tx.gasprice value during EVM execution", long)] + /// The gas price. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub gas_price: Option, - #[clap(help = "the base fee in a block", long)] + /// The base fee in a block. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub block_base_fee_per_gas: Option, - #[clap(help = "the tx.origin value during EVM execution", long)] + /// The transaction origin. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub tx_origin: Option
, - #[clap(help = "the block.coinbase value during EVM execution", long)] + /// The coinbase of the block. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub block_coinbase: Option
, - #[clap(help = "the block.timestamp value during EVM execution", long)] + + /// The timestamp of the block. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub block_timestamp: Option, - #[clap(help = "the block.number value during EVM execution", long)] + /// The block number. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub block_number: Option, - #[clap(help = "the block.difficulty value during EVM execution", long)] + /// The block difficulty. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub block_difficulty: Option, - #[clap(help = "the block.gaslimit value during EVM execution", long)] + /// The block gas limit. + #[clap(long)] #[serde(skip_serializing_if = "Option::is_none")] pub block_gas_limit: Option, - // TODO: Add configuration option for base fee. } diff --git a/cli/src/opts/forge.rs b/cli/src/opts/forge.rs index be8a667beea7..50849e808300 100644 --- a/cli/src/opts/forge.rs +++ b/cli/src/opts/forge.rs @@ -3,7 +3,7 @@ use clap::{Parser, Subcommand, ValueHint}; use ethers::solc::{artifacts::output_selection::ContractOutputSelection, EvmVersion}; use std::{path::PathBuf, str::FromStr}; -use crate::cmd::{ +use crate::cmd::forge::{ bind::BindArgs, build::BuildArgs, config, diff --git a/cli/src/utils.rs b/cli/src/utils.rs index fac3fe7bb7f3..818d7c134e4f 100644 --- a/cli/src/utils.rs +++ b/cli/src/utils.rs @@ -1,8 +1,15 @@ -use std::{future::Future, path::Path, str::FromStr, time::Duration}; +use std::{ + future::Future, + path::{Path, PathBuf}, + str::FromStr, + time::Duration, +}; use ethers::{solc::EvmVersion, types::U256}; -#[cfg(feature = "sputnik-evm")] -use sputnik::Config; +use forge::executor::{opts::EvmOpts, Fork, SpecId}; +use foundry_config::{caching::StorageCachingConfig, Config}; +use tracing_error::ErrorLayer; +use tracing_subscriber::prelude::*; // reexport all `foundry_config::utils` #[doc(hidden)] @@ -52,18 +59,18 @@ impl> FoundryPathExt for T { /// Initializes a tracing Subscriber for logging #[allow(dead_code)] pub fn subscriber() { - tracing_subscriber::FmtSubscriber::builder() - // .with_timer(tracing_subscriber::fmt::time::uptime()) - .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) - .init(); + tracing_subscriber::Registry::default() + .with(tracing_subscriber::EnvFilter::from_default_env()) + .with(ErrorLayer::default()) + .with(tracing_subscriber::fmt::layer()) + .init() } -#[cfg(feature = "sputnik-evm")] -pub fn sputnik_cfg(evm: &EvmVersion) -> Config { +pub fn evm_spec(evm: &EvmVersion) -> SpecId { match evm { - EvmVersion::Istanbul => Config::istanbul(), - EvmVersion::Berlin => Config::berlin(), - EvmVersion::London => Config::london(), + EvmVersion::Istanbul => SpecId::ISTANBUL, + EvmVersion::Berlin => SpecId::BERLIN, + EvmVersion::London => SpecId::LONDON, _ => panic!("Unsupported EVM version"), } } @@ -143,6 +150,60 @@ pub fn block_on(future: F) -> F::Output { rt.block_on(future) } +/// Helper function that returns the [Fork] to use, if any. +/// +/// storage caching for the [Fork] will be enabled if +/// - `fork_url` is present +/// - `fork_block_number` is present +/// - [StorageCachingConfig] allows the `fork_url` + chain id pair +/// - storage is allowed (`no_storage_caching = false`) +/// +/// If all these criteria are met, then storage caching is enabled and storage info will be written +/// to [Config::foundry_cache_dir()]///storage.json +/// +/// for `mainnet` and `--fork-block-number 14435000` on mac the corresponding storage cache will be +/// at `~/.foundry/cache/mainnet/14435000/storage.json` +pub fn get_fork(evm_opts: &EvmOpts, config: &StorageCachingConfig) -> Option { + /// Returns the path where the cache file should be stored + /// + /// or `None` if caching should not be enabled + /// + /// See also [ Config::foundry_block_cache_file()] + fn get_block_storage_path( + evm_opts: &EvmOpts, + config: &StorageCachingConfig, + chain_id: u64, + ) -> Option { + if evm_opts.no_storage_caching { + // storage caching explicitly opted out of + return None + } + let url = evm_opts.fork_url.as_ref()?; + // cache only if block explicitly pinned + let block = evm_opts.fork_block_number?; + + if config.enable_for_endpoint(url) && config.enable_for_chain_id(chain_id) { + return Config::foundry_block_cache_file(chain_id, block) + } + + None + } + + if let Some(ref url) = evm_opts.fork_url { + let chain_id = evm_opts.get_chain_id(); + let cache_storage = get_block_storage_path(evm_opts, config, chain_id); + let fork = Fork { + url: url.clone(), + pin_block: evm_opts.fork_block_number, + cache_path: cache_storage, + chain_id, + }; + return Some(fork) + } + + None +} + /// Conditionally print a message /// /// This macro accepts a predicate and the message to print if the predicate is tru diff --git a/cli/test-utils/src/macros.rs b/cli/test-utils/src/macros.rs index 9e37b302ed45..5a2af7ff8721 100644 --- a/cli/test-utils/src/macros.rs +++ b/cli/test-utils/src/macros.rs @@ -129,8 +129,14 @@ macro_rules! forgetest_external { // Clone the external repository let git_clone = - $crate::util::clone_remote(&format!("https://github.com/{}", $repo), prj.root()); - assert!(git_clone, "could not clone repository"); + $crate::util::clone_remote(&format!("https://github.com/{}", $repo), prj.root()) + .expect("Could not clone repository. Is git installed?"); + assert!( + git_clone.status.success(), + "could not clone repository:\nstdout:\n{}\nstderr:\n{}", + String::from_utf8_lossy(&git_clone.stdout), + String::from_utf8_lossy(&git_clone.stderr) + ); // We just run make install, but we do not care if it worked or not, // since some repositories do not have that target diff --git a/cli/test-utils/src/util.rs b/cli/test-utils/src/util.rs index b676015acbd1..ae79b21e2d39 100644 --- a/cli/test-utils/src/util.rs +++ b/cli/test-utils/src/util.rs @@ -14,7 +14,7 @@ use std::{ fs::File, io::{BufWriter, Write}, path::{Path, PathBuf}, - process::{self, Command, Stdio}, + process::{self, Command}, sync::{ atomic::{AtomicUsize, Ordering}, Arc, Mutex, @@ -40,7 +40,10 @@ pub fn initialize(target: impl AsRef) { } /// Clones a remote repository into the specified directory. -pub fn clone_remote(repo_url: &str, target_dir: impl AsRef) -> bool { +pub fn clone_remote( + repo_url: &str, + target_dir: impl AsRef, +) -> std::io::Result { Command::new("git") .args([ "clone", @@ -50,11 +53,7 @@ pub fn clone_remote(repo_url: &str, target_dir: impl AsRef) -> bool { repo_url, target_dir.as_ref().to_str().expect("Target path for git clone does not exist"), ]) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .expect("Could not clone repository. Is git installed?") - .success() + .output() } /// Setup an empty test project and return a command pointing to the forge @@ -163,7 +162,7 @@ impl TestProject { /// Adds DSTest as a source under "test.sol" pub fn insert_ds_test(&self) -> PathBuf { - let s = include_str!("../../../evm-adapters/testdata/DsTest.sol"); + let s = include_str!("../../../testdata/lib/ds-test/src/test.sol"); self.inner().add_source("test.sol", s).unwrap() } diff --git a/cli/testdata/run_test.sol b/cli/testdata/run_test.sol deleted file mode 100644 index 5ac4e1fdfd23..000000000000 --- a/cli/testdata/run_test.sol +++ /dev/null @@ -1,32 +0,0 @@ -pragma solidity ^0.7.6; - -interface ERC20 { - function balanceOf(address) external view returns (uint256); - function deposit() payable external; -} - -interface VM { - function startPrank(address) external; -} - -contract C { - ERC20 weth = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); - VM constant vm = VM(address(bytes20(uint160(uint256(keccak256('hevm cheat code')))))); - address who = 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045; - - event log_uint(uint256); - - function run() external { - // impersonate the account - vm.startPrank(who); - - uint256 balanceBefore = weth.balanceOf(who); - emit log_uint(balanceBefore); - - weth.deposit{value: 15 ether}(); - - uint256 balanceAfter = weth.balanceOf(who); - emit log_uint(balanceAfter); - - } -} \ No newline at end of file diff --git a/cli/testdata/run_test_lib_linking.sol b/cli/testdata/run_test_lib_linking.sol deleted file mode 100644 index eb42dfc73a7e..000000000000 --- a/cli/testdata/run_test_lib_linking.sol +++ /dev/null @@ -1,38 +0,0 @@ -pragma solidity ^0.7.6; - -interface ERC20 { - function balanceOf(address) external view returns (uint256); - function deposit() payable external; -} - -interface VM { - function startPrank(address) external; -} - -library T { - function getBal(ERC20 t, address who) public view returns (uint256) { - return t.balanceOf(who); - } -} - -contract C { - ERC20 weth = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); - VM constant vm = VM(address(bytes20(uint160(uint256(keccak256('hevm cheat code')))))); - address who = 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045; - - event log_uint(uint256); - - function run() external { - // impersonate the account - vm.startPrank(who); - - uint256 balanceBefore = T.getBal(weth, who); - emit log_uint(balanceBefore); - - weth.deposit{value: 15 ether}(); - - uint256 balanceAfter = weth.balanceOf(who); - emit log_uint(balanceAfter); - - } -} \ No newline at end of file diff --git a/cli/tests/cmd.rs b/cli/tests/cmd.rs index 732bf0130e81..2f879e5297ab 100644 --- a/cli/tests/cmd.rs +++ b/cli/tests/cmd.rs @@ -1,7 +1,7 @@ //! Contains various tests for checking forge's commands use ansi_term::Colour; use ethers::solc::{artifacts::Metadata, ConfigurableContractArtifact}; -use evm_adapters::evm_opts::{EvmOpts, EvmType}; +use forge::executor::opts::EvmOpts; use foundry_cli_test_utils::{ ethers_solc::{remappings::Remapping, PathStyle}, forgetest, forgetest_ignore, forgetest_init, pretty_eq, @@ -11,11 +11,7 @@ use foundry_config::{ parse_with_profile, BasicConfig, Config, OptimizerDetails, SolidityErrorCode, }; use pretty_assertions::assert_eq; -use std::{ - env::{self}, - fs, - str::FromStr, -}; +use std::{env, fs, str::FromStr}; // import forge utils as mod #[allow(unused)] @@ -245,9 +241,7 @@ forgetest_init!(can_get_evm_opts, |prj: TestProject, mut cmd: TestCommand| { assert!(config.ffi); cmd.set_env("FOUNDRY_ETH_RPC_URL", url); - let figment = Config::figment_with_root(prj.root()) - .merge(("evm_type", EvmType::Sputnik)) - .merge(("debug", false)); + let figment = Config::figment_with_root(prj.root()).merge(("debug", false)); let evm_opts: EvmOpts = figment.extract().unwrap(); assert_eq!(evm_opts.fork_url, Some(url.to_string())); }); @@ -472,7 +466,7 @@ Compiler run successful )); }); -// tests that the `run` command works correctly +// Tests that the `run` command works correctly forgetest!(can_execute_run_command, |prj: TestProject, mut cmd: TestCommand| { let script = prj .inner() @@ -494,12 +488,80 @@ contract Demo { cmd.arg("run").arg(script); let output = cmd.stdout_lossy(); assert!(output.ends_with(&format!( - " -Compiler run successful + "Compiler run successful +{} +Gas used: 1751 +== Logs == + script ran +", + Colour::Green.paint("Script ran successfully.") + ),)); +}); + +// Tests that the run command can run arbitrary functions +forgetest!(can_execute_run_command_with_sig, |prj: TestProject, mut cmd: TestCommand| { + let script = prj + .inner() + .add_source( + "Foo", + r#" +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.10; +contract Demo { + event log_string(string); + function myFunction() external { + emit log_string("script ran"); + } +} + "#, + ) + .unwrap(); + + cmd.arg("run").arg(script).arg("--sig").arg("myFunction()"); + let output = cmd.stdout_lossy(); + assert!(output.ends_with(&format!( + "Compiler run successful +{} +Gas used: 1751 +== Logs == + script ran +", + Colour::Green.paint("Script ran successfully.") + ),)); +}); + +// Tests that the run command can run functions with arguments +forgetest!(can_execute_run_command_with_args, |prj: TestProject, mut cmd: TestCommand| { + let script = prj + .inner() + .add_source( + "Foo", + r#" +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.10; +contract Demo { + event log_string(string); + event log_uint(uint); + function run(uint256 a, uint256 b) external { + emit log_string("script ran"); + emit log_uint(a); + emit log_uint(b); + } +} + "#, + ) + .unwrap(); + + cmd.arg("run").arg(script).arg("--sig").arg("run(uint256,uint256)").arg("1").arg("2"); + let output = cmd.stdout_lossy(); + assert!(output.ends_with(&format!( + "Compiler run successful {} -Gas Used: 1751 +Gas used: 3957 == Logs == -script ran + script ran + 1 + 2 ", Colour::Green.paint("Script ran successfully.") ),)); @@ -649,15 +711,16 @@ forgetest_ignore!(can_compile_local_spells, |_: TestProject, mut cmd: TestComman let dss_exec_lib = "src/DssSpell.sol:DssExecLib:0xfD88CeE74f7D78697775aBDAE53f9Da1559728E4"; cmd.args([ - "build", + "test", "--root", root.as_str(), "--fork-url", eth_rpc_url.as_str(), + "--fork-block-number", + "14435000", "--libraries", dss_exec_lib, "-vvv", - "--force", ]); cmd.print_output(); }); diff --git a/cli/tests/integration.rs b/cli/tests/integration.rs index 597ca0933274..0e65db4e5425 100644 --- a/cli/tests/integration.rs +++ b/cli/tests/integration.rs @@ -8,6 +8,10 @@ forgetest_external!(stringutils, "Arachnid/solidity-stringutils"); // forgetest_external!(vaults, "Rari-Capital/vaults"); forgetest_external!(multicall, "makerdao/multicall", &["--block-number", "1"]); forgetest_external!(lootloose, "gakonst/lootloose"); +forgetest_external!(lil_web3, "m1guelpf/lil-web3"); +// Disabled until they fix their submodules: one of them is using SSH which our GitHub action can't +// figure out +// forgetest_external!(maple_loan, "maple-labs/loan"); // Forking tests forgetest_external!(drai, "mds1/drai", 13633752, &["--chain-id", "99"]); diff --git a/config/Cargo.toml b/config/Cargo.toml index 2c9dad4db3d7..ba5059a02c42 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "foundry-config" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = """ Foundry configuration @@ -19,6 +19,7 @@ eyre = "0.6.5" ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["async", "svm-solc"] } Inflector = "0.11.4" +regex = "1.5.5" [dev-dependencies] pretty_assertions = "1.0.0" diff --git a/config/README.md b/config/README.md index 38486b913ae7..4fd8ac548beb 100644 --- a/config/README.md +++ b/config/README.md @@ -93,6 +93,13 @@ block_base_fee_per_gas = 0 block_coinbase = '0x0000000000000000000000000000000000000000' block_timestamp = 0 block_difficulty = 0 +# caches storage retrieved locally for certain chains and endpoints +# can also be restrictied to `chains = ["optimism", "mainnet"]` +# by default only remote endpoints will be cached (no `localhost` or `127.0.0.1`) +# to disable storage caching entirely set `no_storage_caching = true` +rpc_storage_caching = { chains = "all", endpoints = "remote"} +# this overrides `rpc_storage_caching` entirely +no_storage_caching = false ``` ##### Additional Optimizer settings diff --git a/config/src/caching.rs b/config/src/caching.rs new file mode 100644 index 000000000000..d8f8704b51df --- /dev/null +++ b/config/src/caching.rs @@ -0,0 +1,219 @@ +//! Support types for configuring storage caching + +use crate::Chain; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::{fmt, str::FromStr}; + +/// Settings to configure caching of remote +#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] +pub struct StorageCachingConfig { + /// chains to cache + pub chains: CachedChains, + /// endpoints to cache + pub endpoints: CachedEndpoints, +} + +impl StorageCachingConfig { + /// Whether caching should be enabled for the endpoint + pub fn enable_for_endpoint(&self, endpoint: impl AsRef) -> bool { + self.endpoints.is_match(endpoint) + } + + /// Whether caching should be enabled for the chain id + pub fn enable_for_chain_id(&self, chain_id: u64) -> bool { + // ignore dev chain + if chain_id == 1337 { + return false + } + self.chains.is_match(chain_id) + } +} + +/// What chains to cache +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum CachedChains { + /// Cache all chains + All, + /// Don't cache anything + None, + /// Only cache these chains + Chains(Vec), +} +impl CachedChains { + /// Whether the `endpoint` matches + pub fn is_match(&self, chain: u64) -> bool { + match self { + CachedChains::All => true, + CachedChains::None => false, + CachedChains::Chains(chains) => chains.iter().any(|c| c.id() == chain), + } + } +} + +impl Serialize for CachedChains { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + CachedChains::All => serializer.serialize_str("all"), + CachedChains::None => serializer.serialize_str("none"), + CachedChains::Chains(chains) => chains.serialize(serializer), + } + } +} + +impl<'de> Deserialize<'de> for CachedChains { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(untagged)] + enum Chains { + All(String), + Chains(Vec), + } + + match Chains::deserialize(deserializer)? { + Chains::All(s) => match s.as_str() { + "all" => Ok(CachedChains::All), + "none" => Ok(CachedChains::None), + s => Err(serde::de::Error::unknown_variant(s, &["all", "none"])), + }, + Chains::Chains(chains) => Ok(CachedChains::Chains(chains)), + } + } +} + +impl Default for CachedChains { + fn default() -> Self { + CachedChains::All + } +} + +/// What endpoints to enable caching for +#[derive(Debug, Clone)] +pub enum CachedEndpoints { + /// Cache all endpoints + All, + /// Only cache non-local host endpoints + Remote, + /// Only cache these chains + Pattern(regex::Regex), +} + +impl CachedEndpoints { + /// Whether the `endpoint` matches + pub fn is_match(&self, endpoint: impl AsRef) -> bool { + let endpoint = endpoint.as_ref(); + match self { + CachedEndpoints::All => true, + CachedEndpoints::Remote => { + !endpoint.contains("localhost:") && !endpoint.contains("127.0.0.1:") + } + CachedEndpoints::Pattern(re) => re.is_match(endpoint), + } + } +} + +impl PartialEq for CachedEndpoints { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (&CachedEndpoints::Pattern(ref a), &CachedEndpoints::Pattern(ref b)) => { + a.as_str() == b.as_str() + } + (&CachedEndpoints::All, &CachedEndpoints::All) => true, + (&CachedEndpoints::Remote, &CachedEndpoints::Remote) => true, + _ => false, + } + } +} + +impl Eq for CachedEndpoints {} + +impl Default for CachedEndpoints { + fn default() -> Self { + CachedEndpoints::Remote + } +} + +impl fmt::Display for CachedEndpoints { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CachedEndpoints::All => f.write_str("all"), + CachedEndpoints::Remote => f.write_str("remote"), + CachedEndpoints::Pattern(s) => s.fmt(f), + } + } +} + +impl FromStr for CachedEndpoints { + type Err = regex::Error; + + fn from_str(s: &str) -> Result { + match s { + "all" => Ok(CachedEndpoints::All), + "remote" => Ok(CachedEndpoints::Remote), + _ => Ok(CachedEndpoints::Pattern(s.parse()?)), + } + } +} + +impl<'de> Deserialize<'de> for CachedEndpoints { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + String::deserialize(deserializer)?.parse().map_err(serde::de::Error::custom) + } +} + +impl Serialize for CachedEndpoints { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + CachedEndpoints::All => serializer.serialize_str("all"), + CachedEndpoints::Remote => serializer.serialize_str("remote"), + CachedEndpoints::Pattern(pattern) => serializer.serialize_str(pattern.as_str()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_parse_storage_config() { + #[derive(Serialize, Deserialize)] + pub struct Wrapper { + pub rpc_storage_caching: StorageCachingConfig, + } + + let s = r#"rpc_storage_caching = { chains = "all", endpoints = "remote"}"#; + let w: Wrapper = toml::from_str(s).unwrap(); + + assert_eq!( + w.rpc_storage_caching, + StorageCachingConfig { chains: CachedChains::All, endpoints: CachedEndpoints::Remote } + ); + + let s = r#"rpc_storage_caching = { chains = [1, "optimism", 999999], endpoints = "all"}"#; + let w: Wrapper = toml::from_str(s).unwrap(); + + assert_eq!( + w.rpc_storage_caching, + StorageCachingConfig { + chains: CachedChains::Chains(vec![ + Chain::Named(ethers_core::types::Chain::Mainnet), + Chain::Named(ethers_core::types::Chain::Optimism), + Chain::Id(999999) + ]), + endpoints: CachedEndpoints::All + } + ) + } +} diff --git a/config/src/lib.rs b/config/src/lib.rs index 62ae26805e0e..f6ecaa7ebfbf 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -1,6 +1,9 @@ //! foundry configuration. +extern crate core; + use std::{ borrow::Cow, + fmt, path::{Path, PathBuf}, str::FromStr, }; @@ -15,6 +18,7 @@ pub use figment; use semver::Version; use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use crate::caching::StorageCachingConfig; use ethers_core::types::{Address, U256}; pub use ethers_solc::artifacts::OptimizerDetails; use ethers_solc::{ @@ -24,6 +28,7 @@ use ethers_solc::{ remappings::{RelativeRemapping, Remapping}, ConfigurableArtifacts, EvmVersion, Project, ProjectPathsConfig, Solc, SolcConfig, }; +use eyre::{ContextCompat, WrapErr}; use figment::{providers::Data, value::Value}; use inflector::Inflector; @@ -34,6 +39,8 @@ mod macros; pub mod utils; pub use crate::utils::*; +pub mod caching; + /// Foundry configuration /// /// # Defaults @@ -200,6 +207,11 @@ pub struct Config { /// If set to true, changes compilation pipeline to go through the Yul intermediate /// representation. pub via_ir: bool, + /// RPC storage caching settings determines what chains and endpoints to cache + pub rpc_storage_caching: StorageCachingConfig, + /// Disables storage caching entirely. This overrides any settings made in + /// `rpc_storage_caching` + pub no_storage_caching: bool, /// The root path where the config detection started from, `Config::with_root` #[doc(hidden)] // We're skipping serialization here, so it won't be included in the [`Config::to_string()`] @@ -698,6 +710,35 @@ impl Config { dirs_next::home_dir().map(|p| p.join(Config::FOUNDRY_DIR_NAME)) } + /// Returns the path to foundry's cache dir `~/.foundry/cache` + pub fn foundry_cache_dir() -> Option { + Self::foundry_dir().map(|p| p.join("cache")) + } + + /// Returns the path to the cache file of the `block` on the `chain` + /// `~/.foundry/cache///storage.json` + pub fn foundry_block_cache_file(chain_id: impl Into, block: u64) -> Option { + Some( + Config::foundry_cache_dir()? + .join(chain_id.into().to_string()) + .join(format!("{}", block)) + .join("storage.json"), + ) + } + + #[doc = r#"Returns the path to `foundry`'s data directory inside the user's data directory + |Platform | Value | Example | + | ------- | ------------------------------------- | -------------------------------- | + | Linux | `$XDG_CONFIG_HOME` or `$HOME`/.config/foundry | /home/alice/.config/foundry| + | macOS | `$HOME`/Library/Application Support/foundry | /Users/Alice/Library/Application Support/foundry | + | Windows | `{FOLDERID_RoamingAppData}/foundry` | C:\Users\Alice\AppData\Roaming/foundry | + "#] + pub fn data_dir() -> eyre::Result { + let path = dirs_next::data_dir().wrap_err("Failed to find data directory")?.join("foundry"); + std::fs::create_dir_all(&path).wrap_err("Failed to create module directory")?; + Ok(path) + } + /// Returns the path to the `foundry.toml` file, the file is searched for in /// the current working directory and all parent directories until the root, /// and the first hit is used. @@ -855,9 +896,12 @@ impl Default for Config { block_number: 0, fork_block_number: None, chain_id: None, - // toml-rs can't handle larger number because integers are stored signed - // https://github.com/alexcrichton/toml-rs/issues/256 - gas_limit: i64::MAX as u64, + // We want the gas limit to be high, but if we pick a value that is too high we end up + // allowing `mstore`s and `mload`s at very high memory regions, which may cause a panic. + // + // 80m gas was arbitrarily chosen, but corresponds to about 16MiB of memory if only + // used for `mload`/`mstore`. + gas_limit: 80_000_000, gas_price: 0, block_base_fee_per_gas: 0, block_coinbase: Address::zero(), @@ -871,9 +915,12 @@ impl Default for Config { ignored_error_codes: vec![SolidityErrorCode::SpdxLicenseNotProvided], __non_exhaustive: (), via_ir: false, + rpc_storage_caching: Default::default(), + no_storage_caching: false, } } } + /// A non-exhaustive list of solidity error codes #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum SolidityErrorCode { @@ -1230,14 +1277,83 @@ impl BasicConfig { } /// Either a named or chain id or the actual id value -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] #[serde(untagged)] pub enum Chain { - #[serde(with = "from_str_lowercase")] + #[serde(serialize_with = "from_str_lowercase::serialize")] Named(ethers_core::types::Chain), Id(u64), } +impl Chain { + /// The id of the chain + pub fn id(&self) -> u64 { + match self { + Chain::Named(chain) => *chain as u64, + Chain::Id(id) => *id, + } + } +} + +impl fmt::Display for Chain { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Chain::Named(chain) => chain.fmt(f), + Chain::Id(id) => { + if let Ok(chain) = ethers_core::types::Chain::try_from(*id) { + chain.fmt(f) + } else { + id.fmt(f) + } + } + } + } +} + +impl From for Chain { + fn from(id: ethers_core::types::Chain) -> Self { + Chain::Named(id) + } +} + +impl From for Chain { + fn from(id: u64) -> Self { + Chain::Id(id) + } +} + +impl From for u64 { + fn from(c: Chain) -> Self { + match c { + Chain::Named(c) => c as u64, + Chain::Id(id) => id, + } + } +} + +impl<'de> Deserialize<'de> for Chain { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(untagged)] + enum ChainId { + Named(String), + Id(u64), + } + + match ChainId::deserialize(deserializer)? { + ChainId::Named(s) => { + s.to_lowercase().parse().map(Chain::Named).map_err(serde::de::Error::custom) + } + ChainId::Id(id) => Ok(ethers_core::types::Chain::try_from(id) + .map(Chain::Named) + .unwrap_or_else(|_| Chain::Id(id))), + } + } +} + mod from_str_lowercase { use std::str::FromStr; @@ -1261,15 +1377,6 @@ mod from_str_lowercase { } } -impl From for u64 { - fn from(c: Chain) -> Self { - match c { - Chain::Named(c) => c as u64, - Chain::Id(id) => id, - } - } -} - fn canonic(path: impl Into) -> PathBuf { let path = path.into(); ethers_solc::utils::canonicalize(&path).unwrap_or(path) @@ -1281,6 +1388,7 @@ mod tests { use figment::error::Kind::InvalidType; use std::str::FromStr; + use crate::caching::{CachedChains, CachedEndpoints}; use figment::{value::Value, Figment}; use pretty_assertions::assert_eq; @@ -1466,6 +1574,7 @@ mod tests { verbosity = 3 remappings = ["ds-test=lib/ds-test/"] via_ir = true + rpc_storage_caching = { chains = [1, "optimism", 999999], endpoints = "all"} "#, )?; @@ -1480,6 +1589,14 @@ mod tests { remappings: vec![Remapping::from_str("ds-test=lib/ds-test/").unwrap().into()], verbosity: 3, via_ir: true, + rpc_storage_caching: StorageCachingConfig { + chains: CachedChains::Chains(vec![ + Chain::Named(ethers_core::types::Chain::Mainnet), + Chain::Named(ethers_core::types::Chain::Optimism), + Chain::Id(999999) + ]), + endpoints: CachedEndpoints::All + }, ..Config::default() } ); diff --git a/evm-adapters/Cargo.toml b/evm-adapters/Cargo.toml deleted file mode 100644 index 82dd081782fb..000000000000 --- a/evm-adapters/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "evm-adapters" -version = "0.1.0" -authors = ["Georgios Konstantopoulos "] -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -foundry-utils = { path = "./../utils" } - -sputnik = { package = "evm", git = "https://github.com/rust-blockchain/evm", default-features = false, optional = true, features = ["std"] } - -ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full"] } -ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -eyre = "0.6.5" -once_cell = "1.9.0" -tracing = "0.1.28" -bytes = "1.1.0" -tokio = { version = "1.12.0", features = ["rt-multi-thread", "macros"] } -hex = "0.4.3" -thiserror = "1.0.29" -proptest = "1.0.0" -parking_lot = "0.11.2" -futures = "0.3.17" -revm_precompiles = { git = "https://github.com/bluealloy/revm", default-features = false, features = ["k256_ecrecover"] } -serde_json = "1.0.72" -serde = "1.0.130" -ansi_term = "0.12.1" -comfy-table = "5.0.0" - -[dev-dependencies] -ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full", "solc-tests"] } -foundry-utils = { path = "./../utils", features = ["test"] } - -[features] -sputnik-helpers = ["sputnik"] diff --git a/evm-adapters/README.md b/evm-adapters/README.md deleted file mode 100644 index 7b61e040ae71..000000000000 --- a/evm-adapters/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# evm-adapters - -Abstraction over various EVM implementations via the `Evm` trait. Currently -supported: [Sputnik EVM](https://github.com/rust-blockchain/evm/). - -Any implementation of the EVM trait receives [fuzzing support](./src/fuzz.rs) -using the [`proptest`](https://docs.rs/proptest) crate. - -## Sputnik's Hooked Executor - -In order to implement cheatcodes, we had to hook in EVM execution. This was done -by implementing a `Handler` and overriding the `call` function, in the -[`CheatcodeHandler`](crate::sputnik::cheatcodes::CheatcodeHandler) - -## Sputnik's Cached Forking backend - -When testing, it is frequently a requirement to be able to fetch live state from -e.g. Ethereum mainnet instead of redeploying the contracts locally yourself. - -To assist with that, we provide 2 forking providers: - -1. [`ForkMemoryBackend`](crate::sputnik::ForkMemoryBackend): A simple provider - which calls out to the remote node for any data that it does not have - locally, and caching the result to avoid unnecessary extra requests -1. [`SharedBackend`](crate::sputnik::cache::SharedBackend): A backend which can - be cheaply cloned and used in different tests, typically useful for test - parallelization. Under the hood, it has a background worker which - deduplicates any outgoing requests from each individual backend, while also - sharing the return values and cache. This backend not in-use yet. diff --git a/evm-adapters/src/blocking_provider.rs b/evm-adapters/src/blocking_provider.rs deleted file mode 100644 index e2a488bcf513..000000000000 --- a/evm-adapters/src/blocking_provider.rs +++ /dev/null @@ -1,101 +0,0 @@ -use ethers::{ - prelude::BlockNumber, - providers::Middleware, - types::{Address, Block, BlockId, Bytes, TxHash, H256, U256, U64}, -}; -use foundry_utils::RuntimeOrHandle; - -#[derive(Debug)] -/// Blocking wrapper around an Ethers middleware, for use in synchronous contexts -/// (powered by a tokio runtime) -pub struct BlockingProvider { - provider: M, - runtime: RuntimeOrHandle, -} - -impl Clone for BlockingProvider { - fn clone(&self) -> Self { - Self { provider: self.provider.clone(), runtime: RuntimeOrHandle::new() } - } -} - -impl BlockingProvider -where - M::Error: 'static, -{ - /// Constructs the provider. If no tokio runtime exists, it instantiates one as well. - pub fn new(provider: M) -> Self { - Self { provider, runtime: RuntimeOrHandle::new() } - } - - /// Receives a future and runs it to completion. - fn block_on(&self, f: F) -> F::Output { - self.runtime.block_on(f) - } - - /// Gets the specified block as well as the chain id concurrently. - pub fn block_and_chainid( - &self, - block_id: Option>, - ) -> eyre::Result<(Block, U256)> { - let block_id = block_id.map(Into::into).unwrap_or(BlockId::Number(BlockNumber::Latest)); - let f = async { - let block = self.provider.get_block(block_id); - let chain_id = self.provider.get_chainid(); - tokio::try_join!(block, chain_id) - }; - let (block, chain_id) = self.block_on(f)?; - Ok((block.ok_or_else(|| eyre::eyre!("block {:?} not found", block_id))?, chain_id)) - } - - /// Gets the nonce, balance and code associated with an account. - pub fn get_account( - &self, - address: Address, - block_id: Option, - ) -> eyre::Result<(U256, U256, Bytes)> { - let f = async { - let balance = self.provider.get_balance(address, block_id); - let nonce = self.provider.get_transaction_count(address, block_id); - let code = self.provider.get_code(address, block_id); - tokio::try_join!(balance, nonce, code) - }; - let (balance, nonce, code) = self.block_on(f)?; - - Ok((nonce, balance, code)) - } - - /// Gets the current block number. - pub fn get_block_number(&self) -> Result { - self.block_on(self.provider.get_block_number()) - } - - /// Gets the account's balance at the specified block. - pub fn get_balance(&self, address: Address, block: Option) -> Result { - self.block_on(self.provider.get_balance(address, block)) - } - - /// Gets the account's nonce at the specified block. - pub fn get_transaction_count( - &self, - address: Address, - block: Option, - ) -> Result { - self.block_on(self.provider.get_transaction_count(address, block)) - } - - /// Gets the account's code at the specified block. - pub fn get_code(&self, address: Address, block: Option) -> Result { - self.block_on(self.provider.get_code(address, block)) - } - - /// Gets the value at the specified storage slot & block. - pub fn get_storage_at( - &self, - address: Address, - slot: H256, - block: Option, - ) -> Result { - self.block_on(self.provider.get_storage_at(address, slot, block)) - } -} diff --git a/evm-adapters/src/call_tracing.rs b/evm-adapters/src/call_tracing.rs deleted file mode 100644 index fbfcc54fb46e..000000000000 --- a/evm-adapters/src/call_tracing.rs +++ /dev/null @@ -1,646 +0,0 @@ -use ethers::{ - abi::{Abi, Event, Function, RawLog, Token}, - types::{H160, H256, U256}, -}; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; - -use ansi_term::Colour; - -use foundry_utils::format_token; - -#[cfg(feature = "sputnik")] -use crate::sputnik::cheatcodes::{ - cheatcode_handler::{CHEATCODE_ADDRESS, CONSOLE_ADDRESS}, - CONSOLE_ABI, HEVM_ABI, -}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -/// An arena of `CallTraceNode`s -pub struct CallTraceArena { - /// The arena of nodes - pub arena: Vec, - /// The entry index, denoting the first node's index in the arena - pub entry: usize, -} - -impl Default for CallTraceArena { - fn default() -> Self { - CallTraceArena { arena: vec![Default::default()], entry: 0 } - } -} - -// Gets pretty print strings for tokens -pub fn format_labeled_token(param: &Token, exec_info: &ExecutionInfo<'_>) -> String { - match param { - Token::Address(addr) => { - if let Some(label) = exec_info.labeled_addrs.get(addr) { - format!("{} [{:?}]", label, addr) - } else { - format_token(param) - } - } - _ => format_token(param), - } -} - -/// Function output type -pub enum Output { - /// Decoded vec of tokens - Token(Vec), - /// Not decoded raw bytes - Raw(Vec), -} - -/// A struct with all information about execution -pub struct ExecutionInfo<'a> { - pub contracts: &'a BTreeMap)>, - pub identified_contracts: &'a mut BTreeMap, - pub labeled_addrs: &'a BTreeMap, - pub funcs: &'a BTreeMap<[u8; 4], Function>, - pub events: &'a BTreeMap, - pub errors: &'a Abi, -} - -impl<'a> ExecutionInfo<'a> { - pub fn new( - contracts: &'a BTreeMap)>, - identified_contracts: &'a mut BTreeMap, - labeled_addrs: &'a BTreeMap, - funcs: &'a BTreeMap<[u8; 4], Function>, - events: &'a BTreeMap, - errors: &'a Abi, - ) -> Self { - Self { contracts, identified_contracts, labeled_addrs, funcs, events, errors } - } -} - -impl Output { - pub fn construct_string<'a, 'b>( - self, - exec_info: &'b ExecutionInfo<'a>, - color: Colour, - left: &str, - full_str: &mut String, - ) { - match self { - Output::Token(token) => { - let strings = token - .iter() - .map(|token| format_labeled_token(token, exec_info)) - .collect::>() - .join(", "); - full_str.push_str(&*format!( - "\n{} └─ {} {}", - left.replace("├─", "│").replace("└─", " "), - color.paint("←"), - if strings.is_empty() { "()" } else { &*strings } - )); - } - Output::Raw(bytes) => { - full_str.push_str(&*format!( - "\n{} └─ {} {}", - left.replace("├─", "│").replace("└─", " "), - color.paint("←"), - if bytes.is_empty() { - "()".to_string() - } else { - "0x".to_string() + &hex::encode(&bytes) - } - )); - } - } - } -} - -impl CallTraceArena { - /// Pushes a new trace into the arena, returning the trace that was passed in with updated - /// values - pub fn push_trace(&mut self, entry: usize, mut new_trace: &mut CallTrace) { - match new_trace.depth { - // The entry node, just update it - 0 => { - self.update(new_trace.clone()); - } - // we found the parent node, add the new trace as a child - _ if self.arena[entry].trace.depth == new_trace.depth - 1 => { - new_trace.idx = self.arena.len(); - new_trace.location = self.arena[entry].children.len(); - self.arena[entry].ordering.push(LogCallOrder::Call(new_trace.location)); - let node = CallTraceNode { - parent: Some(entry), - idx: self.arena.len(), - trace: new_trace.clone(), - ..Default::default() - }; - self.arena.push(node); - self.arena[entry].children.push(new_trace.idx); - } - // we haven't found the parent node, go deeper - _ => self.push_trace( - *self.arena[entry].children.last().expect("Disconnected trace"), - new_trace, - ), - } - } - - /// Updates the values in the calltrace held by the arena based on the passed in trace - pub fn update(&mut self, trace: CallTrace) { - let node = &mut self.arena[trace.idx]; - node.trace.update(trace); - } - - /// Updates `identified_contracts` for future use so that after an `evm.reset_state()`, we - /// already know which contract corresponds to which address. - /// - /// `idx` is the call arena index to start at. Generally this will be 0, but if you want to - /// update a subset of the tree, you can pass in a different index - /// - /// `contracts` are the known contracts of (name => (abi, runtime_code)). It is used to identify - /// a deployed contract. - /// - /// `identified_contracts` are the identified contract addresses built up from comparing - /// deployed contracts against `contracts` - /// - /// `evm` is the evm that we used so that we can grab deployed code if needed. A lot of times, - /// the evm state is reset so we wont have any code but it can be useful if we want to - /// pretty print right after a test. - pub fn update_identified<'a, S: Clone, E: crate::Evm>( - &self, - idx: usize, - contracts: &BTreeMap)>, - identified_contracts: &mut BTreeMap, - evm: &'a E, - ) { - let trace = &self.arena[idx].trace; - - #[cfg(feature = "sputnik")] - identified_contracts.insert(*CHEATCODE_ADDRESS, ("VM".to_string(), HEVM_ABI.clone())); - - let res = identified_contracts.get(&trace.addr); - if res.is_none() { - let code = if trace.created { trace.output.clone() } else { evm.code(trace.addr) }; - if let Some((name, (abi, _code))) = contracts - .iter() - .find(|(_key, (_abi, known_code))| diff_score(known_code, &code) < 0.10) - { - identified_contracts.insert(trace.addr, (name.to_string(), abi.clone())); - } - } - - // update all children nodes - self.update_children(idx, contracts, identified_contracts, evm); - } - - /// Updates all children nodes by recursing into `update_identified` - pub fn update_children<'a, S: Clone, E: crate::Evm>( - &self, - idx: usize, - contracts: &BTreeMap)>, - identified_contracts: &mut BTreeMap, - evm: &'a E, - ) { - let children_idxs = &self.arena[idx].children; - children_idxs.iter().for_each(|child_idx| { - self.update_identified(*child_idx, contracts, identified_contracts, evm); - }); - } - - /// Construct a CallTraceArena trace string - /// - /// `idx` is the call arena index to start at. Generally this will be 0, but if you want to - /// print a subset of the tree, you can pass in a different index - /// - /// `contracts` are the known contracts of (name => (abi, runtime_code)). It is used to identify - /// a deployed contract. - /// - /// `identified_contracts` are the identified contract addresses built up from comparing - /// deployed contracts against `contracts` - /// - /// `evm` is the evm that we used so that we can grab deployed code if needed. A lot of times, - /// the evm state is reset so we wont have any code but it can be useful if we want to - /// pretty print right after a test. - /// - /// For a user, `left` input should generally be `""`. Left is used recursively - /// to build the tree print out structure and is built up as we recurse down the tree. - pub fn construct_trace_string<'a, S: Clone, E: crate::Evm>( - &self, - idx: usize, - exec_info: &mut ExecutionInfo<'a>, - evm: &'a E, - left: &str, - full_str: &mut String, - ) { - let trace = &self.arena[idx].trace; - - #[cfg(feature = "sputnik")] - { - exec_info - .identified_contracts - .insert(*CHEATCODE_ADDRESS, ("VM".to_string(), HEVM_ABI.clone())); - exec_info - .identified_contracts - .insert(*CONSOLE_ADDRESS, ("console".to_string(), CONSOLE_ABI.clone())); - } - - #[cfg(feature = "sputnik")] - // color the trace function call & output by success - let color = if trace.addr == *CHEATCODE_ADDRESS { - Colour::Blue - } else if trace.success { - Colour::Green - } else { - Colour::Red - }; - - #[cfg(not(feature = "sputnik"))] - let color = if trace.success { Colour::Green } else { Colour::Red }; - - // we have to clone the name and abi because identified_contracts is later borrowed - // immutably - let res = if let Some((name, abi)) = exec_info.identified_contracts.get(&trace.addr) { - Some((name.clone(), abi.clone())) - } else { - None - }; - if res.is_none() { - // get the code to compare - let code = if trace.created { trace.output.clone() } else { evm.code(trace.addr) }; - if let Some((name, (abi, _code))) = exec_info - .contracts - .iter() - .find(|(_key, (_abi, known_code))| diff_score(known_code, &code) < 0.10) - { - // found matching contract, insert and print - exec_info.identified_contracts.insert(trace.addr, (name.to_string(), abi.clone())); - if trace.created { - full_str.push_str(&*format!( - "\n{}{} {}@{}", - left, - Colour::Yellow.paint("→ new"), - name, - trace.addr - )); - self.construct_children_and_logs(idx, exec_info, evm, left, full_str); - full_str.push_str(&*format!( - "\n{} └─ {} {} bytes of code", - left.replace("├─", "│").replace("└─", " "), - color.paint("←"), - trace.output.len() - )); - } else { - // re-enter this function at the current node - self.construct_trace_string(idx, exec_info, evm, left, full_str); - } - } else if trace.created { - // we couldn't identify, print the children and logs without the abi - full_str.push_str(&*format!( - "\n{}{} @{}", - left, - Colour::Yellow.paint("→ new"), - trace.addr - )); - self.construct_children_and_logs(idx, exec_info, evm, left, full_str); - full_str.push_str(&*format!( - "\n{} └─ {} {} bytes of code", - left.replace("├─", "│").replace("└─", " "), - color.paint("←"), - trace.output.len() - )); - } else { - let output = trace.construct_func_call(exec_info, None, color, left, full_str); - self.construct_children_and_logs(idx, exec_info, evm, left, full_str); - output.construct_string(exec_info, color, left, full_str); - } - } else if let Some((name, _abi)) = res { - if trace.created { - full_str.push_str(&*format!( - "\n{}{} {}@{}", - left, - Colour::Yellow.paint("→ new"), - name, - trace.addr - )); - self.construct_children_and_logs(idx, exec_info, evm, left, full_str); - full_str.push_str(&*format!( - "\n{} └─ {} {} bytes of code", - left.replace("├─", "│").replace("└─", " "), - color.paint("←"), - trace.output.len() - )); - } else { - let output = - trace.construct_func_call(exec_info, Some(&name), color, left, full_str); - self.construct_children_and_logs(idx, exec_info, evm, left, full_str); - output.construct_string(exec_info, color, left, full_str); - } - } - } - - /// Prints child calls and logs in order - pub fn construct_children_and_logs<'a, S: Clone, E: crate::Evm>( - &self, - node_idx: usize, - exec_info: &mut ExecutionInfo<'a>, - evm: &'a E, - left: &str, - full_str: &mut String, - ) { - // Ordering stores a vec of `LogCallOrder` which is populated based on if - // a log or a call was called first. This makes it such that we always print - // logs and calls in the correct order - self.arena[node_idx].ordering.iter().for_each(|ordering| match ordering { - LogCallOrder::Log(index) => { - self.arena[node_idx].construct_log( - exec_info, - *index, - exec_info.events, - left, - full_str, - ); - } - LogCallOrder::Call(index) => { - self.construct_trace_string( - self.arena[node_idx].children[*index], - exec_info, - evm, - &(left.replace("├─", "│").replace("└─", " ") + " ├─ "), - full_str, - ); - } - }); - } -} - -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -/// A node in the arena -pub struct CallTraceNode { - /// Parent node index in the arena - pub parent: Option, - /// Children node indexes in the arena - pub children: Vec, - /// This node's index in the arena - pub idx: usize, - /// The call trace - pub trace: CallTrace, - /// Logs - #[serde(skip)] - pub logs: Vec, - /// Ordering of child calls and logs - pub ordering: Vec, -} - -impl CallTraceNode { - /// Prints a log at a particular index, optionally decoding if abi is provided - pub fn construct_log<'a, 'b>( - &self, - exec_info: &'b ExecutionInfo<'a>, - index: usize, - events: &BTreeMap, - left: &str, - full_str: &mut String, - ) { - let log = &self.logs[index]; - let right = " ├─ "; - - if let Some(event) = events.get(&log.topics[0]) { - if let Ok(parsed) = event.parse_log(log.clone()) { - let params = parsed.params; - let strings = params - .into_iter() - .map(|param| { - format!("{}: {}", param.name, format_labeled_token(¶m.value, exec_info)) - }) - .collect::>() - .join(", "); - full_str.push_str(&*format!( - "\n{}emit {}({})", - left.replace("├─", "│") + right, - Colour::Cyan.paint(event.name.clone()), - strings - )); - return - } - } - - // we didnt decode the log, print it as an unknown log - for (i, topic) in log.topics.iter().enumerate() { - let right = if i == log.topics.len() - 1 && log.data.is_empty() { - " └─ " - } else { - " ├─" - }; - full_str.push_str(&*format!( - "\n{}{}topic {}: {}", - if i == 0 { - left.replace("├─", "│") + right - } else { - left.replace("├─", "│") + " │ " - }, - if i == 0 { " emit " } else { " " }, - i, - Colour::Cyan.paint(format!("0x{}", hex::encode(&topic))) - )) - } - full_str.push_str(&*format!( - "\n{} data: {}", - left.replace("├─", "│").replace("└─", " ") + " │ ", - Colour::Cyan.paint(format!("0x{}", hex::encode(&log.data))) - )) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -/// Ordering enum for calls and logs -/// -/// i.e. if Call 0 occurs before Log 0, it will be pushed into the `CallTraceNode`'s ordering before -/// the log. -pub enum LogCallOrder { - Log(usize), - Call(usize), -} - -/// Call trace of a tx -#[derive(Clone, Default, Debug, Deserialize, Serialize)] -pub struct CallTrace { - pub depth: usize, - pub location: usize, - pub idx: usize, - /// Successful - pub success: bool, - /// Label for an address - pub label: Option, - /// Callee - pub addr: H160, - /// Creation - pub created: bool, - /// Ether value transfer - pub value: U256, - /// Call data, including function selector (if applicable) - pub data: Vec, - /// Gas cost - pub cost: u64, - /// Output - pub output: Vec, -} - -impl CallTrace { - /// Updates a trace given another trace - fn update(&mut self, new_trace: Self) { - self.success = new_trace.success; - self.addr = new_trace.addr; - self.cost = new_trace.cost; - self.output = new_trace.output; - self.data = new_trace.data; - self.addr = new_trace.addr; - } - - /// Prints function call, returning the decoded or raw output - pub fn construct_func_call<'a>( - &self, - exec_info: &mut ExecutionInfo<'a>, - name: Option<&String>, - color: Colour, - left: &str, - full_str: &mut String, - ) -> Output { - // Is data longer than 4, meaning we can attempt to decode it - if self.data.len() >= 4 { - if let Some(func) = exec_info.funcs.get(&self.data[0..4]) { - let mut strings = "".to_string(); - if !self.data[4..].is_empty() { - let params = func.decode_input(&self.data[4..]).expect("Bad func data decode"); - strings = params - .iter() - .map(|token| format_labeled_token(token, exec_info)) - .collect::>() - .join(", "); - - #[cfg(feature = "sputnik")] - if self.addr == *CHEATCODE_ADDRESS && func.name == "expectRevert" { - if let Ok(decoded) = - foundry_utils::decode_revert(&self.data, Some(exec_info.errors)) - { - strings = decoded; - } - } - } - - full_str.push_str(&*format!( - "\n{}[{}] {}::{}{}({})", - left, - self.cost, - color.paint( - // clippy bug makes us do this - #[allow(clippy::or_fun_call)] - self.label.as_ref().unwrap_or(name.unwrap_or(&self.addr.to_string())) - ), - color.paint(func.name.clone()), - if self.value > 0.into() { - format!("{{value: {}}}", self.value) - } else { - "".to_string() - }, - strings, - )); - - if !self.output.is_empty() && self.success { - if let Ok(tokens) = func.decode_output(&self.output[..]) { - return Output::Token(tokens) - } else { - return Output::Raw(self.output[..].to_vec()) - } - } else if !self.output.is_empty() && !self.success { - if let Ok(decoded_error) = - foundry_utils::decode_revert(&self.output[..], Some(exec_info.errors)) - { - return Output::Token(vec![ethers::abi::Token::String(decoded_error)]) - } else { - return Output::Raw(self.output.clone()) - } - } else { - return Output::Raw(vec![]) - } - } - } else { - // fallback function - full_str.push_str(&*format!( - "\n{}[{}] {}::fallback{}()", - left, - self.cost, - color.paint( - // clippy bug makes us do this - #[allow(clippy::or_fun_call)] - self.label.as_ref().unwrap_or(name.unwrap_or(&self.addr.to_string())) - ), - if self.value > 0.into() { - format!("{{value: {}}}", self.value) - } else { - "".to_string() - } - )); - - if !self.success { - if let Ok(decoded_error) = - foundry_utils::decode_revert(&self.output[..], Some(exec_info.errors)) - { - return Output::Token(vec![ethers::abi::Token::String(decoded_error)]) - } - } - return Output::Raw(self.output[..].to_vec()) - } - - // We couldn't decode the function call, so print it as an abstract call - full_str.push_str(&*format!( - "\n{}[{}] {}::{}{}({})", - left, - self.cost, - color.paint(self.label.as_ref().unwrap_or(&self.addr.to_string()).to_string()), - if self.data.len() >= 4 { - hex::encode(&self.data[0..4]) - } else { - hex::encode(&self.data[..]) - }, - if self.value > 0.into() { - format!("{{value: {}}}", self.value) - } else { - "".to_string() - }, - if self.data.len() >= 4 { - hex::encode(&self.data[4..]) - } else { - hex::encode(&vec![][..]) - }, - )); - - if !self.success { - if let Ok(decoded_error) = - foundry_utils::decode_revert(&self.output[..], Some(exec_info.errors)) - { - return Output::Token(vec![ethers::abi::Token::String(decoded_error)]) - } - } - Output::Raw(self.output[..].to_vec()) - } -} - -// very simple fuzzy matching to account for immutables. Will fail for small contracts that are -// basically all immutable vars -fn diff_score(bytecode1: &[u8], bytecode2: &[u8]) -> f64 { - let cutoff_len = usize::min(bytecode1.len(), bytecode2.len()); - let b1 = &bytecode1[..cutoff_len]; - let b2 = &bytecode2[..cutoff_len]; - if cutoff_len == 0 { - return 1.0 - } - - let mut diff_chars = 0; - for i in 0..cutoff_len { - if b1[i] != b2[i] { - diff_chars += 1; - } - } - - // println!("diff_score {}", diff_chars as f64 / cutoff_len as f64); - diff_chars as f64 / cutoff_len as f64 -} diff --git a/evm-adapters/src/evm_opts.rs b/evm-adapters/src/evm_opts.rs deleted file mode 100644 index 2b588079fee2..000000000000 --- a/evm-adapters/src/evm_opts.rs +++ /dev/null @@ -1,193 +0,0 @@ -use ethers::types::{Address, U256}; -use serde::{Deserialize, Serialize}; -use std::str::FromStr; - -#[cfg(feature = "sputnik")] -use sputnik::backend::MemoryVicinity; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum EvmType { - #[cfg(feature = "sputnik")] - Sputnik, -} - -#[cfg(any(feature = "sputnik"))] -impl Default for EvmType { - fn default() -> Self { - // if sputnik is enabled, default to it - #[cfg(feature = "sputnik")] - #[rustfmt::skip] - return EvmType::Sputnik; - } -} - -impl FromStr for EvmType { - type Err = eyre::Error; - - fn from_str(s: &str) -> Result { - // silence this warning which indicates that if no evm features are - // enabled, the Ok(...) will never be reached. - #[allow(unreachable_code)] - Ok(match s.to_lowercase().as_str() { - #[cfg(feature = "sputnik")] - "sputnik" => EvmType::Sputnik, - other => eyre::bail!("unknown EVM type {}", other), - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr(any(feature = "sputnik"), derive(Default))] -pub struct EvmOpts { - #[serde(flatten)] - pub env: Env, - - /// the EVM type you want to use (e.g. sputnik, evmodin) - pub evm_type: EvmType, - - /// fetch state over a remote instead of starting from empty state - #[serde(rename = "eth_rpc_url")] - pub fork_url: Option, - - /// pins the block number for the state fork - pub fork_block_number: Option, - - /// the initial balance of each deployed test contract - pub initial_balance: U256, - - /// the address which will be executing all tests - pub sender: Address, - - /// enables the FFI cheatcode - pub ffi: bool, - - /// Verbosity mode of EVM output as number of occurences - pub verbosity: u8, - - /// enable debugger - pub debug: bool, -} - -#[cfg(feature = "sputnik")] -pub use sputnik_helpers::BackendKind; - -// Helper functions for sputnik -#[cfg(feature = "sputnik")] -mod sputnik_helpers { - use super::*; - - use crate::{sputnik::cache::SharedBackend, FAUCET_ACCOUNT}; - use ethers::providers::Provider; - use sputnik::backend::MemoryBackend; - - pub enum BackendKind<'a> { - Simple(MemoryBackend<'a>), - Shared(SharedBackend), - } - - impl EvmOpts { - #[cfg(feature = "sputnik")] - pub fn backend<'a>( - &'a self, - vicinity: &'a MemoryVicinity, - ) -> eyre::Result> { - let mut backend = MemoryBackend::new(vicinity, Default::default()); - // max out the balance of the faucet - let faucet = - backend.state_mut().entry(*FAUCET_ACCOUNT).or_insert_with(Default::default); - faucet.balance = U256::MAX; - // set deployer nonce to 1 to get the same contract addresses - // as dapptools, provided the sender is also - // `0x00a329c0648769A73afAc7F9381E08FB43dBEA72` - let deployer = backend.state_mut().entry(self.sender).or_insert_with(Default::default); - deployer.nonce = U256::from(1); - - let backend = if let Some(ref url) = self.fork_url { - let provider = Provider::try_from(url.as_str())?; - let init_state = backend.state().clone(); - let cache = crate::sputnik::new_shared_cache(init_state); - let backend = SharedBackend::new( - provider, - cache, - vicinity.clone(), - self.fork_block_number.map(Into::into), - ); - BackendKind::Shared(backend) - } else { - BackendKind::Simple(backend) - }; - - Ok(backend) - } - - #[cfg(feature = "sputnik")] - pub fn vicinity(&self) -> eyre::Result { - Ok(if let Some(ref url) = self.fork_url { - let provider = ethers::providers::Provider::try_from(url.as_str())?; - let rt = tokio::runtime::Runtime::new().expect("could not start tokio rt"); - rt.block_on(crate::sputnik::vicinity( - &provider, - self.env.chain_id, - self.fork_block_number, - Some(self.env.tx_origin), - ))? - } else { - self.env.sputnik_state() - }) - } - } -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct Env { - /// the block gas limit - pub gas_limit: u64, - - /// the chainid opcode value - pub chain_id: Option, - - /// the tx.gasprice value during EVM execution - pub gas_price: u64, - - /// the base fee in a block - pub block_base_fee_per_gas: u64, - - /// the tx.origin value during EVM execution - pub tx_origin: Address, - - /// the block.coinbase value during EVM execution - pub block_coinbase: Address, - - /// the block.timestamp value during EVM execution - pub block_timestamp: u64, - - /// the block.number value during EVM execution" - pub block_number: u64, - - /// the block.difficulty value during EVM execution - pub block_difficulty: u64, - - /// the block.gaslimit value during EVM execution - pub block_gas_limit: Option, - // TODO: Add configuration option for base fee. -} - -impl Env { - #[cfg(feature = "sputnik")] - pub fn sputnik_state(&self) -> MemoryVicinity { - MemoryVicinity { - chain_id: self.chain_id.unwrap_or(99).into(), - - gas_price: self.gas_price.into(), - origin: self.tx_origin, - - block_coinbase: self.block_coinbase, - block_number: self.block_number.into(), - block_timestamp: self.block_timestamp.into(), - block_difficulty: self.block_difficulty.into(), - block_base_fee_per_gas: self.block_base_fee_per_gas.into(), - block_gas_limit: self.block_gas_limit.unwrap_or(self.gas_limit).into(), - block_hashes: Vec::new(), - } - } -} diff --git a/evm-adapters/src/fuzz.rs b/evm-adapters/src/fuzz.rs deleted file mode 100644 index 96fd057d992a..000000000000 --- a/evm-adapters/src/fuzz.rs +++ /dev/null @@ -1,334 +0,0 @@ -//! Fuzzing support abstracted over the [`Evm`](crate::Evm) used -use crate::{Evm, ASSUME_MAGIC_RETURN_CODE}; -use ethers::{ - abi::{Abi, Function, ParamType, Token, Tokenizable}, - types::{Address, Bytes, I256, U256}, -}; -use std::{ - cell::{RefCell, RefMut}, - marker::PhantomData, -}; - -pub use proptest::test_runner::{Config as FuzzConfig, Reason}; -use proptest::{ - prelude::*, - test_runner::{TestError, TestRunner}, -}; -use serde::{Deserialize, Serialize}; - -mod strategies; - -/// Wrapper around any [`Evm`](crate::Evm) implementor which provides fuzzing support using [`proptest`](https://docs.rs/proptest/1.0.0/proptest/). -/// -/// After instantiation, calling `fuzz` will proceed to hammer the deployed smart contract with -/// inputs, until it finds a counterexample. The provided `TestRunner` contains all the -/// configuration which can be overridden via [environment variables](https://docs.rs/proptest/1.0.0/proptest/test_runner/struct.Config.html) -#[derive(Debug)] -pub struct FuzzedExecutor<'a, E, S> { - evm: RefCell<&'a mut E>, - runner: TestRunner, - state: PhantomData, - sender: Address, -} - -impl<'a, S, E: Evm> FuzzedExecutor<'a, E, S> { - pub fn into_inner(self) -> &'a mut E { - self.evm.into_inner() - } - - /// Returns a mutable reference to the fuzzer's internal EVM instance - pub fn as_mut(&self) -> RefMut<'_, &'a mut E> { - self.evm.borrow_mut() - } - - /// Instantiates a fuzzed executor EVM given a testrunner - pub fn new(evm: &'a mut E, runner: TestRunner, sender: Address) -> Self { - Self { evm: RefCell::new(evm), runner, state: PhantomData, sender } - } - - /// Fuzzes the provided function, assuming it is available at the contract at `address` - /// If `should_fail` is set to `true`, then it will stop only when there's a success - /// test case. - /// - /// Returns a list of all the consumed gas and calldata of every fuzz case - pub fn fuzz( - &self, - func: &Function, - address: Address, - should_fail: bool, - abi: Option<&Abi>, - ) -> FuzzTestResult - where - // We need to be able to clone the state so as to snapshot it and reset - // it back after every test run, to have isolation of state across each - // fuzz test run. - S: Clone, - { - let strat = fuzz_calldata(func); - - // Snapshot the state before the test starts running - let pre_test_state = self.evm.borrow().state().clone(); - - // stores the consumed gas and calldata of every successful fuzz call - let fuzz_cases: RefCell> = RefCell::new(Default::default()); - - // stores the latest reason of a test call, this will hold the return reason of failed test - // case if the runner failed - let return_reason: RefCell> = RefCell::new(None); - let revert_reason = RefCell::new(None); - - let mut runner = self.runner.clone(); - tracing::debug!(func = ?func.name, should_fail, "fuzzing"); - let test_error = runner - .run(&strat, |calldata| { - let mut evm = self.evm.borrow_mut(); - // Before each test, we must reset to the initial state - evm.reset(pre_test_state.clone()); - - let (returndata, reason, gas, _) = evm - .call_raw(self.sender, address, calldata.clone(), 0.into(), false) - .expect("could not make raw evm call"); - - // When assume cheat code is triggered return a special string "FOUNDRY::ASSUME" - if returndata.as_ref() == ASSUME_MAGIC_RETURN_CODE { - let _ = return_reason.borrow_mut().insert(reason); - let err = "ASSUME: Too many rejects"; - let _ = revert_reason.borrow_mut().insert(err.to_string()); - return Err(TestCaseError::Reject(err.into())) - } - - // We must check success before resetting the state, otherwise resetting the state - // will also reset the `failed` state variable back to false. - let success = evm.check_success(address, &reason, should_fail); - - // store the result of this test case - let _ = return_reason.borrow_mut().insert(reason); - - if !success { - let revert = - foundry_utils::decode_revert(returndata.as_ref(), abi).unwrap_or_default(); - let _ = revert_reason.borrow_mut().insert(revert); - } - - // This will panic and get caught by the executor - proptest::prop_assert!( - success, - "{}, expected failure: {}, reason: '{}'", - func.name, - should_fail, - match foundry_utils::decode_revert(returndata.as_ref(), abi) { - Ok(e) => e, - Err(e) => e.to_string(), - } - ); - - // push test case to the case set - fuzz_cases.borrow_mut().push(FuzzCase { calldata, gas }); - - Ok(()) - }) - .err() - .map(|test_error| FuzzError { - test_error, - return_reason: return_reason.into_inner().expect("Reason must be set"), - revert_reason: revert_reason.into_inner().expect("Revert error string must be set"), - }); - - self.evm.borrow_mut().reset(pre_test_state); - FuzzTestResult { cases: FuzzedCases::new(fuzz_cases.into_inner()), test_error } - } -} - -/// The outcome of a fuzz test -pub struct FuzzTestResult { - /// Every successful fuzz test case - pub cases: FuzzedCases, - /// if there was a case that resulted in an error, this contains the error and the return - /// reason of the failed call - pub test_error: Option>, -} - -impl FuzzTestResult { - /// Returns `true` if all test cases succeeded - pub fn is_ok(&self) -> bool { - self.test_error.is_none() - } - - /// Returns `true` if a test case failed - pub fn is_err(&self) -> bool { - self.test_error.is_some() - } -} - -pub struct FuzzError { - /// The proptest error occurred as a result of a test case - pub test_error: TestError, - /// The return reason of the offending call - pub return_reason: Reason, - /// The revert string of the offending call - pub revert_reason: String, -} - -/// Container type for all successful test cases -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(transparent)] -pub struct FuzzedCases { - cases: Vec, -} - -impl FuzzedCases { - pub fn new(mut cases: Vec) -> Self { - cases.sort_by_key(|c| c.gas); - Self { cases } - } - - pub fn cases(&self) -> &[FuzzCase] { - &self.cases - } - - pub fn into_cases(self) -> Vec { - self.cases - } - - /// Returns the median gas of all test cases - pub fn median_gas(&self) -> u64 { - let mid = self.cases.len() / 2; - self.cases.get(mid).map(|c| c.gas).unwrap_or_default() - } - - /// Returns the average gas use of all test cases - pub fn mean_gas(&self) -> u64 { - if self.cases.is_empty() { - return 0 - } - - (self.cases.iter().map(|c| c.gas as u128).sum::() / self.cases.len() as u128) as u64 - } - - pub fn highest(&self) -> Option<&FuzzCase> { - self.cases.last() - } - - pub fn lowest(&self) -> Option<&FuzzCase> { - self.cases.first() - } - - pub fn highest_gas(&self) -> u64 { - self.highest().map(|c| c.gas).unwrap_or_default() - } - - pub fn lowest_gas(&self) -> u64 { - self.lowest().map(|c| c.gas).unwrap_or_default() - } -} - -/// Data of a single fuzz test case -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct FuzzCase { - /// The calldata used for this fuzz test - pub calldata: Bytes, - // Consumed gas - pub gas: u64, -} - -/// Given a function, it returns a proptest strategy which generates valid abi-encoded calldata -/// for that function's input types. -pub fn fuzz_calldata(func: &Function) -> impl Strategy + '_ { - // We need to compose all the strategies generated for each parameter in all - // possible combinations - let strats = func.inputs.iter().map(|input| fuzz_param(&input.kind)).collect::>(); - - strats.prop_map(move |tokens| { - tracing::trace!(input = ?tokens); - func.encode_input(&tokens).unwrap().into() - }) -} - -/// The max length of arrays we fuzz for is 256. -const MAX_ARRAY_LEN: usize = 256; - -/// Given an ethabi parameter type, returns a proptest strategy for generating values for that -/// datatype. Works with ABI Encoder v2 tuples. -fn fuzz_param(param: &ParamType) -> impl Strategy { - match param { - ParamType::Address => { - // The key to making this work is the `boxed()` call which type erases everything - // https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html - any::<[u8; 20]>().prop_map(|x| Address::from_slice(&x).into_token()).boxed() - } - ParamType::Bytes => any::>().prop_map(|x| Bytes::from(x).into_token()).boxed(), - // For ints and uints we sample from a U256, then wrap it to the correct size with a - // modulo operation. Note that this introduces modulo bias, but it can be removed with - // rejection sampling if it's determined the bias is too severe. Rejection sampling may - // slow down tests as it resamples bad values, so may want to benchmark the performance - // hit and weigh that against the current bias before implementing - ParamType::Int(n) => match n / 8 { - 32 => any::<[u8; 32]>() - .prop_map(move |x| I256::from_raw(U256::from(&x)).into_token()) - .boxed(), - y @ 1..=31 => any::<[u8; 32]>() - .prop_map(move |x| { - // Generate a uintN in the correct range, then shift it to the range of intN - // by subtracting 2^(N-1) - let uint = U256::from(&x) % U256::from(2).pow(U256::from(y * 8)); - let max_int_plus1 = U256::from(2).pow(U256::from(y * 8 - 1)); - let num = I256::from_raw(uint.overflowing_sub(max_int_plus1).0); - num.into_token() - }) - .boxed(), - _ => panic!("unsupported solidity type int{}", n), - }, - ParamType::Uint(n) => { - strategies::UintStrategy::new(*n, vec![]).prop_map(|x| x.into_token()).boxed() - } - ParamType::Bool => any::().prop_map(|x| x.into_token()).boxed(), - ParamType::String => any::>() - .prop_map(|x| Token::String(unsafe { std::str::from_utf8_unchecked(&x).to_string() })) - .boxed(), - ParamType::Array(param) => proptest::collection::vec(fuzz_param(param), 0..MAX_ARRAY_LEN) - .prop_map(Token::Array) - .boxed(), - ParamType::FixedBytes(size) => (0..*size as u64) - .map(|_| any::()) - .collect::>() - .prop_map(Token::FixedBytes) - .boxed(), - ParamType::FixedArray(param, size) => (0..*size as u64) - .map(|_| fuzz_param(param).prop_map(|param| param.into_token())) - .collect::>() - .prop_map(Token::FixedArray) - .boxed(), - ParamType::Tuple(params) => { - params.iter().map(fuzz_param).collect::>().prop_map(Token::Tuple).boxed() - } - } -} - -#[cfg(test)] -#[cfg(feature = "sputnik")] -mod tests { - use super::*; - - use crate::{ - sputnik::helpers::{fuzzvm, vm}, - test_helpers::COMPILED, - Evm, - }; - - #[test] - fn prints_fuzzed_revert_reasons() { - let mut evm = vm(); - - let compiled = COMPILED.find("FuzzTests").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - let evm = fuzzvm(&mut evm); - - let func = compiled.abi.unwrap().function("testFuzzedRevert").unwrap(); - let res = evm.fuzz(func, addr, false, compiled.abi); - let error = res.test_error.unwrap(); - let revert_reason = error.revert_reason; - assert_eq!(revert_reason, "fuzztest-revert"); - } -} diff --git a/evm-adapters/src/lib.rs b/evm-adapters/src/lib.rs deleted file mode 100644 index 6607606fb083..000000000000 --- a/evm-adapters/src/lib.rs +++ /dev/null @@ -1,302 +0,0 @@ -#![doc = include_str!("../README.md")] -#[cfg(feature = "sputnik")] -/// Abstraction over [Sputnik EVM](https://github.com/rust-blockchain/evm) -pub mod sputnik; -#[cfg(feature = "sputnik")] -use crate::sputnik::cheatcodes::debugger::DebugArena; - -mod blocking_provider; -use crate::call_tracing::CallTraceArena; - -pub use blocking_provider::BlockingProvider; - -pub mod fuzz; - -pub mod call_tracing; - -pub mod gas_report; - -/// Helpers for easily constructing EVM objects. -pub mod evm_opts; - -use ethers::{ - abi::{Abi, Detokenize, Tokenize}, - contract::{decode_function_data, encode_function_data}, - core::types::{Address, Bytes, U256}, -}; - -use foundry_utils::IntoFunction; - -use eyre::Result; -use once_cell::sync::Lazy; - -pub const ASSUME_MAGIC_RETURN_CODE: &[u8] = "FOUNDRY::ASSUME".as_bytes(); - -/// The account that we use to fund all the deployed contracts -pub static FAUCET_ACCOUNT: Lazy
= - Lazy::new(|| Address::from_slice(ðers::utils::keccak256("turbodapp faucet")[12..])); - -/// Errors related to the EVM call execution -#[derive(thiserror::Error, Debug)] -pub enum EvmError { - #[error("Execution reverted: {reason}, (gas: {gas_used})")] - // TODO: Add proper log printing. - /// Error which occurred during execution of an EVM transaction - Execution { reason: String, gas_used: u64, logs: Vec }, - #[error(transparent)] - /// Error which occurred during ABI encoding / decoding of data - AbiError(#[from] ethers::contract::AbiError), - #[error(transparent)] - /// Any other generic error - Eyre(#[from] eyre::Error), -} - -// TODO: Any reason this should be an async trait? -/// Low-level abstraction layer for interfacing with various EVMs. Once instantiated, one -/// only needs to specify the transaction parameters -pub trait Evm { - /// The returned reason type from an EVM (Success / Revert/ Stopped etc.) - type ReturnReason: std::fmt::Debug + PartialEq; - - /// Gets the revert reason type - fn revert() -> Self::ReturnReason; - - fn expected_revert(&self) -> Option<&[u8]>; - - /// Whether a return reason should be considered successful - fn is_success(reason: &Self::ReturnReason) -> bool; - /// Whether a return reason should be considered failing - fn is_fail(reason: &Self::ReturnReason) -> bool; - - /// Sets the provided contract bytecode at the corresponding addresses - fn initialize_contracts>(&mut self, contracts: I); - - /// Gets a reference to the current state of the EVM - fn state(&self) -> &State; - - fn code(&self, address: Address) -> Vec; - - /// Sets the balance at the specified address - fn set_balance(&mut self, address: Address, amount: U256); - - /// Resets the EVM's state to the provided value - fn reset(&mut self, state: State); - - /// Turns on/off tracing, returning the previously set value - fn set_tracing_enabled(&mut self, enabled: bool) -> bool; - - /// Returns whether tracing is enabled - fn tracing_enabled(&self) -> bool; - - /// Grabs debug steps - #[cfg(feature = "sputnik")] - fn debug_calls(&self) -> Vec; - - /// Gets all logs from the execution, regardless of reverts - fn all_logs(&self) -> Vec; - - /// Performs a [`call_unchecked`](Self::call_unchecked), checks if execution reverted, and - /// proceeds to return the decoded response to the user. - fn call( - &mut self, - from: Address, - to: Address, - func: F, - args: T, // derive arbitrary for Tokenize? - value: U256, - abi: Option<&Abi>, - ) -> std::result::Result<(D, Self::ReturnReason, u64, Vec), EvmError> { - let func = func.into(); - let (retdata, status, gas, logs) = self.call_unchecked(from, to, &func, args, value)?; - if Self::is_fail(&status) { - // try to decode the revert reason, else default to the revert status error. - let reason = foundry_utils::decode_revert(retdata.as_ref(), abi) - .unwrap_or_else(|_| format!("{:?}", status)); - Err(EvmError::Execution { reason, gas_used: gas, logs }) - } else { - let retdata = decode_function_data(&func, retdata, false)?; - Ok((retdata, status, gas, logs)) - } - } - - fn traces(&self) -> Vec { - vec![] - } - - fn reset_traces(&mut self) {} - /// Executes the specified EVM call against the state - // TODO: Should we just make this take a `TransactionRequest` or other more - // ergonomic type? - #[tracing::instrument(skip_all, fields(from, to, func = %func.name))] - fn call_unchecked( - &mut self, - from: Address, - to: Address, - func: ðers::abi::Function, - args: T, // derive arbitrary for Tokenize? - value: U256, - ) -> Result<(Bytes, Self::ReturnReason, u64, Vec)> { - let calldata = encode_function_data(func, args)?; - #[allow(deprecated)] - let is_static = func.constant.unwrap_or_default() || - matches!( - func.state_mutability, - ethers::abi::StateMutability::View | ethers::abi::StateMutability::Pure - ); - self.call_raw(from, to, calldata, value, is_static) - } - - fn call_raw( - &mut self, - from: Address, - to: Address, - calldata: Bytes, - value: U256, - is_static: bool, - ) -> Result<(Bytes, Self::ReturnReason, u64, Vec)>; - - /// Deploys the provided contract bytecode and returns the address - fn deploy( - &mut self, - from: Address, - calldata: Bytes, - value: U256, - ) -> Result<(Address, Self::ReturnReason, u64, Vec)>; - - /// Runs the `setUp()` function call to instantiate the contract's state - fn setup(&mut self, address: Address) -> Result<(Self::ReturnReason, Vec)> { - let span = tracing::trace_span!("setup", ?address); - let _enter = span.enter(); - let (_, status, _, logs) = - self.call::<(), _, _>(Address::zero(), address, "setUp()", (), 0.into(), None)?; - Ok((status, logs)) - } - - /// Runs the `failed()` function call to inspect the test contract's state and - /// see whether the `failed` state var is set. This is to allow compatibility - /// with dapptools-style DSTest smart contracts to preserve emitting of logs - fn failed(&mut self, address: Address) -> Result { - let (failed, _, _, _) = self.call::( - Address::zero(), - address, - "failed()(bool)", - (), - 0.into(), - None, - )?; - Ok(failed) - } - - /// Given a smart contract address, the result type and whether it's expected to fail, - /// it returns the test's success status - fn check_success( - &mut self, - address: Address, - reason: &Self::ReturnReason, - should_fail: bool, - ) -> bool { - // Check if the call is successful - let mut success = Self::is_success(reason); - // for successful calls, we should also check the ds-test `failed` - // value - if success { - if let Ok(failed) = self.failed(address) { - success = !failed; - } - } - // check if there is a remaining expected revert - if self.expected_revert().is_some() { - success = false; - } - - // Check Success output: Should Fail vs Success - // - // Success - // ----------------------- - // | | false | true | - // | ----------------------| - // Should Fail | false | false | true | - // | ----------------------| - // | true | true | false | - // ----------------------- - (should_fail && !success) || (!should_fail && success) - } - - // TODO: Should we add a "deploy contract" function as well, or should we assume that - // the EVM is instantiated with a DB that includes any needed contracts? -} - -// Test helpers which are generic over EVM implementation -#[cfg(test)] -mod test_helpers { - use super::*; - use ethers::{ - prelude::Lazy, - solc::{ - artifacts::CompactContractRef, AggregatedCompilerOutput, Project, ProjectPathsConfig, - }, - }; - - pub static COMPILED: Lazy = Lazy::new(|| { - let paths = - ProjectPathsConfig::builder().root("testdata").sources("testdata").build().unwrap(); - let project = Project::builder().paths(paths).ephemeral().no_artifacts().build().unwrap(); - let res = project.compile().unwrap(); - if res.has_compiler_errors() { - panic!("{}", res); - } - res.output() - }); - - pub fn can_call_vm_directly>(mut evm: E, compiled: CompactContractRef) { - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - let (_, status1, _, _) = evm - .call::<(), _, _>( - Address::zero(), - addr, - "greet(string)", - "hi".to_owned(), - 0.into(), - compiled.abi, - ) - .unwrap(); - - let (retdata, status2, _, _) = evm - .call::( - Address::zero(), - addr, - "greeting()(string)", - (), - 0.into(), - compiled.abi, - ) - .unwrap(); - assert_eq!(retdata, "hi"); - - vec![status1, status2].iter().for_each(|reason| { - let res = evm.check_success(addr, reason, false); - assert!(res); - }); - } - - pub fn solidity_unit_test>(mut evm: E, compiled: CompactContractRef) { - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - // call the setup function to deploy the contracts inside the test - let status1 = evm.setup(addr).unwrap().0; - - let (_, status2, _, _) = evm - .call::<(), _, _>(Address::zero(), addr, "testGreeting()", (), 0.into(), compiled.abi) - .unwrap(); - - vec![status1, status2].iter().for_each(|reason| { - let res = evm.check_success(addr, reason, false); - assert!(res); - }); - - // TODO: Add testFail - } -} diff --git a/evm-adapters/src/sputnik/cheatcodes/backend.rs b/evm-adapters/src/sputnik/cheatcodes/backend.rs deleted file mode 100644 index ba64efb9809e..000000000000 --- a/evm-adapters/src/sputnik/cheatcodes/backend.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Cheatcode-enabled backend implementation -use super::Cheatcodes; -use ethers::types::{H160, H256, U256}; -use sputnik::backend::{Backend, Basic}; - -#[derive(Debug, Clone)] -/// A cheatcode backend is a wrapper around the inner backend which returns the -/// cheatcode value if it's already been set, else it falls back to the default value -/// inside the backend. -/// -/// The cheatcode backend can be composed with other enhanced backends, e.g. the forking -/// backend. You should always put the cheatcode backend on the highest layer of your -/// stack of backend middlewares, so that it is always hit first. -pub struct CheatcodeBackend { - /// The inner backend type. - pub backend: B, - /// The enabled cheatcodes - pub cheats: Cheatcodes, -} - -impl Backend for CheatcodeBackend { - // TODO: Override the return values based on the values of `self.cheats` - fn gas_price(&self) -> U256 { - self.backend.gas_price() - } - - fn origin(&self) -> H160 { - self.cheats.origin.unwrap_or_else(|| self.backend.origin()) - } - - fn block_hash(&self, number: U256) -> H256 { - self.cheats - .block_hashes - .get(&number) - .cloned() - .unwrap_or_else(|| self.backend.block_hash(number)) - } - - fn block_number(&self) -> U256 { - self.cheats.block_number.unwrap_or_else(|| self.backend.block_number()) - } - - fn block_coinbase(&self) -> H160 { - self.backend.block_coinbase() - } - - fn block_timestamp(&self) -> U256 { - self.cheats.block_timestamp.unwrap_or_else(|| self.backend.block_timestamp()) - } - - fn block_base_fee_per_gas(&self) -> U256 { - self.cheats.block_base_fee_per_gas.unwrap_or_else(|| self.backend.block_base_fee_per_gas()) - } - - fn block_difficulty(&self) -> U256 { - self.backend.block_difficulty() - } - - fn block_gas_limit(&self) -> U256 { - self.backend.block_gas_limit() - } - - fn chain_id(&self) -> U256 { - self.backend.chain_id() - } - - fn exists(&self, address: H160) -> bool { - self.backend.exists(address) - } - - fn basic(&self, address: H160) -> Basic { - self.backend.basic(address) - } - - fn code(&self, address: H160) -> Vec { - self.backend.code(address) - } - - fn storage(&self, address: H160, index: H256) -> H256 { - self.backend.storage(address, index) - } - - fn original_storage(&self, address: H160, index: H256) -> Option { - self.backend.original_storage(address, index) - } -} diff --git a/evm-adapters/src/sputnik/cheatcodes/cheatcode_handler.rs b/evm-adapters/src/sputnik/cheatcodes/cheatcode_handler.rs deleted file mode 100644 index 06e4fa438514..000000000000 --- a/evm-adapters/src/sputnik/cheatcodes/cheatcode_handler.rs +++ /dev/null @@ -1,2269 +0,0 @@ -//! Hooks to EVM execution -use super::{ - backend::CheatcodeBackend, memory_stackstate_owned::MemoryStackStateOwned, ConsoleCalls, - HEVMCalls, HevmConsoleEvents, -}; -use crate::{ - call_tracing::{CallTrace, CallTraceArena, LogCallOrder}, - sputnik::{cheatcodes::memory_stackstate_owned::ExpectedEmit, Executor, SputnikExecutor}, - Evm, ASSUME_MAGIC_RETURN_CODE, -}; -use std::collections::BTreeMap; - -use std::{fs::File, io::Read, path::Path}; - -use serde::Deserialize; -use sputnik::{ - backend::Backend, - executor::stack::{ - Log, PrecompileFailure, PrecompileOutput, PrecompileSet, StackExecutor, StackExitKind, - StackState, StackSubstateMetadata, - }, - gasometer, Capture, Config, Context, CreateScheme, ExitError, ExitReason, ExitRevert, - ExitSucceed, Handler, Memory, Opcode, Runtime, Transfer, -}; -use std::{ - process::{Command, Stdio}, - rc::Rc, -}; - -use ethers::{ - abi::{RawLog, Token}, - contract::EthLogDecode, - core::{abi::AbiDecode, k256::ecdsa::SigningKey, utils}, - signers::{LocalWallet, Signer}, - solc::{artifacts::CompactContractBytecode, ProjectPathsConfig}, - types::{Address, H160, H256, U256}, -}; - -use std::{convert::Infallible, str::FromStr}; - -use crate::sputnik::cheatcodes::{ - debugger::{CheatOp, DebugArena, DebugNode, DebugStep, OpCode}, - memory_stackstate_owned::Prank, - patch_hardhat_console_log_selector, -}; -use once_cell::sync::Lazy; - -use ethers::abi::Tokenize; - -// This is now getting us the right hash? Also tried [..20] -// Lazy::new(|| Address::from_slice(&keccak256("hevm cheat code")[12..])); -/// Address where the Vm cheatcodes contract lives -pub static CHEATCODE_ADDRESS: Lazy
= Lazy::new(|| { - Address::from_slice(&hex::decode("7109709ECfa91a80626fF3989D68f67F5b1DD12D").unwrap()) -}); - -// This is the address used by console.sol, vendored by nomiclabs/hardhat: -// https://github.com/nomiclabs/hardhat/blob/master/packages/hardhat-core/console.sol -pub static CONSOLE_ADDRESS: Lazy
= Lazy::new(|| { - Address::from_slice(&hex::decode("000000000000000000636F6e736F6c652e6c6f67").unwrap()) -}); - -/// Wrapper around both return types for expectRevert in call or create -enum ExpectRevertReturn { - Call(Capture<(ExitReason, Vec), Infallible>), - Create(Capture<(ExitReason, Option, Vec), Infallible>), -} - -impl ExpectRevertReturn { - pub fn into_call_inner(self) -> Capture<(ExitReason, Vec), Infallible> { - match self { - ExpectRevertReturn::Call(inner) => inner, - _ => panic!("tried to get call response inner from a create"), - } - } - pub fn into_create_inner(self) -> Capture<(ExitReason, Option, Vec), Infallible> { - match self { - ExpectRevertReturn::Create(inner) => inner, - _ => panic!("tried to get create response inner from a call"), - } - } - - pub fn is_call(&self) -> bool { - matches!(self, ExpectRevertReturn::Call(..)) - } -} - -/// For certain cheatcodes, we may internally change the status of the call, i.e. in -/// `expectRevert`. Solidity will see a successful call and attempt to abi.decode for the called -/// function. Therefore, we need to populate the return with dummy bytes such that the decode -/// doesn't fail -pub static DUMMY_OUTPUT: [u8; 320] = [0u8; 320]; - -/// Hooks on live EVM execution and forwards everything else to a Sputnik [`Handler`]. -/// -/// It allows: -/// 1. Logging of values for debugging -/// 2. Modifying chain state live with cheatcodes -/// -/// The `call_inner` and `create_inner` functions are copy-pasted from upstream, so that -/// it can hook in the runtime. They may eventually be removed if Sputnik allows bringing in your -/// own runtime handler. -#[derive(Clone, Debug)] -// TODO: Should this be called `HookedHandler`? Maybe we could implement other hooks -// here, e.g. hardhat console.log-style, or dapptools logs, some ad-hoc method for tracing -// etc. -pub struct CheatcodeHandler { - handler: H, - enable_ffi: bool, - console_logs: Vec, -} - -pub(crate) fn convert_log(log: Log) -> Option { - use HevmConsoleEvents::*; - let log = RawLog { topics: log.topics, data: log.data }; - let event = HevmConsoleEvents::decode_log(&log).ok()?; - let ret = match event { - LogsFilter(inner) => format!("{}", inner.0), - LogBytesFilter(inner) => format!("{}", inner.0), - LogNamedAddressFilter(inner) => format!("{}: {:?}", inner.key, inner.val), - LogNamedBytes32Filter(inner) => { - format!("{}: 0x{}", inner.key, hex::encode(inner.val)) - } - LogNamedDecimalIntFilter(inner) => { - let (sign, val) = inner.val.into_sign_and_abs(); - format!( - "{}: {}{}", - inner.key, - sign, - ethers::utils::format_units(val, inner.decimals.as_u32()).unwrap() - ) - } - LogNamedDecimalUintFilter(inner) => { - format!( - "{}: {}", - inner.key, - ethers::utils::format_units(inner.val, inner.decimals.as_u32()).unwrap() - ) - } - LogNamedIntFilter(inner) => format!("{}: {:?}", inner.key, inner.val), - LogNamedUintFilter(inner) => format!("{}: {:?}", inner.key, inner.val), - LogNamedBytesFilter(inner) => { - format!("{}: 0x{}", inner.key, hex::encode(inner.val)) - } - LogNamedStringFilter(inner) => format!("{}: {}", inner.key, inner.val), - - e => e.to_string(), - }; - Some(ret) -} - -// Forwards everything internally except for the transact_call which is overwritten. -// TODO: Maybe we can pull this functionality up to the `Evm` trait to avoid having so many traits? -impl<'a, 'b, B: Backend, P: PrecompileSet> SputnikExecutor> - for CheatcodeStackExecutor<'a, 'b, B, P> -{ - fn config(&self) -> &Config { - self.handler.config() - } - - fn state(&self) -> &CheatcodeStackState<'a, B> { - self.handler.state() - } - - fn state_mut(&mut self) -> &mut CheatcodeStackState<'a, B> { - self.handler.state_mut() - } - - fn expected_revert(&self) -> Option<&[u8]> { - self.handler.state().expected_revert.as_deref() - } - - fn set_tracing_enabled(&mut self, enabled: bool) -> bool { - let curr = self.state_mut().trace_enabled; - self.state_mut().trace_enabled = enabled; - curr - } - - fn tracing_enabled(&self) -> bool { - self.state().trace_enabled - } - - fn debug_calls(&self) -> Vec { - self.state().debug_steps.clone() - } - - fn gas_left(&self) -> U256 { - // NB: We do this to avoid `function cannot return without recursing` - U256::from(self.state().metadata().gasometer().gas()) - } - - fn gas_used(&self) -> U256 { - // NB: We do this to avoid `function cannot return without recursing` - U256::from(self.state().metadata().gasometer().total_used_gas()) - } - - fn gas_refund(&self) -> U256 { - U256::from(self.state().metadata().gasometer().refunded_gas()) - } - - fn all_logs(&self) -> Vec { - self.handler.state().all_logs.clone() - } - - fn transact_call( - &mut self, - caller: H160, - address: H160, - value: U256, - data: Vec, - gas_limit: u64, - access_list: Vec<(H160, Vec)>, - ) -> (ExitReason, Vec) { - // reset all_logs because its a new call - self.state_mut().all_logs = vec![]; - - let transaction_cost = gasometer::call_transaction_cost(&data, &access_list); - match self.state_mut().metadata_mut().gasometer_mut().record_transaction(transaction_cost) { - Ok(()) => (), - Err(e) => return (e.into(), Vec::new()), - } - - // Initialize initial addresses for EIP-2929 - if self.config().increase_state_access_gas { - let addresses = core::iter::once(caller).chain(core::iter::once(address)); - self.state_mut().metadata_mut().access_addresses(addresses); - - self.handler.initialize_with_access_list(access_list); - } - - self.state_mut().inc_nonce(caller); - - let context = Context { caller, address, apparent_value: value }; - - match self.call_inner( - address, - Some(Transfer { source: caller, target: address, value }), - data, - Some(gas_limit), - false, - false, - false, - context, - ) { - Capture::Exit((s, v)) => { - if self.state().trace_enabled { - self.state_mut().increment_call_index(); - } - - // check if all expected calls were made - if let Some((address, expecteds)) = - self.state().expected_calls.iter().find(|(_, expecteds)| !expecteds.is_empty()) - { - return ( - ExitReason::Revert(ExitRevert::Reverted), - ethers::abi::encode(&[Token::String(format!( - "Expected a call to 0x{} with data {}, but got none", - address, - ethers::types::Bytes::from(expecteds[0].clone()) - ))]), - ) - } - - if !self.state().expected_emits.is_empty() { - return ( - ExitReason::Revert(ExitRevert::Reverted), - ethers::abi::encode(&[Token::String( - "Expected an emit, but no logs were emitted afterward".to_string(), - )]), - ) - } - (s, v) - } - Capture::Trap(_) => { - self.state_mut().increment_call_index(); - unreachable!() - } - } - } - - fn transact_create( - &mut self, - caller: H160, - value: U256, - init_code: Vec, - gas_limit: u64, - access_list: Vec<(H160, Vec)>, - ) -> ExitReason { - // reset all_logs because its a new call - self.state_mut().all_logs = vec![]; - - let transaction_cost = gasometer::create_transaction_cost(&init_code, &access_list); - match self.state_mut().metadata_mut().gasometer_mut().record_transaction(transaction_cost) { - Ok(()) => (), - Err(e) => return e.into(), - }; - self.handler.initialize_with_access_list(access_list); - - match self.create_inner( - caller, - CreateScheme::Legacy { caller }, - value, - init_code, - Some(gas_limit), - false, - ) { - Capture::Exit((s, _, _)) => { - if self.state().trace_enabled { - self.state_mut().increment_call_index(); - } - s - } - Capture::Trap(_) => { - self.state_mut().increment_call_index(); - unreachable!() - } - } - } - - fn create_address(&self, scheme: CreateScheme) -> Address { - self.handler.create_address(scheme) - } - - fn clear_logs(&mut self) { - self.console_logs.clear(); - self.state_mut().substate.logs_mut().clear() - } - - fn raw_logs(&self) -> Vec { - let logs = self.state().substate.logs().to_vec(); - logs.into_iter().map(|log| RawLog { topics: log.topics, data: log.data }).collect() - } - - fn traces(&self) -> Vec { - self.state().traces.clone() - } - - fn reset_traces(&mut self) { - self.state_mut().reset_traces(); - } - - fn logs(&self) -> Vec { - let logs = self.state().substate.logs().to_vec(); - logs.into_iter().filter_map(convert_log).chain(self.console_logs.clone()).collect() - } -} - -/// A [`MemoryStackStateOwned`] state instantiated over a [`CheatcodeBackend`] -pub type CheatcodeStackState<'a, B> = MemoryStackStateOwned<'a, CheatcodeBackend>; - -/// A [`CheatcodeHandler`] which uses a [`CheatcodeStackState`] to store its state and a -/// [`StackExecutor`] for executing transactions. -pub type CheatcodeStackExecutor<'a, 'b, B, P> = - CheatcodeHandler, P>>; - -impl<'a, 'b, B: Backend, P: PrecompileSet> - Executor, CheatcodeStackExecutor<'a, 'b, B, P>> -{ - /// Instantiates a cheatcode-enabled [`Executor`] - pub fn new_with_cheatcodes( - backend: B, - gas_limit: u64, - config: &'a Config, - precompiles: &'b P, - enable_ffi: bool, - enable_trace: bool, - debug: bool, - ) -> Self { - // make this a cheatcode-enabled backend - let backend = CheatcodeBackend { backend, cheats: Default::default() }; - - // create the memory stack state (owned, so that we can modify the backend via - // self.state_mut on the transact_call fn) - let metadata = StackSubstateMetadata::new(gas_limit, config); - let state = MemoryStackStateOwned::new(metadata, backend, enable_trace, debug); - - // create the executor and wrap it with the cheatcode handler - let executor = StackExecutor::new_with_precompiles(state, config, precompiles); - let executor = CheatcodeHandler { handler: executor, enable_ffi, console_logs: Vec::new() }; - - let mut evm = Executor::from_executor(executor, gas_limit); - - // Need to create a non-empty contract at the cheat code address so that the EVM backend - // thinks that something exists there. - evm.initialize_contracts([ - (*CHEATCODE_ADDRESS, vec![0u8; 1].into()), - (*CONSOLE_ADDRESS, vec![0u8; 1].into()), - ]); - - evm - } -} - -// helper for creating an exit type -fn evm_error(retdata: &str) -> Capture<(ExitReason, Vec), Infallible> { - Capture::Exit(( - ExitReason::Revert(ExitRevert::Reverted), - ethers::abi::encode(&[Token::String(retdata.to_owned())]), - )) -} - -// Enum which unifies the deserialization of Hardhat-style artifacts -// with Forge-style artifacts, to get their bytecode. -#[derive(Deserialize)] -#[serde(untagged)] -#[allow(clippy::large_enum_variant)] -enum Bytecode { - Bytecode(BytecodeHelper), - CompactContractBytecode(CompactContractBytecode), -} - -// helper type for deserialization -#[derive(Deserialize)] -struct BytecodeHelper { - #[serde(deserialize_with = "ethers::solc::artifacts::deserialize_bytes")] - bytecode: ethers::types::Bytes, -} - -impl Bytecode { - fn into_inner(self) -> Option { - match self { - Bytecode::Bytecode(inner) => Some(inner.bytecode), - Bytecode::CompactContractBytecode(inner) => { - inner.bytecode.and_then(|bcode| bcode.object.into_bytes()) - } - } - } -} - -// helper for creating the Expected Revert return type, based on if there was a call or a create, -// and if there was any decoded retdata that matched the expected revert value. -fn revert_return_evm( - call: bool, - result: Option<(&[u8], &[u8])>, - err: impl FnOnce() -> T, -) -> ExpectRevertReturn { - let success = - result.map(|(retdata, expected_revert)| retdata == expected_revert).unwrap_or(false); - - match (success, call) { - // Success case for CALLs needs to return a dummy output value which - // can be decoded - (true, true) => ExpectRevertReturn::Call(Capture::Exit(( - ExitReason::Succeed(ExitSucceed::Returned), - DUMMY_OUTPUT.to_vec(), - ))), - // Success case for CREATE doesn't need to return any value but must return a - // dummy address - (true, false) => ExpectRevertReturn::Create(Capture::Exit(( - ExitReason::Succeed(ExitSucceed::Returned), - Some(Address::from_str("0000000000000000000000000000000000000001").unwrap()), - Vec::new(), - ))), - // Failure cases just return the abi encoded error - (false, true) => ExpectRevertReturn::Call(Capture::Exit(( - ExitReason::Revert(ExitRevert::Reverted), - ethers::abi::encode(&[Token::String(err().to_string())]), - ))), - (false, false) => ExpectRevertReturn::Create(Capture::Exit(( - ExitReason::Revert(ExitRevert::Reverted), - None, - ethers::abi::encode(&[Token::String(err().to_string())]), - ))), - } -} - -impl<'a, 'b, B: Backend, P: PrecompileSet> CheatcodeStackExecutor<'a, 'b, B, P> { - /// Checks whether the provided call reverted with an expected revert reason. - fn expected_revert( - &mut self, - res: ExpectRevertReturn, - expected_revert: Option>, - ) -> ExpectRevertReturn { - // return early if there was no revert expected - let expected_revert = match expected_revert { - Some(inner) => inner, - None => return res, - }; - - let call = res.is_call(); - - // If the call was successful (i.e. did not revert) return - // an error. Otherwise, get the return data - let data = match res { - ExpectRevertReturn::Create(Capture::Exit((ExitReason::Revert(_e), None, revdata))) => { - Some(revdata) - } - ExpectRevertReturn::Call(Capture::Exit((ExitReason::Revert(_e), revdata))) => { - Some(revdata) - } - _ => return revert_return_evm(call, None, || "Expected revert did not revert"), - }; - - // if there was no revert data return an error - let data = match data { - Some(inner) => inner, - None => { - return revert_return_evm(call, None, || "Expected revert did not revert with data") - } - }; - - // do the actual check - if data.len() >= 4 && data[0..4] == [8, 195, 121, 160] { - // its a revert string - let decoded_data = ethers::abi::decode(&[ethers::abi::ParamType::Bytes], &data[4..]) - .expect("String error code, but not actual string"); - - let decoded_data = - decoded_data[0].clone().into_bytes().expect("Can never fail because it is bytes"); - - let err = || { - format!( - "Error != expected error: '{}' != '{}'", - String::from_utf8_lossy(&decoded_data[..]), - String::from_utf8_lossy(&expected_revert) - ) - }; - revert_return_evm(call, Some((&decoded_data, &expected_revert)), err) - } else { - let err = || { - format!( - "Error data != expected error data: 0x{} != 0x{}", - hex::encode(&data), - hex::encode(&expected_revert) - ) - }; - revert_return_evm(call, Some((&data, &expected_revert)), err) - } - } - - /// Given a transaction's calldata, it tries to parse it a console call and print the call - fn console_log(&mut self, input: Vec) -> Capture<(ExitReason, Vec), Infallible> { - // replacing hardhat style selectors (`uint`) with abigen style (`uint256`) - let input = patch_hardhat_console_log_selector(input); - let decoded = match ConsoleCalls::decode(&input) { - Ok(inner) => inner, - Err(err) => return evm_error(&err.to_string()), - }; - self.console_logs.push(decoded.to_string()); - Capture::Exit((ExitReason::Succeed(ExitSucceed::Stopped), vec![])) - } - - /// Adds CheatOp to the latest DebugArena - fn add_debug(&mut self, cheatop: CheatOp) { - if self.state().debug_enabled { - let depth = - if let Some(depth) = self.state().metadata().depth() { depth + 1 } else { 0 }; - self.state_mut().debug_mut().push_node( - 0, - DebugNode { - address: *CHEATCODE_ADDRESS, - depth, - steps: vec![DebugStep { - op: OpCode::from(cheatop), - memory: Memory::new(0), - ..Default::default() - }], - ..Default::default() - }, - ); - } - } - - fn prank( - &mut self, - single_call: bool, - msg_sender: Address, - caller: Address, - origin: Option
, - ) -> Result<(), Capture<(ExitReason, Vec), Infallible>> { - let curr_depth = - if let Some(depth) = self.state().metadata().depth() { depth + 1 } else { 0 }; - - let prank = Prank { - prank_caller: msg_sender, - new_caller: caller, - new_origin: origin, - depth: curr_depth, - }; - if single_call { - if self.state().next_prank.is_some() { - return Err(evm_error("You have an active `prank` call already. Use either `prank` or `startPrank`, not both")); - } - self.state_mut().next_prank = Some(prank); - } else { - // startPrank works by using frame depth to determine whether to overwrite - // msg.sender if we set a prank caller at a particular depth, it - // will continue to use the prank caller for any subsequent calls - // until stopPrank is called. - // - // We additionally have to store the original message sender of the cheatcode caller - // so that we dont apply it to any other addresses when depth == - // prank_depth - if let Some(Prank { depth, prank_caller, .. }) = self.state().prank { - if curr_depth == depth && caller == prank_caller { - return Err(evm_error("You have an active `startPrank` at this frame depth already. Use either `prank` or `startPrank`, not both")); - } - } - self.state_mut().prank = Some(prank); - } - Ok(()) - } - - fn expect_revert( - &mut self, - inner: Vec, - ) -> Result<(), Capture<(ExitReason, Vec), Infallible>> { - self.add_debug(CheatOp::EXPECTREVERT); - if self.state().expected_revert.is_some() { - return Err(evm_error( - "You must call another function prior to expecting a second revert.", - )) - } else { - self.state_mut().expected_revert = Some(inner); - } - Ok(()) - } - - /// Given a transaction's calldata, it tries to parse it as an [`HEVM cheatcode`](super::HEVM) - /// call and modify the state accordingly. - fn apply_cheatcode( - &mut self, - input: Vec, - msg_sender: H160, - ) -> Capture<(ExitReason, Vec), Infallible> { - let mut res = vec![]; - let pre_index = self.state().trace_index; - let trace = self.start_trace(*CHEATCODE_ADDRESS, input.clone(), 0.into(), false); - // Get a mutable ref to the state so we can apply the cheats - let decoded = match HEVMCalls::decode(&input) { - Ok(inner) => inner, - Err(err) => return evm_error(&err.to_string()), - }; - - match decoded { - HEVMCalls::Warp(inner) => { - self.add_debug(CheatOp::WARP); - self.state_mut().backend.cheats.block_timestamp = Some(inner.0); - } - HEVMCalls::Roll(inner) => { - self.add_debug(CheatOp::ROLL); - self.state_mut().backend.cheats.block_number = Some(inner.0); - // insert a random block hash for the specified block number if it was not - // specified already - self.state_mut() - .backend - .cheats - .block_hashes - .entry(inner.0) - .or_insert_with(H256::random); - } - HEVMCalls::Fee(inner) => { - self.add_debug(CheatOp::FEE); - self.state_mut().backend.cheats.block_base_fee_per_gas = Some(inner.0); - } - HEVMCalls::Store(inner) => { - self.add_debug(CheatOp::STORE); - self.state_mut().set_storage(inner.0, inner.1.into(), inner.2.into()); - } - HEVMCalls::Load(inner) => { - self.add_debug(CheatOp::LOAD); - res = self.state_mut().storage(inner.0, inner.1.into()).0.to_vec(); - } - HEVMCalls::Ffi(inner) => { - self.add_debug(CheatOp::FFI); - let args = inner.0; - // if FFI is not explicitly enabled at runtime, do not let this be called - // (we could have an FFI cheatcode executor instead but feels like - // over engineering) - if !self.enable_ffi { - return evm_error( - "ffi disabled: run again with --ffi if you want to allow tests to call external scripts", - ); - } - - // execute the command & get the stdout - let output = - match Command::new(&args[0]).args(&args[1..]).stderr(Stdio::inherit()).output() - { - Ok(res) => res.stdout, - Err(err) => return evm_error(&err.to_string()), - }; - - // get the hex string - let output = unsafe { std::str::from_utf8_unchecked(&output) }; - let output = output.strip_prefix("0x").unwrap_or(output); - //decode hex - let decoded = match hex::decode(output) { - Ok(res) => res, - Err(err) => return evm_error(&err.to_string()), - }; - - // encode the data as Bytes - res = ethers::abi::encode(&[Token::Bytes(decoded.to_vec())]); - } - HEVMCalls::GetCode(inner) => { - self.add_debug(CheatOp::GETCODE); - - // TODO: Make this path relative to project root in some way. - let path = if inner.0.ends_with(".json") { - Path::new(&inner.0).to_path_buf() - } else { - let parts = inner.0.split(':').collect::>(); - let contract_file = parts[0]; - let contract_name = if parts.len() == 1 { - parts[0].replace(".sol", "") - } else { - parts[1].to_string() - }; - - let outdir = ProjectPathsConfig::find_artifacts_dir(Path::new("./")); - outdir.join(format!("{}/{}.json", contract_file, contract_name)) - }; - - let mut data = String::new(); - match File::open(path) { - Ok(mut file) => match file.read_to_string(&mut data) { - Ok(_) => {} - Err(e) => return evm_error(&e.to_string()), - }, - Err(e) => return evm_error(&e.to_string()), - } - - match serde_json::from_str::(&data) { - Ok(bytecode) => { - if let Some(bin) = bytecode.into_inner() { - res = ethers::abi::encode(&[Token::Bytes(bin.to_vec())]); - } else { - return evm_error( - "No bytecode for contract. is it abstract or unlinked?", - ) - } - } - Err(e) => return evm_error(&e.to_string()), - } - } - HEVMCalls::Addr(inner) => { - self.add_debug(CheatOp::ADDR); - let sk = inner.0; - if sk.is_zero() { - return evm_error("Bad Cheat Code. Private Key cannot be 0.") - } - // 256 bit priv key -> 32 byte slice - let mut bs: [u8; 32] = [0; 32]; - sk.to_big_endian(&mut bs); - let xsk = match SigningKey::from_bytes(&bs) { - Ok(xsk) => xsk, - Err(err) => return evm_error(&err.to_string()), - }; - let addr = utils::secret_key_to_address(&xsk); - res = ethers::abi::encode(&[Token::Address(addr)]); - } - HEVMCalls::Sign(inner) => { - self.add_debug(CheatOp::SIGN); - let sk = inner.0; - let digest = inner.1; - if sk.is_zero() { - return evm_error("Bad Cheat Code. Private Key cannot be 0.") - } - // 256 bit priv key -> 32 byte slice - let mut bs: [u8; 32] = [0; 32]; - sk.to_big_endian(&mut bs); - - let xsk = match SigningKey::from_bytes(&bs) { - Ok(xsk) => xsk, - Err(err) => return evm_error(&err.to_string()), - }; - let wallet = LocalWallet::from(xsk).with_chain_id(self.handler.chain_id().as_u64()); - - // The EVM precompile does not use EIP-155 - let sig = wallet.sign_hash(digest.into(), false); - - let recovered = match sig.recover(digest) { - Ok(rec) => rec, - Err(e) => return evm_error(&e.to_string()), - }; - - assert_eq!(recovered, wallet.address()); - - let mut r_bytes = [0u8; 32]; - let mut s_bytes = [0u8; 32]; - sig.r.to_big_endian(&mut r_bytes); - sig.s.to_big_endian(&mut s_bytes); - res = ethers::abi::encode(&[Token::Tuple(vec![ - Token::Uint(sig.v.into()), - Token::FixedBytes(r_bytes.to_vec()), - Token::FixedBytes(s_bytes.to_vec()), - ])]); - } - HEVMCalls::Prank0(inner) => { - self.add_debug(CheatOp::PRANK); - let caller = inner.0; - if let Err(err) = self.prank(true, msg_sender, caller, None) { - return err - } - } - HEVMCalls::StartPrank0(inner) => { - self.add_debug(CheatOp::STARTPRANK); - let caller = inner.0; - if let Err(err) = self.prank(false, msg_sender, caller, None) { - return err - } - } - HEVMCalls::Prank1(inner) => { - self.add_debug(CheatOp::PRANK); - let caller = inner.0; - let origin = inner.1; - if let Err(err) = self.prank(true, msg_sender, caller, Some(origin)) { - return err - } - } - HEVMCalls::StartPrank1(inner) => { - self.add_debug(CheatOp::STARTPRANK); - let caller = inner.0; - let origin = inner.1; - if let Err(err) = self.prank(false, msg_sender, caller, Some(origin)) { - return err - } - } - HEVMCalls::StopPrank(_) => { - self.add_debug(CheatOp::STOPPRANK); - self.state_mut().prank = None; - } - HEVMCalls::ExpectRevert0(inner) => { - if let Err(e) = self.expect_revert(inner.0.to_vec()) { - return e - } - } - HEVMCalls::ExpectRevert1(inner) => { - if let Err(e) = self.expect_revert(inner.0.to_vec()) { - return e - } - } - HEVMCalls::Deal(inner) => { - self.add_debug(CheatOp::DEAL); - let who = inner.0; - let value = inner.1; - self.state_mut().reset_balance(who); - self.state_mut().deposit(who, value); - } - HEVMCalls::Etch(inner) => { - self.add_debug(CheatOp::ETCH); - let who = inner.0; - let code = inner.1; - self.state_mut().set_code(who, code.to_vec()); - } - HEVMCalls::Record(_) => { - self.add_debug(CheatOp::RECORD); - self.state_mut().accesses = Some(Default::default()); - } - HEVMCalls::Accesses(inner) => { - self.add_debug(CheatOp::ACCESSES); - let address = inner.0; - // we dont reset all records in case user wants to query multiple address - if let Some(record_accesses) = &self.state().accesses { - res = ethers::abi::encode(&[ - record_accesses - .reads - .borrow_mut() - .remove(&address) - .unwrap_or_default() - .into_tokens()[0] - .clone(), - record_accesses - .writes - .borrow_mut() - .remove(&address) - .unwrap_or_default() - .into_tokens()[0] - .clone(), - ]); - if record_accesses.reads.borrow().len() == 0 && - record_accesses.writes.borrow().len() == 0 - { - self.state_mut().accesses = None; - } - } else { - res = ethers::abi::encode(&[Token::Array(vec![]), Token::Array(vec![])]); - } - } - HEVMCalls::ExpectEmit(inner) => { - self.add_debug(CheatOp::EXPECTEMIT); - let expected_emit = ExpectedEmit { - depth: if let Some(depth) = self.state().metadata().depth() { - depth + 1 - } else { - 0 - }, - log: None, - checks: [inner.0, inner.1, inner.2, inner.3], - found: false, - }; - self.state_mut().expected_emits.push(expected_emit); - } - HEVMCalls::MockCall(inner) => { - self.add_debug(CheatOp::MOCKCALL); - self.state_mut() - .mocked_calls - .entry(inner.0) - .or_default() - .insert(inner.1.to_vec(), inner.2.to_vec()); - } - HEVMCalls::ClearMockedCalls(_) => { - self.add_debug(CheatOp::CLEARMOCKEDCALLS); - self.state_mut().mocked_calls = Default::default(); - } - HEVMCalls::ExpectCall(inner) => { - self.add_debug(CheatOp::EXPECTCALL); - self.state_mut().expected_calls.entry(inner.0).or_default().push(inner.1.to_vec()); - } - HEVMCalls::Label(inner) => { - self.add_debug(CheatOp::LABEL); - let address = inner.0; - let label = inner.1; - - self.state_mut().labels.insert(address, label); - } - HEVMCalls::Assume(inner) => { - self.add_debug(CheatOp::ASSUME); - if !inner.0 { - res = ASSUME_MAGIC_RETURN_CODE.into(); - return Capture::Exit((ExitReason::Revert(ExitRevert::Reverted), res)) - } - } - }; - - self.fill_trace(&trace, true, Some(res.clone()), pre_index); - // cheatcodes should cost 0 gas - if let Some(new_trace) = &trace { - let trace = &mut self.state_mut().trace_mut().arena[new_trace.idx].trace; - trace.cost = 0; - } - // TODO: Add more cheat codes. - Capture::Exit((ExitReason::Succeed(ExitSucceed::Stopped), res)) - } - - // NB: This function is copy-pasted from upstream's `execute`, adjusted so that we call the - // Runtime with our own handler - pub fn execute(&mut self, runtime: &mut Runtime) -> ExitReason { - match runtime.run(self) { - Capture::Exit(s) => s, - Capture::Trap(_) => unreachable!("Trap is Infallible"), - } - } - - /// Executes the call/create while also tracking the state of the machine (including opcodes) - fn debug_execute( - &mut self, - runtime: &mut Runtime, - address: Address, - code: Rc>, - creation: bool, - ) -> ExitReason { - let depth = if let Some(depth) = self.state().metadata().depth() { depth + 1 } else { 0 }; - - match self.debug_run(runtime, address, depth, code, creation) { - Capture::Exit(s) => s, - Capture::Trap(_) => unreachable!("Trap is Infallible"), - } - } - - /// Does *not* actually perform a step, just records the debug information for the step - fn debug_step( - &mut self, - runtime: &mut Runtime, - code: Rc>, - steps: &mut Vec, - pc_ic: Rc>, - ) -> bool { - // grab the pc, opcode and stack - let pc = runtime.machine().position().as_ref().map(|p| *p).unwrap_or_default(); - let mut push_bytes = None; - - if let Some((op, stack)) = runtime.machine().inspect() { - // wrap the op to make it compatible with opcode extensions for cheatops - let wrapped_op = OpCode::from(op); - - // check how big the push size is, and grab the pushed bytes if possible - if let Some(push_size) = wrapped_op.push_size() { - let push_start = pc + 1; - let push_end = pc + 1 + push_size as usize; - if push_end < code.len() { - push_bytes = Some(code[push_start..push_end].to_vec()); - } else { - panic!("PUSH{} exceeds limit of codesize", push_size) - } - } - - // grab the stack data and reverse it (last element is "top" of stack) - let mut stack = stack.data().clone(); - stack.reverse(); - // push the step into the vector - steps.push(DebugStep { - pc, - stack, - memory: runtime.machine().memory().clone(), - op: wrapped_op, - push_bytes, - ic: *pc_ic.get(&pc).as_ref().copied().unwrap_or(&0usize), - total_gas_used: self.handler.used_gas(), - }); - match op { - Opcode::CREATE | - Opcode::CREATE2 | - Opcode::CALL | - Opcode::CALLCODE | - Opcode::DELEGATECALL | - Opcode::STATICCALL => { - // this would create an interrupt, have `debug_run` construct a new vec - // to commit the current vector of steps into the debugarena - // this maintains the call hierarchy correctly - true - } - _ => false, - } - } else { - // failure case. - let mut stack = runtime.machine().stack().data().clone(); - stack.reverse(); - steps.push(DebugStep { - pc, - stack, - memory: runtime.machine().memory().clone(), - op: OpCode::from(Opcode::INVALID), - push_bytes, - ic: *pc_ic.get(&pc).as_ref().copied().unwrap_or(&0usize), - total_gas_used: self.handler.used_gas(), - }); - true - } - } - - fn debug_run( - &mut self, - runtime: &mut Runtime, - address: Address, - depth: usize, - code: Rc>, - creation: bool, - ) -> Capture { - let mut done = false; - let mut res = Capture::Exit(ExitReason::Succeed(ExitSucceed::Returned)); - let mut steps = Vec::new(); - // grab the debug instruction pointers for either construct or runtime bytecode - let dip = if creation { - &mut self.state_mut().debug_instruction_pointers.0 - } else { - &mut self.state_mut().debug_instruction_pointers.1 - }; - // get the program counter => instruction counter mapping from memory or construct it - let ics = if let Some(pc_ic) = dip.get(&address) { - // grabs an Rc of an already created pc -> ic mapping - pc_ic.clone() - } else { - // builds a program counter to instruction counter map - // basically this strips away bytecodes to make it work - // with the sourcemap output from the solc compiler - let mut pc_ic: BTreeMap = BTreeMap::new(); - - let mut i = 0; - let mut push_ctr = 0usize; - while i < code.len() { - let wrapped_op = OpCode::from(Opcode(code[i])); - pc_ic.insert(i, i - push_ctr); - - if let Some(push_size) = wrapped_op.push_size() { - i += push_size as usize; - i += 1; - push_ctr += push_size as usize; - } else { - i += 1; - } - } - let pc_ic = Rc::new(pc_ic); - - dip.insert(address, pc_ic.clone()); - pc_ic - }; - while !done { - // debug step doesnt actually execute the step, it just peeks into the machine - // will return true or false, which signifies whether to push the steps - // as a node and reset the steps vector or not - if self.debug_step(runtime, code.clone(), &mut steps, ics.clone()) && !steps.is_empty() - { - self.state_mut().debug_mut().push_node( - 0, - DebugNode { - address, - depth, - steps: steps.clone(), - creation, - ..Default::default() - }, - ); - steps = Vec::new(); - } - // actually executes the opcode step - let r = runtime.step(self); - match r { - Ok(()) => {} - Err(e) => { - done = true; - // we wont hit an interrupt when we finish stepping - // so we have add the accumulated steps as if debug_step returned true - if !steps.is_empty() { - self.state_mut().debug_mut().push_node( - 0, - DebugNode { - address, - depth, - steps: steps.clone(), - creation, - ..Default::default() - }, - ); - } - match e { - Capture::Exit(s) => res = Capture::Exit(s), - Capture::Trap(_) => unreachable!("Trap is Infallible"), - } - } - } - } - res - } - - fn start_trace( - &mut self, - address: H160, - input: Vec, - transfer: U256, - creation: bool, - ) -> Option { - if self.state().trace_enabled { - let mut trace: CallTrace = CallTrace { - // depth only starts tracking at first child substate and is 0. so add 1 when depth - // is some. - depth: if let Some(depth) = self.state().metadata().depth() { - depth + 1 - } else { - 0 - }, - addr: address, - created: creation, - data: input, - value: transfer, - label: self.state().labels.get(&address).cloned(), - ..Default::default() - }; - - self.state_mut().trace_mut().push_trace(0, &mut trace); - self.state_mut().trace_index = trace.idx; - Some(trace) - } else { - None - } - } - - fn fill_trace( - &mut self, - new_trace: &Option, - success: bool, - output: Option>, - pre_trace_index: usize, - ) { - self.state_mut().trace_index = pre_trace_index; - if let Some(new_trace) = new_trace { - let used_gas = self.handler.used_gas(); - let trace = &mut self.state_mut().trace_mut().arena[new_trace.idx].trace; - trace.output = output.unwrap_or_default(); - trace.cost = used_gas; - trace.success = success; - } - } - - // NB: This function is copy-pasted from upstream's call_inner - #[allow(clippy::too_many_arguments)] - fn call_inner( - &mut self, - code_address: H160, - transfer: Option, - input: Vec, - target_gas: Option, - is_static: bool, - take_l64: bool, - take_stipend: bool, - context: Context, - ) -> Capture<(ExitReason, Vec), Infallible> { - let pre_index = self.state().trace_index; - let trace = self.start_trace( - code_address, - input.clone(), - transfer.as_ref().map(|x| x.value).unwrap_or_default(), - false, - ); - - macro_rules! try_or_fail { - ( $e:expr ) => { - match $e { - Ok(v) => v, - Err(e) => { - self.fill_trace(&trace, false, None, pre_index); - return Capture::Exit((e.into(), Vec::new())) - } - } - }; - } - - fn l64(gas: u64) -> u64 { - gas - gas / 64 - } - - let after_gas = if take_l64 && self.config().call_l64_after_gas { - if self.config().estimate { - let initial_after_gas = self.state().metadata().gasometer().gas(); - let diff = initial_after_gas - l64(initial_after_gas); - try_or_fail!(self.state_mut().metadata_mut().gasometer_mut().record_cost(diff)); - self.state().metadata().gasometer().gas() - } else { - l64(self.state().metadata().gasometer().gas()) - } - } else { - self.state().metadata().gasometer().gas() - }; - - let target_gas = target_gas.unwrap_or(after_gas); - let mut gas_limit = std::cmp::min(target_gas, after_gas); - - try_or_fail!(self.state_mut().metadata_mut().gasometer_mut().record_cost(gas_limit)); - - if let Some(transfer) = transfer.as_ref() { - if take_stipend && transfer.value != U256::zero() { - gas_limit = gas_limit.saturating_add(self.config().call_stipend); - } - } - - let code = self.code(code_address); - self.handler.enter_substate(gas_limit, is_static); - self.state_mut().touch(context.address); - - if let Some(depth) = self.state().metadata().depth() { - if depth > self.config().call_stack_limit { - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Reverted); - return Capture::Exit((ExitError::CallTooDeep.into(), Vec::new())) - } - } - - if let Some(transfer) = transfer { - match self.state_mut().transfer(transfer) { - Ok(()) => (), - Err(e) => { - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Reverted); - return Capture::Exit((ExitReason::Error(e), Vec::new())) - } - } - } - - if let Some(result) = self.handler.precompiles().execute( - code_address, - &input, - Some(gas_limit), - &context, - is_static, - ) { - return match result { - Ok(PrecompileOutput { exit_status, output, cost, logs }) => { - for Log { address, topics, data } in logs { - match self.log(address, topics, data) { - Ok(_) => continue, - Err(error) => { - self.fill_trace(&trace, false, Some(output.clone()), pre_index); - return Capture::Exit((ExitReason::Error(error), output)) - } - } - } - - let _ = self.state_mut().metadata_mut().gasometer_mut().record_cost(cost); - self.fill_trace(&trace, true, Some(output.clone()), pre_index); - let _ = self.handler.exit_substate(StackExitKind::Succeeded); - Capture::Exit((ExitReason::Succeed(exit_status), output)) - } - Err(e) => { - let e = match e { - PrecompileFailure::Error { exit_status } => ExitReason::Error(exit_status), - PrecompileFailure::Revert { exit_status, .. } => { - ExitReason::Revert(exit_status) - } - PrecompileFailure::Fatal { exit_status } => ExitReason::Fatal(exit_status), - }; - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - Capture::Exit((e, Vec::new())) - } - } - } - - // each cfg is about 200 bytes, is this a lot to clone? why does this error - // not manifest upstream? - let config = self.config().clone(); - let mut runtime; - let reason = if self.state().debug_enabled { - let code = Rc::new(code); - runtime = Runtime::new(code.clone(), Rc::new(input), context, &config); - self.debug_execute(&mut runtime, code_address, code, false) - } else { - runtime = Runtime::new(Rc::new(code), Rc::new(input), context, &config); - self.execute(&mut runtime) - }; - - // // log::debug!(target: "evm", "Call execution using address {}: {:?}", code_address, - // reason); - - match reason { - ExitReason::Succeed(s) => { - self.fill_trace(&trace, true, Some(runtime.machine().return_value()), pre_index); - let _ = self.handler.exit_substate(StackExitKind::Succeeded); - Capture::Exit((ExitReason::Succeed(s), runtime.machine().return_value())) - } - ExitReason::Error(e) => { - self.fill_trace(&trace, false, Some(runtime.machine().return_value()), pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Error(e), Vec::new())) - } - ExitReason::Revert(e) => { - self.fill_trace(&trace, false, Some(runtime.machine().return_value()), pre_index); - let _ = self.handler.exit_substate(StackExitKind::Reverted); - Capture::Exit((ExitReason::Revert(e), runtime.machine().return_value())) - } - ExitReason::Fatal(e) => { - self.fill_trace(&trace, false, Some(runtime.machine().return_value()), pre_index); - self.state_mut().metadata_mut().gasometer_mut().fail(); - let _ = self.handler.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Fatal(e), Vec::new())) - } - } - } - - // NB: This function is copy-pasted from upstream's create_inner - fn create_inner( - &mut self, - caller: H160, - scheme: CreateScheme, - value: U256, - init_code: Vec, - target_gas: Option, - take_l64: bool, - ) -> Capture<(ExitReason, Option, Vec), Infallible> { - let pre_index = self.state().trace_index; - - let address = self.create_address(scheme); - let trace = self.start_trace(address, init_code.clone(), value, true); - - macro_rules! try_or_fail { - ( $e:expr ) => { - match $e { - Ok(v) => v, - Err(e) => { - self.fill_trace(&trace, false, None, pre_index); - return Capture::Exit((e.into(), None, Vec::new())) - } - } - }; - } - - fn check_first_byte(config: &Config, code: &[u8]) -> Result<(), ExitError> { - if config.disallow_executable_format { - if let Some(0xef) = code.get(0) { - return Err(ExitError::InvalidCode) - } - } - Ok(()) - } - - fn l64(gas: u64) -> u64 { - gas - gas / 64 - } - - self.state_mut().metadata_mut().access_address(caller); - self.state_mut().metadata_mut().access_address(address); - - if let Some(depth) = self.state().metadata().depth() { - if depth > self.config().call_stack_limit { - self.fill_trace(&trace, false, None, pre_index); - return Capture::Exit((ExitError::CallTooDeep.into(), None, Vec::new())) - } - } - - if self.balance(caller) < value { - self.fill_trace(&trace, false, None, pre_index); - return Capture::Exit((ExitError::OutOfFund.into(), None, Vec::new())) - } - - let after_gas = if take_l64 && self.config().call_l64_after_gas { - if self.config().estimate { - let initial_after_gas = self.state().metadata().gasometer().gas(); - let diff = initial_after_gas - l64(initial_after_gas); - try_or_fail!(self.state_mut().metadata_mut().gasometer_mut().record_cost(diff)); - self.state().metadata().gasometer().gas() - } else { - l64(self.state().metadata().gasometer().gas()) - } - } else { - self.state().metadata().gasometer().gas() - }; - - let target_gas = target_gas.unwrap_or(after_gas); - - let gas_limit = core::cmp::min(after_gas, target_gas); - try_or_fail!(self.state_mut().metadata_mut().gasometer_mut().record_cost(gas_limit)); - - self.state_mut().inc_nonce(caller); - - self.handler.enter_substate(gas_limit, false); - - { - if self.code_size(address) != U256::zero() { - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new())) - } - - if self.handler.nonce(address) > U256::zero() { - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new())) - } - - self.state_mut().reset_storage(address); - } - - let context = Context { address, caller, apparent_value: value }; - let transfer = Transfer { source: caller, target: address, value }; - match self.state_mut().transfer(transfer) { - Ok(()) => (), - Err(e) => { - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Reverted); - return Capture::Exit((ExitReason::Error(e), None, Vec::new())) - } - } - - if self.config().create_increase_nonce { - self.state_mut().inc_nonce(address); - } - - let config = self.config().clone(); - let mut runtime; - let reason = if self.state().debug_enabled { - let code = Rc::new(init_code); - runtime = Runtime::new(code.clone(), Rc::new(Vec::new()), context, &config); - self.debug_execute(&mut runtime, address, code, true) - } else { - runtime = Runtime::new(Rc::new(init_code), Rc::new(Vec::new()), context, &config); - self.execute(&mut runtime) - }; - // log::debug!(target: "evm", "Create execution using address {}: {:?}", address, reason); - - match reason { - ExitReason::Succeed(s) => { - let out = runtime.machine().return_value(); - - // As of EIP-3541 code starting with 0xef cannot be deployed - if let Err(e) = check_first_byte(self.config(), &out) { - self.state_mut().metadata_mut().gasometer_mut().fail(); - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - return Capture::Exit((e.into(), None, Vec::new())) - } - - if let Some(limit) = self.config().create_contract_limit { - if out.len() > limit { - self.state_mut().metadata_mut().gasometer_mut().fail(); - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - return Capture::Exit(( - ExitError::CreateContractLimit.into(), - None, - Vec::new(), - )) - } - } - - match self.state_mut().metadata_mut().gasometer_mut().record_deposit(out.len()) { - Ok(()) => { - self.fill_trace(&trace, true, Some(out.clone()), pre_index); - let e = self.handler.exit_substate(StackExitKind::Succeeded); - self.state_mut().set_code(address, out); - // this may overwrite the trace and thats okay - try_or_fail!(e); - Capture::Exit((ExitReason::Succeed(s), Some(address), Vec::new())) - } - Err(e) => { - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Error(e), None, Vec::new())) - } - } - } - ExitReason::Error(e) => { - self.state_mut().metadata_mut().gasometer_mut().fail(); - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Error(e), None, Vec::new())) - } - ExitReason::Revert(e) => { - self.fill_trace(&trace, false, Some(runtime.machine().return_value()), pre_index); - let _ = self.handler.exit_substate(StackExitKind::Reverted); - Capture::Exit((ExitReason::Revert(e), None, runtime.machine().return_value())) - } - ExitReason::Fatal(e) => { - self.state_mut().metadata_mut().gasometer_mut().fail(); - self.fill_trace(&trace, false, None, pre_index); - let _ = self.handler.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Fatal(e), None, Vec::new())) - } - } - } -} - -// Delegates everything internally, except the `call_inner` call, which is hooked -// so that we can modify -impl<'a, 'b, B: Backend, P: PrecompileSet> Handler for CheatcodeStackExecutor<'a, 'b, B, P> { - type CreateInterrupt = Infallible; - type CreateFeedback = Infallible; - type CallInterrupt = Infallible; - type CallFeedback = Infallible; - - fn call( - &mut self, - code_address: H160, - transfer: Option, - input: Vec, - target_gas: Option, - is_static: bool, - context: Context, - ) -> Capture<(ExitReason, Vec), Self::CallInterrupt> { - // We intercept calls to the `CHEATCODE_ADDRESS` to apply the cheatcode directly - // to the state. - // NB: This is very similar to how Optimism's custom intercept logic to "predeploys" work - // (e.g. with the StateManager) - if code_address == *CHEATCODE_ADDRESS { - self.apply_cheatcode(input, context.caller) - } else if code_address == *CONSOLE_ADDRESS { - self.console_log(input) - } else { - // record prior origin - let prev_origin = self.state().backend.cheats.origin; - - // modify execution context depending on the cheatcode - let expected_revert = self.state_mut().expected_revert.take(); - let mut new_context = context; - let mut new_transfer = transfer; - let curr_depth = - if let Some(depth) = self.state().metadata().depth() { depth + 1 } else { 0 }; - - // handle `startPrank` - see apply_cheatcodes for more info - if let Some(Prank { prank_caller, new_caller, new_origin, depth }) = self.state().prank - { - // if depth and msg.sender match, perform the prank - if curr_depth == depth && new_context.caller == prank_caller { - new_context.caller = new_caller; - - if let Some(t) = &new_transfer { - new_transfer = - Some(Transfer { source: new_caller, target: t.target, value: t.value }); - } - - // set the origin if the user used the overloaded func - self.state_mut().backend.cheats.origin = new_origin; - } - } - - // handle normal `prank` - if let Some(Prank { new_caller, new_origin, .. }) = self.state_mut().next_prank.take() { - new_context.caller = new_caller; - - if let Some(t) = &new_transfer { - new_transfer = - Some(Transfer { source: new_caller, target: t.target, value: t.value }); - } - - self.state_mut().backend.cheats.origin = new_origin; - } - - // handle expected calls - if let Some(expecteds) = self.state_mut().expected_calls.get_mut(&code_address) { - if let Some(found_match) = expecteds.iter().position(|expected| { - expected.len() <= input.len() && expected == &input[..expected.len()] - }) { - expecteds.remove(found_match); - } - } - - // handle mocked calls - if let Some(mocks) = self.state().mocked_calls.get(&code_address) { - if let Some(mock_retdata) = mocks.get(&input) { - return Capture::Exit(( - ExitReason::Succeed(ExitSucceed::Returned), - mock_retdata.clone(), - )) - } else if let Some((_, mock_retdata)) = - mocks.iter().find(|(mock, _)| *mock == &input[..mock.len()]) - { - return Capture::Exit(( - ExitReason::Succeed(ExitSucceed::Returned), - mock_retdata.clone(), - )) - } - } - - // perform the call - let res = self.call_inner( - code_address, - new_transfer, - input, - target_gas, - is_static, - true, - true, - new_context, - ); - - // if we set the origin, now we should reset to previous - self.state_mut().backend.cheats.origin = prev_origin; - - // handle expected emits - if !self.state_mut().expected_emits.is_empty() && - !self - .state() - .expected_emits - .iter() - .filter(|expected| expected.depth == curr_depth) - .all(|expected| expected.found) - { - return evm_error("Log != expected log") - } else { - // empty out expected_emits after successfully capturing all of them - self.state_mut().expected_emits.retain(|expected| !expected.found); - } - - self.expected_revert(ExpectRevertReturn::Call(res), expected_revert).into_call_inner() - } - } - - // Everything else is left the same - fn balance(&self, address: H160) -> U256 { - self.handler.balance(address) - } - - fn code_size(&self, address: H160) -> U256 { - self.handler.code_size(address) - } - - fn code_hash(&self, address: H160) -> H256 { - self.handler.code_hash(address) - } - - fn code(&self, address: H160) -> Vec { - self.handler.code(address) - } - - fn storage(&self, address: H160, index: H256) -> H256 { - self.handler.storage(address, index) - } - - fn original_storage(&self, address: H160, index: H256) -> H256 { - self.handler.original_storage(address, index) - } - - fn gas_left(&self) -> U256 { - // Need to disambiguate type, because the same method exists in the `SputnikExecutor` - // trait and the `Handler` trait. - Handler::gas_left(&self.handler) - } - - fn gas_price(&self) -> U256 { - self.handler.gas_price() - } - - fn origin(&self) -> H160 { - self.handler.origin() - } - - fn block_hash(&self, number: U256) -> H256 { - self.handler.block_hash(number) - } - - fn block_number(&self) -> U256 { - self.handler.block_number() - } - - fn block_coinbase(&self) -> H160 { - self.handler.block_coinbase() - } - - fn block_timestamp(&self) -> U256 { - self.handler.block_timestamp() - } - - fn block_difficulty(&self) -> U256 { - self.handler.block_difficulty() - } - - fn block_gas_limit(&self) -> U256 { - self.handler.block_gas_limit() - } - - fn block_base_fee_per_gas(&self) -> U256 { - self.handler.block_base_fee_per_gas() - } - - fn chain_id(&self) -> U256 { - self.handler.chain_id() - } - - fn exists(&self, address: H160) -> bool { - self.handler.exists(address) - } - - fn deleted(&self, address: H160) -> bool { - self.handler.deleted(address) - } - - fn is_cold(&self, address: H160, index: Option) -> bool { - self.handler.is_cold(address, index) - } - - fn set_storage(&mut self, address: H160, index: H256, value: H256) -> Result<(), ExitError> { - self.handler.set_storage(address, index, value) - } - - fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError> { - if self.state().trace_enabled { - let index = self.state().trace_index; - let node = &mut self.state_mut().traces.last_mut().expect("no traces").arena[index]; - node.ordering.push(LogCallOrder::Log(node.logs.len())); - node.logs.push(RawLog { topics: topics.clone(), data: data.clone() }); - } - - if let Some(decoded) = - convert_log(Log { address, topics: topics.clone(), data: data.clone() }) - { - self.state_mut().all_logs.push(decoded); - } - - if !self.state().expected_emits.is_empty() { - // get expected emits - let expected_emits = &mut self.state_mut().expected_emits; - - // do we have empty expected emits to fill? - if let Some(next_expect_to_fill) = - expected_emits.iter_mut().find(|expect| expect.log.is_none()) - { - next_expect_to_fill.log = - Some(RawLog { topics: topics.clone(), data: data.clone() }); - } else { - // no unfilled, grab next unfound - // try to fill the first unfound - if let Some(next_expect) = expected_emits.iter_mut().find(|expect| !expect.found) { - // unpack the log - if let Some(RawLog { topics: expected_topics, data: expected_data }) = - &next_expect.log - { - if expected_topics[0] == topics[0] { - // same event topic 0, topic length should be the same - let topics_match = topics - .iter() - .skip(1) - .enumerate() - .filter(|(i, _topic)| { - // do we want to check? - next_expect.checks[*i] - }) - .all(|(i, topic)| topic == &expected_topics[i + 1]); - - // check data - next_expect.found = if next_expect.checks[3] { - expected_data == &data && topics_match - } else { - topics_match - }; - } - } - } - } - } - - self.handler.log(address, topics, data) - } - - fn mark_delete(&mut self, address: H160, target: H160) -> Result<(), ExitError> { - self.handler.mark_delete(address, target) - } - - fn create( - &mut self, - caller: H160, - scheme: CreateScheme, - value: U256, - init_code: Vec, - target_gas: Option, - ) -> Capture<(ExitReason, Option, Vec), Self::CreateInterrupt> { - // modify execution context depending on the cheatcode - - let prev_origin = self.state().backend.cheats.origin; - let expected_revert = self.state_mut().expected_revert.take(); - let mut new_tx_caller = caller; - let mut new_scheme = scheme; - let curr_depth = - if let Some(depth) = self.state().metadata().depth() { depth + 1 } else { 0 }; - - // handle `startPrank` - see apply_cheatcodes for more info - if let Some(Prank { prank_caller, new_caller, new_origin, depth }) = self.state().prank { - if curr_depth == depth && new_tx_caller == prank_caller { - new_tx_caller = new_caller; - - self.state_mut().backend.cheats.origin = new_origin - } - } - - // handle normal `prank` - if let Some(Prank { new_caller, new_origin, .. }) = self.state_mut().next_prank.take() { - new_tx_caller = new_caller; - - self.state_mut().backend.cheats.origin = new_origin - } - - if caller != new_tx_caller { - new_scheme = match scheme { - CreateScheme::Legacy { .. } => CreateScheme::Legacy { caller: new_tx_caller }, - CreateScheme::Create2 { code_hash, salt, .. } => { - CreateScheme::Create2 { caller: new_tx_caller, code_hash, salt } - } - _ => scheme, - }; - } - - let res = self.create_inner(new_tx_caller, new_scheme, value, init_code, target_gas, true); - - // if we set the origin, now we should reset to prior origin - self.state_mut().backend.cheats.origin = prev_origin; - - if !self.state_mut().expected_emits.is_empty() && - !self - .state() - .expected_emits - .iter() - .filter(|expected| expected.depth == curr_depth) - .all(|expected| expected.found) - { - return revert_return_evm(false, None, || "Log != expected log").into_create_inner() - } else { - // empty out expected_emits after successfully capturing all of them - self.state_mut().expected_emits = Vec::new(); - } - - self.expected_revert(ExpectRevertReturn::Create(res), expected_revert).into_create_inner() - } - - fn pre_validate( - &mut self, - context: &Context, - opcode: sputnik::Opcode, - stack: &sputnik::Stack, - ) -> Result<(), ExitError> { - self.handler.pre_validate(context, opcode, stack) - } -} - -#[cfg(test)] -mod tests { - use crate::{ - call_tracing::ExecutionInfo, - fuzz::FuzzedExecutor, - sputnik::helpers::{vm, vm_no_limit, vm_tracing}, - test_helpers::COMPILED, - Evm, - }; - - use super::*; - - #[test] - fn ds_test_logs() { - let mut evm = vm(); - let compiled = COMPILED.find("DebugLogs").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - // after the evm call is done, we call `logs` and print it all to the user - let (_, _, _, logs) = evm - .call::<(), _, _>(Address::zero(), addr, "test_log()", (), 0.into(), compiled.abi) - .unwrap(); - let expected = [ - "Hi", - "0x1234", - "0x1111111111111111111111111111111111111111", - "0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", - "123", - "1234", - "0x4567", - "lol", - "addr: 0x2222222222222222222222222222222222222222", - "key: 0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", - "key: 0.000000000000000123", - "key: -0.000000000000000123", - "key: 1.000000000000000000", - "key: -1.000000000000000000", - "key: -0.000000000123", - "key: -1000000.000000000000", - "key: 0.000000000000001234", - "key: 1.000000000000000000", - "key: 0.000000001234", - "key: 1000000.000000000000", - "key: 123", - "key: 1234", - "key: 0x4567", - "key: lol", - ] - .iter() - .map(ToString::to_string) - .collect::>(); - assert_eq!(logs, expected); - } - - #[test] - fn console_logs() { - let mut evm = vm(); - - let compiled = COMPILED.find("ConsoleLogs").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - // after the evm call is done, we call `logs` and print it all to the user - let (_, _, _, logs) = evm - .call::<(), _, _>(Address::zero(), addr, "test_log()", (), 0.into(), compiled.abi) - .unwrap(); - let expected = [ - "0x1111111111111111111111111111111111111111", - "Hi", - "Hi, Hi", - "1337", - "1337, 1245", - "Hi, 1337", - ] - .iter() - .map(ToString::to_string) - .collect::>(); - assert_eq!(logs, expected); - - let (_, _, _, logs) = evm - .call::<(), _, _>(Address::zero(), addr, "test_log()", (), 0.into(), compiled.abi) - .unwrap(); - assert_eq!(logs, expected); - } - - #[test] - fn console_logs_types() { - let mut evm = vm(); - - let compiled = COMPILED.find("ConsoleLogs").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - // after the evm call is done, we call `logs` and print it all to the user - let (_, _, _, logs) = evm - .call::<(), _, _>(Address::zero(), addr, "test_log_types()", (), 0.into(), compiled.abi) - .unwrap(); - let expected = - ["String", "1337", "-20", "1245", "true", "0x1111111111111111111111111111111111111111"] - .iter() - .map(ToString::to_string) - .collect::>(); - assert_eq!(logs, expected); - } - - #[test] - fn console_logs_types_bytes() { - let mut evm = vm(); - - let compiled = COMPILED.find("ConsoleLogs").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - // after the evm call is done, we call `logs` and print it all to the user - let (_, _, _, logs) = evm - .call::<(), _, _>( - Address::zero(), - addr, - "test_log_types_bytes()", - (), - 0.into(), - compiled.abi, - ) - .unwrap(); - let expected = [ - r#"Bytes(b"logBytes")"#, - r#"Bytes(b"\xfb\xa3\xa4\xb5")"#, - "0xfb", - "0xfba3", - "0xfba3a4", - "0xfba3a4b5", - "0xfba3a4b500", - "0xfba3a4b50000", - "0xfba3a4b5000000", - "0xfba3a4b500000000", - "0xfba3a4b50000000000", - "0xfba3a4b5000000000000", - "0xfba3a4b500000000000000", - "0xfba3a4b50000000000000000", - "0xfba3a4b5000000000000000000", - "0xfba3a4b500000000000000000000", - "0xfba3a4b50000000000000000000000", - "0xfba3a4b5000000000000000000000000", - "0xfba3a4b500000000000000000000000000", - "0xfba3a4b50000000000000000000000000000", - "0xfba3a4b5000000000000000000000000000000", - "0xfba3a4b500000000000000000000000000000000", - "0xfba3a4b50000000000000000000000000000000000", - "0xfba3a4b5000000000000000000000000000000000000", - "0xfba3a4b500000000000000000000000000000000000000", - "0xfba3a4b50000000000000000000000000000000000000000", - "0xfba3a4b5000000000000000000000000000000000000000000", - "0xfba3a4b500000000000000000000000000000000000000000000", - "0xfba3a4b50000000000000000000000000000000000000000000000", - "0xfba3a4b5000000000000000000000000000000000000000000000000", - "0xfba3a4b500000000000000000000000000000000000000000000000000", - "0xfba3a4b50000000000000000000000000000000000000000000000000000", - "0xfba3a4b5000000000000000000000000000000000000000000000000000000", - "0xfba3a4b500000000000000000000000000000000000000000000000000000000", - ] - .iter() - .map(ToString::to_string) - .collect::>(); - assert_eq!(logs, expected); - } - - #[test] - fn logs_external_contract() { - let mut evm = vm(); - - let compiled = COMPILED.find("DebugLogs").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - // after the evm call is done, we call `logs` and print it all to the user - let (_, _, _, logs) = evm - .call::<(), _, _>( - Address::zero(), - addr, - "test_log_elsewhere()", - (), - 0.into(), - compiled.abi, - ) - .unwrap(); - let expected = ["0x1111111111111111111111111111111111111111", "Hi"] - .iter() - .map(ToString::to_string) - .collect::>(); - assert_eq!(logs, expected); - } - - #[test] - fn cheatcodes() { - let mut evm = vm_no_limit(); - let compiled = COMPILED.find("CheatCodes").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - let state = evm.state().clone(); - let mut cfg = proptest::test_runner::Config::default(); - cfg.failure_persistence = None; - let runner = proptest::test_runner::TestRunner::new(cfg); - - // ensure the storage slot is set at 10 anyway - let (storage_contract, _, _, _) = evm - .call::( - Address::zero(), - addr, - "store()(address)", - (), - 0.into(), - compiled.abi, - ) - .unwrap(); - let (slot, _, _, _) = evm - .call::( - Address::zero(), - storage_contract, - "slot0()(uint256)", - (), - 0.into(), - compiled.abi, - ) - .unwrap(); - assert_eq!(slot, 10.into()); - - let evm = FuzzedExecutor::new(&mut evm, runner, Address::zero()); - - let abi = compiled.abi.as_ref().unwrap(); - for func in abi.functions().filter(|func| func.name.starts_with("test")) { - // Skip the FFI unit test if not in a unix system - if func.name == "testFFI" && !cfg!(unix) { - continue - } - - let should_fail = func.name.starts_with("testFail"); - if func.inputs.is_empty() { - let (_, reason, _, _) = - evm.as_mut().call_unchecked(Address::zero(), addr, func, (), 0.into()).unwrap(); - assert!(evm.as_mut().check_success(addr, &reason, should_fail)); - } else { - assert!(evm.fuzz(func, addr, should_fail, Some(abi)).is_ok()); - } - - evm.as_mut().reset(state.clone()); - } - } - - #[test] - fn ffi_fails_if_disabled() { - let mut evm = vm_no_limit(); - evm.executor.enable_ffi = false; - - let compiled = COMPILED.find("CheatCodes").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - let err = evm - .call::<(), _, _>(Address::zero(), addr, "testFFI()", (), 0.into(), compiled.abi) - .unwrap_err(); - let reason = match err { - crate::EvmError::Execution { reason, .. } => reason, - _ => panic!("unexpected error"), - }; - assert_eq!(reason, "ffi disabled: run again with --ffi if you want to allow tests to call external scripts"); - } - - #[test] - fn tracing_call() { - use std::collections::BTreeMap; - let mut evm = vm_tracing(false); - - let compiled = COMPILED.find("Trace").expect("could not find contract"); - let (addr, _, _, _) = evm - .deploy( - Address::zero(), - compiled.bin.unwrap().clone().into_bytes().expect("shouldn't be linked"), - 0.into(), - ) - .unwrap(); - - // after the evm call is done, we call `logs` and print it all to the user - let (_, _, _, _) = evm - .call::<(), _, _>( - Address::zero(), - addr, - "recurseCall(uint256,uint256)", - (U256::from(2u32), U256::from(0u32)), - 0u32.into(), - compiled.abi, - ) - .unwrap(); - - let mut mapping = BTreeMap::new(); - mapping.insert( - "Trace".to_string(), - ( - compiled.abi.expect("No abi").clone(), - compiled - .bin_runtime - .expect("No runtime") - .clone() - .into_bytes() - .expect("Linking?") - .to_vec(), - ), - ); - let compiled = COMPILED.find("RecursiveCall").expect("could not find contract"); - mapping.insert( - "RecursiveCall".to_string(), - ( - compiled.abi.expect("No abi").clone(), - compiled - .bin_runtime - .expect("No runtime") - .clone() - .into_bytes() - .expect("Linking?") - .to_vec(), - ), - ); - let mut identified = Default::default(); - let (funcs, events, errors) = foundry_utils::flatten_known_contracts(&mapping); - let labels = BTreeMap::new(); - let mut exec_info = - ExecutionInfo::new(&mapping, &mut identified, &labels, &funcs, &events, &errors); - let mut trace_string = "".to_string(); - evm.traces()[1].construct_trace_string(0, &mut exec_info, &evm, "", &mut trace_string); - println!("{}", trace_string); - } - - #[test] - fn tracing_create() { - use std::collections::BTreeMap; - - let mut evm = vm_tracing(false); - - let compiled = COMPILED.find("Trace").expect("could not find contract"); - let (addr, _, _, _) = evm - .deploy( - Address::zero(), - compiled.bin.unwrap().clone().into_bytes().expect("shouldn't be linked"), - 0.into(), - ) - .unwrap(); - - // after the evm call is done, we call `logs` and print it all to the user - let (_, _, _, _) = evm - .call::<(), _, _>( - Address::zero(), - addr, - "recurseCreate(uint256,uint256)", - (U256::from(3u32), U256::from(0u32)), - 0u32.into(), - compiled.abi, - ) - .unwrap(); - - let mut mapping = BTreeMap::new(); - mapping.insert( - "Trace".to_string(), - ( - compiled.abi.expect("No abi").clone(), - compiled - .bin_runtime - .expect("No runtime") - .clone() - .into_bytes() - .expect("Linking?") - .to_vec(), - ), - ); - let compiled = COMPILED.find("RecursiveCall").expect("could not find contract"); - mapping.insert( - "RecursiveCall".to_string(), - ( - compiled.abi.expect("No abi").clone(), - compiled - .bin_runtime - .expect("No runtime") - .clone() - .into_bytes() - .expect("Linking?") - .to_vec(), - ), - ); - let mut identified = Default::default(); - let (funcs, events, errors) = foundry_utils::flatten_known_contracts(&mapping); - let labels = BTreeMap::new(); - let mut exec_info = - ExecutionInfo::new(&mapping, &mut identified, &labels, &funcs, &events, &errors); - let mut trace_string = "".to_string(); - evm.traces()[1].construct_trace_string(0, &mut exec_info, &evm, "", &mut trace_string); - println!("{}", trace_string); - } -} diff --git a/evm-adapters/src/sputnik/cheatcodes/debugger.rs b/evm-adapters/src/sputnik/cheatcodes/debugger.rs deleted file mode 100644 index 3bf8e92bfc0d..000000000000 --- a/evm-adapters/src/sputnik/cheatcodes/debugger.rs +++ /dev/null @@ -1,412 +0,0 @@ -use sputnik::{Memory, Opcode}; - -use ethers::types::{Address, H256}; - -use std::{borrow::Cow, fmt::Display}; - -#[derive(Debug, Clone)] -/// An arena of `DebugNode`s -pub struct DebugArena { - /// The arena of nodes - pub arena: Vec, - /// The entry index, denoting the first node's index in the arena - pub entry: usize, -} - -impl Default for DebugArena { - fn default() -> Self { - DebugArena { arena: vec![Default::default()], entry: 0 } - } -} - -impl DebugArena { - /// Pushes a new debug node into the arena - pub fn push_node(&mut self, entry: usize, mut new_node: DebugNode) { - match new_node.depth { - // The entry node, just update it - 0 => { - self.arena[entry] = new_node; - } - // we found the parent node, add the new node as a child - _ if self.arena[entry].depth == new_node.depth - 1 => { - new_node.idx = self.arena.len(); - new_node.location = self.arena[entry].children.len(); - self.arena[entry].children.push(new_node.idx); - self.arena.push(new_node); - } - // we haven't found the parent node, go deeper - _ => self.push_node( - *self.arena[entry].children.last().expect("Disconnected debug node"), - new_node, - ), - } - } - - /// Recursively traverses the tree of debug step nodes and flattens it into a - /// vector where each element contains - /// 1. the address of the contract being executed - /// 2. a vector of all the debug steps along that contract's execution path. - /// - /// This then makes it easy to pretty print the execution steps. - pub fn flatten(&self, entry: usize, flattened: &mut Vec<(Address, Vec, bool)>) { - let node = &self.arena[entry]; - flattened.push((node.address, node.steps.clone(), node.creation)); - node.children.iter().for_each(|child| { - self.flatten(*child, flattened); - }); - } -} - -#[derive(Default, Debug, Clone)] -/// A node in the arena -pub struct DebugNode { - /// Parent node index in the arena - pub parent: Option, - /// Children node indexes in the arena - pub children: Vec, - /// Location in parent - pub location: usize, - /// This node's index in the arena - pub idx: usize, - /// Address context - pub address: Address, - /// Depth - pub depth: usize, - /// The debug steps - pub steps: Vec, - /// Contract Creation - pub creation: bool, -} - -impl DebugNode { - pub fn new(address: Address, depth: usize, steps: Vec) -> Self { - Self { address, depth, steps, ..Default::default() } - } -} - -/// A `DebugStep` is a snapshot of the EVM's runtime state. It holds the current program counter -/// (where in the program you are), the stack and memory (prior to the opcodes execution), any bytes -/// to be pushed onto the stack, and the instruction counter for use with sourcemaps -#[derive(Debug, Clone)] -pub struct DebugStep { - /// Program Counter - pub pc: usize, - /// Stack *prior* to running this struct's associated opcode - pub stack: Vec, - /// Memory *prior* to running this struct's associated opcode - pub memory: Memory, - /// Opcode to be executed - pub op: OpCode, - /// Optional bytes that are being pushed onto the stack - pub push_bytes: Option>, - /// Instruction counter, used for sourcemap mapping to source code - pub ic: usize, - /// Cumulative gas usage - pub total_gas_used: u64, -} - -impl Default for DebugStep { - fn default() -> Self { - Self { - pc: 0, - stack: vec![], - memory: Memory::new(0), - op: OpCode(Opcode::INVALID, None), - push_bytes: None, - ic: 0, - total_gas_used: 0, - } - } -} - -impl DebugStep { - /// Pretty print the step's opcode - pub fn pretty_opcode(&self) -> String { - if let Some(push_bytes) = &self.push_bytes { - format!("{}(0x{})", self.op, hex::encode(push_bytes)) - } else { - self.op.to_string() - } - } -} - -impl Display for DebugStep { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(push_bytes) = &self.push_bytes { - write!( - f, - "pc: {:?}\nop: {}(0x{})\nstack: {:#?}\nmemory: 0x{}\n\n", - self.pc, - self.op, - hex::encode(push_bytes), - self.stack, - hex::encode(self.memory.data()) - ) - } else { - write!( - f, - "pc: {:?}\nop: {}\nstack: {:#?}\nmemory: 0x{}\n\n", - self.pc, - self.op, - self.stack, - hex::encode(self.memory.data()) - ) - } - } -} - -/// CheatOps are `forge` specific identifiers for cheatcodes since cheatcodes don't touch the evm -#[derive(Debug, Copy, Clone)] -pub enum CheatOp { - ROLL, - WARP, - FEE, - STORE, - LOAD, - FFI, - ADDR, - SIGN, - PRANK, - STARTPRANK, - STOPPRANK, - DEAL, - ETCH, - EXPECTREVERT, - RECORD, - ACCESSES, - EXPECTEMIT, - MOCKCALL, - CLEARMOCKEDCALLS, - EXPECTCALL, - GETCODE, - LABEL, - ASSUME, -} - -impl From for OpCode { - fn from(cheat: CheatOp) -> OpCode { - OpCode(Opcode(0x0C), Some(cheat)) - } -} - -impl CheatOp { - /// Gets the `CheatOp` as a string for printing purposes - pub const fn name(&self) -> &'static str { - match self { - CheatOp::ROLL => "VM_ROLL", - CheatOp::WARP => "VM_WARP", - CheatOp::FEE => "VM_FEE", - CheatOp::STORE => "VM_STORE", - CheatOp::LOAD => "VM_LOAD", - CheatOp::FFI => "VM_FFI", - CheatOp::ADDR => "VM_ADDR", - CheatOp::SIGN => "VM_SIGN", - CheatOp::PRANK => "VM_PRANK", - CheatOp::STARTPRANK => "VM_STARTPRANK", - CheatOp::STOPPRANK => "VM_STOPPRANK", - CheatOp::DEAL => "VM_DEAL", - CheatOp::ETCH => "VM_ETCH", - CheatOp::EXPECTREVERT => "VM_EXPECTREVERT", - CheatOp::RECORD => "VM_RECORD", - CheatOp::ACCESSES => "VM_ACCESSES", - CheatOp::EXPECTEMIT => "VM_EXPECTEMIT", - CheatOp::MOCKCALL => "VM_MOCKCALL", - CheatOp::CLEARMOCKEDCALLS => "VM_CLEARMOCKEDCALLS", - CheatOp::EXPECTCALL => "VM_EXPECTCALL", - CheatOp::GETCODE => "VM_GETCODE", - CheatOp::LABEL => "VM_LABEL", - CheatOp::ASSUME => "VM_ASSUME", - } - } -} - -impl Default for CheatOp { - fn default() -> Self { - CheatOp::ROLL - } -} - -#[derive(Debug, Clone, Copy)] -pub struct OpCode(pub Opcode, pub Option); - -impl From for OpCode { - fn from(op: Opcode) -> OpCode { - OpCode(op, None) - } -} - -impl OpCode { - /// Gets the name of the opcode as a string - pub const fn name(&self) -> &'static str { - match self.0 { - Opcode::STOP => "STOP", - Opcode::ADD => "ADD", - Opcode::MUL => "MUL", - Opcode::SUB => "SUB", - Opcode::DIV => "DIV", - Opcode::SDIV => "SDIV", - Opcode::MOD => "MOD", - Opcode::SMOD => "SMOD", - Opcode::ADDMOD => "ADDMOD", - Opcode::MULMOD => "MULMOD", - Opcode::EXP => "EXP", - Opcode::SIGNEXTEND => "SIGNEXTEND", - Opcode::LT => "LT", - Opcode::GT => "GT", - Opcode::SLT => "SLT", - Opcode::SGT => "SGT", - Opcode::EQ => "EQ", - Opcode::ISZERO => "ISZERO", - Opcode::AND => "AND", - Opcode::OR => "OR", - Opcode::XOR => "XOR", - Opcode::NOT => "NOT", - Opcode::BYTE => "BYTE", - Opcode::SHL => "SHL", - Opcode::SHR => "SHR", - Opcode::SAR => "SAR", - Opcode::SHA3 => "KECCAK256", - Opcode::ADDRESS => "ADDRESS", - Opcode::BALANCE => "BALANCE", - Opcode::ORIGIN => "ORIGIN", - Opcode::CALLER => "CALLER", - Opcode::CALLVALUE => "CALLVALUE", - Opcode::CALLDATALOAD => "CALLDATALOAD", - Opcode::CALLDATASIZE => "CALLDATASIZE", - Opcode::CALLDATACOPY => "CALLDATACOPY", - Opcode::CODESIZE => "CODESIZE", - Opcode::CODECOPY => "CODECOPY", - Opcode::GASPRICE => "GASPRICE", - Opcode::EXTCODESIZE => "EXTCODESIZE", - Opcode::EXTCODECOPY => "EXTCODECOPY", - Opcode::RETURNDATASIZE => "RETURNDATASIZE", - Opcode::RETURNDATACOPY => "RETURNDATACOPY", - Opcode::EXTCODEHASH => "EXTCODEHASH", - Opcode::BLOCKHASH => "BLOCKHASH", - Opcode::COINBASE => "COINBASE", - Opcode::TIMESTAMP => "TIMESTAMP", - Opcode::NUMBER => "NUMBER", - Opcode::DIFFICULTY => "DIFFICULTY", - Opcode::GASLIMIT => "GASLIMIT", - Opcode::CHAINID => "CHAINID", - Opcode::SELFBALANCE => "SELFBALANCE", - Opcode::BASEFEE => "BASEFEE", - Opcode::POP => "POP", - Opcode::MLOAD => "MLOAD", - Opcode::MSTORE => "MSTORE", - Opcode::MSTORE8 => "MSTORE8", - Opcode::SLOAD => "SLOAD", - Opcode::SSTORE => "SSTORE", - Opcode::JUMP => "JUMP", - Opcode::JUMPI => "JUMPI", - Opcode::PC => "PC", - Opcode::MSIZE => "MSIZE", - Opcode::GAS => "GAS", - Opcode::JUMPDEST => "JUMPDEST", - Opcode::PUSH1 => "PUSH1", - Opcode::PUSH2 => "PUSH2", - Opcode::PUSH3 => "PUSH3", - Opcode::PUSH4 => "PUSH4", - Opcode::PUSH5 => "PUSH5", - Opcode::PUSH6 => "PUSH6", - Opcode::PUSH7 => "PUSH7", - Opcode::PUSH8 => "PUSH8", - Opcode::PUSH9 => "PUSH9", - Opcode::PUSH10 => "PUSH10", - Opcode::PUSH11 => "PUSH11", - Opcode::PUSH12 => "PUSH12", - Opcode::PUSH13 => "PUSH13", - Opcode::PUSH14 => "PUSH14", - Opcode::PUSH15 => "PUSH15", - Opcode::PUSH16 => "PUSH16", - Opcode::PUSH17 => "PUSH17", - Opcode::PUSH18 => "PUSH18", - Opcode::PUSH19 => "PUSH19", - Opcode::PUSH20 => "PUSH20", - Opcode::PUSH21 => "PUSH21", - Opcode::PUSH22 => "PUSH22", - Opcode::PUSH23 => "PUSH23", - Opcode::PUSH24 => "PUSH24", - Opcode::PUSH25 => "PUSH25", - Opcode::PUSH26 => "PUSH26", - Opcode::PUSH27 => "PUSH27", - Opcode::PUSH28 => "PUSH28", - Opcode::PUSH29 => "PUSH29", - Opcode::PUSH30 => "PUSH30", - Opcode::PUSH31 => "PUSH31", - Opcode::PUSH32 => "PUSH32", - Opcode::DUP1 => "DUP1", - Opcode::DUP2 => "DUP2", - Opcode::DUP3 => "DUP3", - Opcode::DUP4 => "DUP4", - Opcode::DUP5 => "DUP5", - Opcode::DUP6 => "DUP6", - Opcode::DUP7 => "DUP7", - Opcode::DUP8 => "DUP8", - Opcode::DUP9 => "DUP9", - Opcode::DUP10 => "DUP10", - Opcode::DUP11 => "DUP11", - Opcode::DUP12 => "DUP12", - Opcode::DUP13 => "DUP13", - Opcode::DUP14 => "DUP14", - Opcode::DUP15 => "DUP15", - Opcode::DUP16 => "DUP16", - Opcode::SWAP1 => "SWAP1", - Opcode::SWAP2 => "SWAP2", - Opcode::SWAP3 => "SWAP3", - Opcode::SWAP4 => "SWAP4", - Opcode::SWAP5 => "SWAP5", - Opcode::SWAP6 => "SWAP6", - Opcode::SWAP7 => "SWAP7", - Opcode::SWAP8 => "SWAP8", - Opcode::SWAP9 => "SWAP9", - Opcode::SWAP10 => "SWAP10", - Opcode::SWAP11 => "SWAP11", - Opcode::SWAP12 => "SWAP12", - Opcode::SWAP13 => "SWAP13", - Opcode::SWAP14 => "SWAP14", - Opcode::SWAP15 => "SWAP15", - Opcode::SWAP16 => "SWAP16", - Opcode::LOG0 => "LOG0", - Opcode::LOG1 => "LOG1", - Opcode::LOG2 => "LOG2", - Opcode::LOG3 => "LOG3", - Opcode::LOG4 => "LOG4", - Opcode::CREATE => "CREATE", - Opcode::CALL => "CALL", - Opcode::CALLCODE => "CALLCODE", - Opcode::RETURN => "RETURN", - Opcode::DELEGATECALL => "DELEGATECALL", - Opcode::CREATE2 => "CREATE2", - Opcode::STATICCALL => "STATICCALL", - Opcode::REVERT => "REVERT", - Opcode::INVALID => "INVALID", - Opcode::SUICIDE => "SELFDESTRUCT", - _ => { - if let Some(cheat) = self.1 { - cheat.name() - } else { - "UNDEFINED" - } - } - } - } - - /// Optionally return the push size of the opcode if it is a push - pub fn push_size(self) -> Option { - self.0.is_push() - } -} - -impl Display for OpCode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let name = self.name(); - - let n = if name == "UNDEFINED" { - Cow::Owned(format!("UNDEFINED(0x{:02x})", self.0 .0)) - } else { - Cow::Borrowed(name) - }; - write!(f, "{}", n) - } -} diff --git a/evm-adapters/src/sputnik/cheatcodes/memory_stackstate_owned.rs b/evm-adapters/src/sputnik/cheatcodes/memory_stackstate_owned.rs deleted file mode 100644 index 31db29635900..000000000000 --- a/evm-adapters/src/sputnik/cheatcodes/memory_stackstate_owned.rs +++ /dev/null @@ -1,300 +0,0 @@ -use sputnik::{ - backend::{Backend, Basic}, - executor::stack::{MemoryStackSubstate, StackState, StackSubstateMetadata}, - ExitError, Transfer, -}; - -use crate::{call_tracing::CallTraceArena, sputnik::cheatcodes::debugger::DebugArena}; - -use ethers::{ - abi::RawLog, - types::{H160, H256, U256}, -}; - -use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; - -#[derive(Clone, Default)] -pub struct RecordAccess { - pub reads: RefCell>>, - pub writes: RefCell>>, -} - -#[derive(Clone, Default, Debug)] -pub struct ExpectedEmit { - pub depth: usize, - pub log: Option, - pub checks: [bool; 4], - /// Whether this expected emit was actually found in the subcall - pub found: bool, -} - -#[derive(Clone, Default, Debug)] -pub struct Prank { - /// Address of the contract that called prank - pub prank_caller: H160, - /// Address to set msg.sender to - pub new_caller: H160, - /// New origin to use - pub new_origin: Option, - /// Call depth at which the prank was called - pub depth: usize, -} - -/// This struct implementation is copied from [upstream](https://github.com/rust-blockchain/evm/blob/5ecf36ce393380a89c6f1b09ef79f686fe043624/src/executor/stack/state.rs#L412) and modified to own the Backend type. -/// -/// We had to copy it so that we can modify the Stack's internal backend, because -/// the upstream MemoryStackState only has an immutable reference to `Backend` which -/// does not allow us to do so. -#[derive(Clone)] -pub struct MemoryStackStateOwned<'config, B> { - pub backend: B, - pub substate: MemoryStackSubstate<'config>, - /// Tracing enabled - pub trace_enabled: bool, - /// Current call index used for incrementing traces index vec below - pub call_index: usize, - /// Temporary value used for putting logs in the correct trace - pub trace_index: usize, - /// Arena allocator that holds a tree of traces - pub traces: Vec, - /// Expected revert storage of bytes - pub expected_revert: Option>, - /// Next call's prank - pub next_prank: Option, - /// StartPrank information - pub prank: Option, - /// List of accesses done during a call - pub accesses: Option, - /// All logs accumulated (regardless of revert status) - pub all_logs: Vec, - /// Expected events by end of the next call - pub expected_emits: Vec, - pub mocked_calls: BTreeMap, Vec>>, - pub expected_calls: BTreeMap>>, - /// Debug enabled - pub debug_enabled: bool, - /// An arena allocator of DebugNodes for debugging purposes - pub debug_steps: Vec, - /// Instruction pointers that maps an address to a mapping of pc to ic - pub debug_instruction_pointers: Dip, - /// Labels for an address in call traces - pub labels: BTreeMap, -} - -impl<'config, B: Backend> MemoryStackStateOwned<'config, B> { - pub fn deposit(&mut self, address: H160, value: U256) { - self.substate.deposit(address, value, &self.backend); - } - - pub fn increment_call_index(&mut self) { - self.traces.push(Default::default()); - self.debug_steps.push(Default::default()); - self.call_index += 1; - } - pub fn trace_mut(&mut self) -> &mut CallTraceArena { - &mut self.traces[self.call_index] - } - - pub fn debug_mut(&mut self) -> &mut DebugArena { - &mut self.debug_steps[self.call_index] - } - - pub fn trace(&self) -> &CallTraceArena { - &self.traces[self.call_index] - } - - pub fn reset_traces(&mut self) { - self.traces = vec![Default::default()]; - self.call_index = 0; - } -} - -/// Debug Instruction pointers: a tuple with 2 maps, the first being for creation -/// sourcemaps, the second for runtime sourcemaps. -/// -/// Each has a structure of (Address => (program_counter => instruction_counter)) -/// For sourcemap usage, we need to convert a program counter to an instruction counter and use the -/// instruction counter as the index into the sourcemap vector. An instruction counter (pointer) is -/// just the program counter minus the sum of push bytes (i.e. PUSH1(0x01), would apply a -1 effect -/// to all subsequent instruction counters) -pub type Dip = - (BTreeMap>>, BTreeMap>>); - -impl<'config, B: Backend> MemoryStackStateOwned<'config, B> { - pub fn new( - metadata: StackSubstateMetadata<'config>, - backend: B, - trace_enabled: bool, - debug_enabled: bool, - ) -> Self { - Self { - backend, - substate: MemoryStackSubstate::new(metadata), - trace_enabled, - call_index: 0, - trace_index: 1, - traces: vec![Default::default()], - expected_revert: None, - next_prank: None, - prank: None, - accesses: None, - all_logs: Default::default(), - expected_emits: Default::default(), - mocked_calls: Default::default(), - expected_calls: Default::default(), - debug_enabled, - debug_steps: vec![Default::default()], - debug_instruction_pointers: (BTreeMap::new(), BTreeMap::new()), - labels: BTreeMap::new(), - } - } -} - -impl<'config, B: Backend> Backend for MemoryStackStateOwned<'config, B> { - fn gas_price(&self) -> U256 { - self.backend.gas_price() - } - fn origin(&self) -> H160 { - self.backend.origin() - } - fn block_hash(&self, number: U256) -> H256 { - self.backend.block_hash(number) - } - fn block_number(&self) -> U256 { - self.backend.block_number() - } - fn block_coinbase(&self) -> H160 { - self.backend.block_coinbase() - } - fn block_timestamp(&self) -> U256 { - self.backend.block_timestamp() - } - fn block_difficulty(&self) -> U256 { - self.backend.block_difficulty() - } - fn block_gas_limit(&self) -> U256 { - self.backend.block_gas_limit() - } - fn block_base_fee_per_gas(&self) -> U256 { - self.backend.block_base_fee_per_gas() - } - fn chain_id(&self) -> U256 { - self.backend.chain_id() - } - - fn exists(&self, address: H160) -> bool { - self.substate.known_account(address).is_some() || self.backend.exists(address) - } - - fn basic(&self, address: H160) -> Basic { - self.substate.known_basic(address).unwrap_or_else(|| self.backend.basic(address)) - } - - fn code(&self, address: H160) -> Vec { - self.substate.known_code(address).unwrap_or_else(|| self.backend.code(address)) - } - - fn storage(&self, address: H160, key: H256) -> H256 { - if let Some(record_accesses) = &self.accesses { - record_accesses.reads.borrow_mut().entry(address).or_insert_with(Vec::new).push(key); - } - self.substate - .known_storage(address, key) - .unwrap_or_else(|| self.backend.storage(address, key)) - } - - fn original_storage(&self, address: H160, key: H256) -> Option { - if let Some(value) = self.substate.known_original_storage(address, key) { - return Some(value) - } - - self.backend.original_storage(address, key) - } -} - -impl<'config, B: Backend> StackState<'config> for MemoryStackStateOwned<'config, B> { - fn metadata(&self) -> &StackSubstateMetadata<'config> { - self.substate.metadata() - } - - fn metadata_mut(&mut self) -> &mut StackSubstateMetadata<'config> { - self.substate.metadata_mut() - } - - fn enter(&mut self, gas_limit: u64, is_static: bool) { - self.substate.enter(gas_limit, is_static) - } - - fn exit_commit(&mut self) -> Result<(), ExitError> { - self.substate.exit_commit() - } - - fn exit_revert(&mut self) -> Result<(), ExitError> { - self.substate.exit_revert() - } - - fn exit_discard(&mut self) -> Result<(), ExitError> { - self.substate.exit_discard() - } - - fn is_empty(&self, address: H160) -> bool { - if let Some(known_empty) = self.substate.known_empty(address) { - return known_empty - } - - self.backend.basic(address).balance == U256::zero() && - self.backend.basic(address).nonce == U256::zero() && - self.backend.code(address).len() == 0 - } - - fn deleted(&self, address: H160) -> bool { - self.substate.deleted(address) - } - - fn is_cold(&self, address: H160) -> bool { - self.substate.is_cold(address) - } - - fn is_storage_cold(&self, address: H160, key: H256) -> bool { - self.substate.is_storage_cold(address, key) - } - - fn inc_nonce(&mut self, address: H160) { - self.substate.inc_nonce(address, &self.backend); - } - - fn set_storage(&mut self, address: H160, key: H256, value: H256) { - if let Some(record_accesses) = &self.accesses { - record_accesses.writes.borrow_mut().entry(address).or_insert_with(Vec::new).push(key); - } - self.substate.set_storage(address, key, value) - } - - fn reset_storage(&mut self, address: H160) { - self.substate.reset_storage(address, &self.backend); - } - - fn log(&mut self, address: H160, topics: Vec, data: Vec) { - self.substate.log(address, topics, data); - } - - fn set_deleted(&mut self, address: H160) { - self.substate.set_deleted(address) - } - - fn set_code(&mut self, address: H160, code: Vec) { - self.substate.set_code(address, code, &self.backend) - } - - fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError> { - self.substate.transfer(transfer, &self.backend) - } - - fn reset_balance(&mut self, address: H160) { - self.substate.reset_balance(address, &self.backend) - } - - fn touch(&mut self, address: H160) { - self.substate.touch(address, &self.backend) - } -} diff --git a/evm-adapters/src/sputnik/evm.rs b/evm-adapters/src/sputnik/evm.rs deleted file mode 100644 index 36e37871d8fd..000000000000 --- a/evm-adapters/src/sputnik/evm.rs +++ /dev/null @@ -1,470 +0,0 @@ -use crate::{call_tracing::CallTraceArena, Evm, FAUCET_ACCOUNT}; -use ethers::types::{Address, Bytes, U256}; - -use crate::sputnik::cheatcodes::debugger::DebugArena; - -use sputnik::{ - backend::{Backend, MemoryAccount}, - executor::stack::{ - MemoryStackState, PrecompileSet, StackExecutor, StackState, StackSubstateMetadata, - }, - Config, CreateScheme, ExitReason, ExitRevert, Transfer, -}; -use std::{collections::BTreeMap, marker::PhantomData}; - -use eyre::Result; - -use super::SputnikExecutor; - -pub type MemoryState = BTreeMap; - -// TODO: Check if we can implement this as the base layer of an ethers-provider -// Middleware stack instead of doing RPC calls. -/// Wrapper around Sputnik Executors which implements the [`Evm`] trait. -pub struct Executor { - pub executor: E, - pub gas_limit: u64, - marker: PhantomData, -} - -impl Executor { - /// Instantiates the executor given a Sputnik instance. - pub fn from_executor(executor: E, gas_limit: u64) -> Self { - Self { executor, gas_limit, marker: PhantomData } - } -} - -// Concrete implementation over the in-memory backend without cheatcodes -impl<'a, 'b, B: Backend, P: PrecompileSet> - Executor, StackExecutor<'a, 'b, MemoryStackState<'a, 'a, B>, P>> -{ - /// Given a gas limit, vm version, initial chain configuration and initial state - // TODO: See if we can make lifetimes better here - pub fn new(gas_limit: u64, config: &'a Config, backend: &'a B, precompiles: &'b P) -> Self { - // setup gasometer - let metadata = StackSubstateMetadata::new(gas_limit, config); - // setup state - let state = MemoryStackState::new(metadata, backend); - // setup executor - let executor = StackExecutor::new_with_precompiles(state, config, precompiles); - - Self { executor, gas_limit, marker: PhantomData } - } -} - -// Note regarding usage of Generic vs Associated Types in traits: -// -// We use StackState as a trait and not as an associated type because we want to -// allow the developer what the db type should be. Whereas for ReturnReason, we want it -// to be generic across implementations, but we don't want to make it a user-controlled generic. -impl<'a, S, E> Evm for Executor -where - E: SputnikExecutor, - S: StackState<'a>, -{ - type ReturnReason = ExitReason; - - fn revert() -> Self::ReturnReason { - ExitReason::Revert(ExitRevert::Reverted) - } - - fn expected_revert(&self) -> Option<&[u8]> { - self.executor.expected_revert() - } - - fn is_success(reason: &Self::ReturnReason) -> bool { - matches!(reason, ExitReason::Succeed(_)) - } - - fn is_fail(reason: &Self::ReturnReason) -> bool { - !Self::is_success(reason) - } - - fn reset(&mut self, state: S) { - let mut _state = self.executor.state_mut(); - *_state = state; - } - - fn set_tracing_enabled(&mut self, enabled: bool) -> bool { - self.executor.set_tracing_enabled(enabled) - } - - fn tracing_enabled(&self) -> bool { - self.executor.tracing_enabled() - } - - /// Grabs debug steps - #[cfg(feature = "sputnik")] - fn debug_calls(&self) -> Vec { - self.executor.debug_calls() - } - - /// given an iterator of contract address to contract bytecode, initializes - /// the state with the contract deployed at the specified address - fn initialize_contracts>(&mut self, contracts: T) { - let state_ = self.executor.state_mut(); - contracts.into_iter().for_each(|(address, bytecode)| { - state_.set_code(address, bytecode.to_vec()); - }) - } - - fn set_balance(&mut self, address: Address, balance: U256) { - self.executor - .state_mut() - .transfer(Transfer { source: *FAUCET_ACCOUNT, target: address, value: balance }) - .expect("could not transfer funds") - } - - fn state(&self) -> &S { - self.executor.state() - } - - fn code(&self, address: Address) -> Vec { - self.executor.state().code(address) - } - - fn traces(&self) -> Vec { - self.executor.traces() - } - - fn reset_traces(&mut self) { - self.executor.reset_traces() - } - - fn all_logs(&self) -> Vec { - self.executor.all_logs() - } - - /// Deploys the provided contract bytecode - fn deploy( - &mut self, - from: Address, - calldata: Bytes, - value: U256, - ) -> Result<(Address, ExitReason, u64, Vec)> { - let gas_used_before = self.executor.gas_used(); - let refunded_gas_before = self.executor.gas_refund(); - - // The account's created contract address is pre-computed by using the account's nonce - // before it executes the contract deployment transaction. - let address = self.executor.create_address(CreateScheme::Legacy { caller: from }); - let status = - self.executor.transact_create(from, value, calldata.to_vec(), self.gas_limit, vec![]); - - // get the deployment logs - let logs = self.executor.logs(); - // and clear them - self.executor.clear_logs(); - - let refunded_gas = self.executor.gas_refund().saturating_sub(refunded_gas_before); - let gas_used_after = self.executor.gas_used(); - // we dont remove call data costs here because its highly relevant to users - let gas = gas_used_after - .saturating_sub(gas_used_before) - .saturating_sub(refunded_gas) - .saturating_sub(21000.into()); - - if Self::is_fail(&status) { - tracing::trace!(?status, "failed"); - Err(eyre::eyre!("deployment reverted, reason: {:?}", status)) - } else { - tracing::trace!(?status, ?address, ?gas, "success"); - Ok((address, status, gas.as_u64(), logs)) - } - } - - /// Runs the selected function - fn call_raw( - &mut self, - from: Address, - to: Address, - calldata: Bytes, - value: U256, - _is_static: bool, - ) -> Result<(Bytes, ExitReason, u64, Vec)> { - let gas_used_before = self.executor.gas_used(); - let refunded_gas_before = self.executor.gas_refund(); - - let (status, retdata) = - self.executor.transact_call(from, to, value, calldata.to_vec(), self.gas_limit, vec![]); - - tracing::trace!(logs_before = ?self.executor.logs()); - - let refunded_gas = self.executor.gas_refund().saturating_sub(refunded_gas_before); - let gas_used_after = self.executor.gas_used(); - // remove base and calldata costs - let gas = foundry_utils::remove_extra_costs( - gas_used_after.saturating_sub(gas_used_before).saturating_sub(refunded_gas), - calldata.as_ref(), - ); - - // get the logs - let logs = self.executor.logs(); - tracing::trace!(logs_after = ?self.executor.logs()); - // clear them - self.executor.clear_logs(); - - Ok((retdata.into(), status, gas.as_u64(), logs)) - } -} - -#[cfg(any(test, feature = "sputnik-helpers"))] -pub mod helpers { - use super::*; - use ethers::types::H160; - use sputnik::backend::{MemoryBackend, MemoryVicinity}; - - use crate::{ - fuzz::FuzzedExecutor, - sputnik::{ - cheatcodes::cheatcode_handler::{CheatcodeStackExecutor, CheatcodeStackState}, - PrecompileFn, PRECOMPILES_MAP, - }, - }; - use once_cell::sync::Lazy; - - pub type TestSputnikVM<'a, B> = Executor< - // state - CheatcodeStackState<'a, B>, - // actual stack executor - CheatcodeStackExecutor<'a, 'a, B, BTreeMap>, - >; - - pub static CFG: Lazy = Lazy::new(Config::london); - - /// London config without a contract size limit. Useful for testing but is a depature from - /// mainnet rules. - pub static CFG_NO_LMT: Lazy = Lazy::new(|| { - let mut cfg = Config::london(); - cfg.create_contract_limit = None; - cfg - }); - - pub static VICINITY: Lazy = Lazy::new(new_vicinity); - pub const GAS_LIMIT: u64 = 30_000_000; - - /// Instantiates a Sputnik EVM with enabled cheatcodes + FFI and a simple non-forking in memory - /// backend and tracing disabled - pub fn vm<'a>() -> TestSputnikVM<'a, MemoryBackend<'a>> { - let backend = new_backend(&*VICINITY, Default::default()); - Executor::new_with_cheatcodes( - backend, - GAS_LIMIT, - &*CFG, - &*PRECOMPILES_MAP, - true, - false, - false, - ) - } - - /// Instantiates a Sputnik EVM with enabled cheatcodes + FFI and a simple non-forking in memory - /// backend and tracing disabled, and no contract size limit - pub fn vm_no_limit<'a>() -> TestSputnikVM<'a, MemoryBackend<'a>> { - let backend = new_backend(&*VICINITY, Default::default()); - Executor::new_with_cheatcodes( - backend, - GAS_LIMIT, - &*CFG_NO_LMT, - &*PRECOMPILES_MAP, - true, - false, - false, - ) - } - - /// Instantiates a Sputnik EVM with enabled cheatcodes + FFI and a simple non-forking in memory - /// backend and tracing enabled - pub fn vm_tracing<'a>(with_contract_limit: bool) -> TestSputnikVM<'a, MemoryBackend<'a>> { - let backend = new_backend(&*VICINITY, Default::default()); - if with_contract_limit { - Executor::new_with_cheatcodes( - backend, - GAS_LIMIT, - &*CFG, - &*PRECOMPILES_MAP, - true, - true, - false, - ) - } else { - Executor::new_with_cheatcodes( - backend, - GAS_LIMIT, - &*CFG_NO_LMT, - &*PRECOMPILES_MAP, - true, - true, - false, - ) - } - } - - /// Instantiates a Sputnik EVM with enabled cheatcodes + FFI and a simple non-forking in memory - /// backend and debug enabled, and tracing disabled - pub fn vm_debug<'a>(with_contract_limit: bool) -> TestSputnikVM<'a, MemoryBackend<'a>> { - let backend = new_backend(&*VICINITY, Default::default()); - if with_contract_limit { - Executor::new_with_cheatcodes( - backend, - GAS_LIMIT, - &*CFG, - &*PRECOMPILES_MAP, - true, - false, - true, - ) - } else { - Executor::new_with_cheatcodes( - backend, - GAS_LIMIT, - &*CFG_NO_LMT, - &*PRECOMPILES_MAP, - true, - false, - true, - ) - } - } - - /// Instantiates a FuzzedExecutor over provided Sputnik EVM - pub fn fuzzvm<'a, B: Backend>( - evm: &'a mut TestSputnikVM<'a, B>, - ) -> FuzzedExecutor<'a, TestSputnikVM<'a, B>, CheatcodeStackState<'a, B>> { - let cfg = proptest::test_runner::Config { failure_persistence: None, ..Default::default() }; - - let runner = proptest::test_runner::TestRunner::new(cfg); - FuzzedExecutor::new(evm, runner, Address::zero()) - } - - pub fn new_backend(vicinity: &MemoryVicinity, state: MemoryState) -> MemoryBackend<'_> { - MemoryBackend::new(vicinity, state) - } - - pub fn new_vicinity() -> MemoryVicinity { - MemoryVicinity { - gas_price: U256::zero(), - origin: H160::default(), - block_hashes: Vec::new(), - block_number: Default::default(), - block_coinbase: Default::default(), - block_timestamp: Default::default(), - block_difficulty: Default::default(), - block_gas_limit: Default::default(), - block_base_fee_per_gas: Default::default(), - chain_id: U256::one(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - sputnik::helpers::vm, - test_helpers::{can_call_vm_directly, solidity_unit_test, COMPILED}, - }; - use ethers::utils::id; - use sputnik::{ExitReason, ExitRevert, ExitSucceed}; - - // can bubble up sputnik errors - #[test] - fn test_oog() { - let mut evm = vm(); - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - evm.gas_limit = 0; - let err = evm - .call::<(), _, _>(Address::zero(), addr, "testGreeting()", (), 0.into(), None) - .unwrap_err(); - let (reason, _) = match err { - crate::EvmError::Execution { reason, gas_used, .. } => (reason, gas_used), - _ => panic!("unexpected error variant"), - }; - assert_eq!(reason, "Error(OutOfGas)"); - } - - #[test] - fn sputnik_can_call_vm_directly() { - let evm = vm(); - let compiled = COMPILED.find("Greeter").expect("could not find contract"); - can_call_vm_directly(evm, compiled); - } - - #[test] - fn sputnik_solidity_unit_test() { - let evm = vm(); - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - solidity_unit_test(evm, compiled); - } - - #[test] - fn failing_with_no_reason_if_no_setup() { - let mut evm = vm(); - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - let (status, res) = evm.executor.transact_call( - Address::zero(), - addr, - 0.into(), - id("testFailGreeting()").to_vec(), - evm.gas_limit, - vec![], - ); - assert_eq!(status, ExitReason::Revert(ExitRevert::Reverted)); - assert!(res.is_empty()); - } - - #[test] - fn failing_solidity_unit_test() { - let mut evm = vm(); - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - // call the setup function to deploy the contracts inside the test - let status = evm.setup(addr).unwrap().0; - assert_eq!(status, ExitReason::Succeed(ExitSucceed::Stopped)); - - let err = evm - .call::<(), _, _>( - Address::zero(), - addr, - "testFailGreeting()", - (), - 0.into(), - compiled.abi, - ) - .unwrap_err(); - let (reason, gas_used) = match err { - crate::EvmError::Execution { reason, gas_used, .. } => (reason, gas_used), - _ => panic!("unexpected error variant"), - }; - assert_eq!(reason, "not equal to `hi`".to_string()); - assert_eq!(gas_used, 26569); - } - - #[test] - fn test_can_call_large_contract() { - let mut evm = vm(); - let compiled = COMPILED.find("LargeContract").expect("could not find contract"); - - let from = Address::random(); - let (addr, _, _, _) = - evm.deploy(from, compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - // makes a call to the contract - let sig = ethers::utils::id("foo()").to_vec(); - let res = evm.call_raw(from, addr, sig.into(), 0.into(), true).unwrap(); - // the retdata cannot be empty - assert!(!res.0.as_ref().is_empty()); - // the call must be successful - assert!(matches!(res.1, ExitReason::Succeed(_))); - } -} diff --git a/evm-adapters/src/sputnik/forked_backend/cache.rs b/evm-adapters/src/sputnik/forked_backend/cache.rs deleted file mode 100644 index 5f142c8afa90..000000000000 --- a/evm-adapters/src/sputnik/forked_backend/cache.rs +++ /dev/null @@ -1,549 +0,0 @@ -//! Smart caching and deduplication of requests when using a forking provider -use sputnik::backend::{Backend, Basic, MemoryAccount, MemoryVicinity}; - -use ethers::{ - providers::Middleware, - types::{Address, BlockId, Bytes, TxHash, H160, H256, U256}, -}; -use futures::{ - channel::mpsc::{channel, Receiver, Sender}, - stream::{Fuse, Stream, StreamExt}, - task::{Context, Poll}, - Future, FutureExt, -}; -use parking_lot::RwLock; -use std::{ - collections::{hash_map::Entry, BTreeMap, HashMap}, - pin::Pin, - sync::{ - mpsc::{channel as oneshot_channel, Sender as OneshotSender}, - Arc, - }, -}; - -use foundry_utils::RuntimeOrHandle; - -/// A basic in memory cache (address -> Account) -pub type MemCache = BTreeMap; - -/// A state cache that can be shared across threads -/// -/// This can can be used as global state cache. -pub type SharedCache = Arc>; - -/// Create a new shareable state cache. -/// -/// # Example -/// -/// ```rust -/// use evm_adapters::sputnik::{MemCache,new_shared_cache}; -/// let cache = new_shared_cache(MemCache::default()); -/// ``` -pub fn new_shared_cache(cache: T) -> SharedCache { - Arc::new(RwLock::new(cache)) -} - -type AccountFuture = - Pin, Address)> + Send>>; -type StorageFuture = Pin, Address, H256)> + Send>>; - -/// Request variants that are executed by the provider -enum ProviderRequest { - Account(AccountFuture), - Storage(StorageFuture), -} - -/// The Request type the Backend listens for -#[derive(Debug)] -enum BackendRequest { - Basic(Address, OneshotSender), - Exists(Address, OneshotSender), - Code(Address, OneshotSender>), - Storage(Address, H256, OneshotSender), -} - -/// Various types of senders waiting for an answer related to get_account request -enum AccountListener { - Exists(OneshotSender), - Basic(OneshotSender), - Code(OneshotSender>), -} - -/// Handles an internal provider and listens for requests. -/// -/// This handler will remain active as long as it is reachable (request channel still open) and -/// requests are in progress. -#[must_use = "BackendHandler does nothing unless polled."] -struct BackendHandler { - provider: M, - /// Stores the state. - cache: SharedCache, - /// Requests currently in progress - pending_requests: Vec>, - /// Listeners that wait for a `get_account` related response - /// We also store the `get_storage_at` responses until the initial account info is fetched. - /// The reason for that is because of the simple `address -> Account` model of the cache, so we - /// only create a new entry for an address of basic info (balance, nonce, code) was fetched. - account_requests: HashMap, BTreeMap)>, - /// Listeners that wait for a `get_storage_at` response - storage_requests: HashMap<(Address, H256), Vec>>, - /// Incoming commands. - incoming: Fuse>, - /// The block to fetch data from. - // This is an `Option` so that we can have less code churn in the functions below - block_id: Option, -} - -impl BackendHandler -where - M: Middleware + Clone + 'static, -{ - fn new( - provider: M, - cache: SharedCache, - rx: Receiver, - block_id: Option, - ) -> Self { - Self { - provider, - cache, - pending_requests: Default::default(), - account_requests: Default::default(), - storage_requests: Default::default(), - incoming: rx.fuse(), - block_id, - } - } - - /// handle the request in queue in the future. - /// - /// We always check: - /// 1. if the requested value is already stored in the cache, then answer the sender - /// 2. otherwise, fetch it via the provider but check if a request for that value is already in - /// progress (e.g. another Sender just requested the same account) - fn on_request(&mut self, req: BackendRequest) { - match req { - BackendRequest::Basic(addr, sender) => { - let lock = self.cache.read(); - let basic = - lock.get(&addr).map(|acc| Basic { nonce: acc.nonce, balance: acc.balance }); - // release the lock - drop(lock); - if let Some(basic) = basic { - let _ = sender.send(basic); - } else { - self.request_account(addr, AccountListener::Basic(sender)); - } - } - BackendRequest::Code(addr, sender) => { - let lock = self.cache.read(); - let code = lock.get(&addr).map(|acc| acc.code.clone()); - // release the lock - drop(lock); - if let Some(basic) = code { - let _ = sender.send(basic); - } else { - self.request_account(addr, AccountListener::Code(sender)); - } - } - BackendRequest::Exists(addr, sender) => { - let lock = self.cache.read(); - let acc = lock.get(&addr); - let has_account = acc.is_some(); - let exists = acc - .map(|acc| { - !acc.balance.is_zero() || !acc.nonce.is_zero() || !acc.code.is_empty() - }) - .unwrap_or_default(); - // release the lock - drop(lock); - - if has_account { - let _ = sender.send(exists); - } else { - self.request_account(addr, AccountListener::Exists(sender)); - } - } - BackendRequest::Storage(addr, idx, sender) => { - let lock = self.cache.read(); - let acc = lock.get(&addr); - let has_account = acc.is_some(); - let value = acc.and_then(|acc| acc.storage.get(&idx).copied()); - // release the lock - drop(lock); - - if has_account { - // account is already stored in the cache - if let Some(value) = value { - let _ = sender.send(value); - } else { - // account present but not storage -> fetch storage - self.request_account_storage(addr, idx, sender); - } - } else { - // account is still missing in the cache - // check if already fetched but not in cache yet - if let Some(value) = - self.account_requests.get(&addr).and_then(|(_, s)| s.get(&idx).copied()) - { - let _ = sender.send(value); - } else { - // fetch storage via provider - self.request_account_storage(addr, idx, sender); - } - } - } - } - } - - /// process a request for account's storage - fn request_account_storage( - &mut self, - address: Address, - idx: H256, - listener: OneshotSender, - ) { - match self.storage_requests.entry((address, idx)) { - Entry::Occupied(mut entry) => { - entry.get_mut().push(listener); - } - Entry::Vacant(entry) => { - entry.insert(vec![listener]); - let provider = self.provider.clone(); - let block_id = self.block_id; - let fut = Box::pin(async move { - let storage = provider.get_storage_at(address, idx, block_id).await; - (storage, address, idx) - }); - self.pending_requests.push(ProviderRequest::Storage(fut)); - } - } - } - - /// returns the future that fetches the account data - fn get_account_req(&self, address: Address) -> ProviderRequest { - let provider = self.provider.clone(); - let block_id = self.block_id; - let fut = Box::pin(async move { - let balance = provider.get_balance(address, block_id); - let nonce = provider.get_transaction_count(address, block_id); - let code = provider.get_code(address, block_id); - let resp = tokio::try_join!(balance, nonce, code); - (resp, address) - }); - ProviderRequest::Account(fut) - } - - /// process a request for an account - fn request_account(&mut self, address: Address, listener: AccountListener) { - match self.account_requests.entry(address) { - Entry::Occupied(mut entry) => { - entry.get_mut().0.push(listener); - } - Entry::Vacant(entry) => { - entry.insert((vec![listener], Default::default())); - self.pending_requests.push(self.get_account_req(address)); - } - } - } -} - -impl Future for BackendHandler -where - M: Middleware + Clone + Unpin + 'static, -{ - type Output = (); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let pin = self.get_mut(); - - // receive new requests to delegate to the underlying provider - while let Poll::Ready(Some(req)) = Pin::new(&mut pin.incoming).poll_next(cx) { - pin.on_request(req) - } - - // poll all requests in progress - for n in (0..pin.pending_requests.len()).rev() { - let mut request = pin.pending_requests.swap_remove(n); - match &mut request { - ProviderRequest::Account(fut) => { - if let Poll::Ready((resp, addr)) = fut.poll_unpin(cx) { - let (balance, nonce, code) = resp.unwrap_or_else(|_| { - tracing::trace!("Failed to get account for {}", addr); - Default::default() - }); - let code = code.to_vec(); - let (listeners, storage) = - pin.account_requests.remove(&addr).unwrap_or_default(); - let acc = MemoryAccount { nonce, balance, code: code.clone(), storage }; - pin.cache.write().insert(addr, acc); - // notify all listeners - for listener in listeners { - match listener { - AccountListener::Exists(sender) => { - let exists = - !balance.is_zero() || !nonce.is_zero() || !code.is_empty(); - let _ = sender.send(exists); - } - AccountListener::Basic(sender) => { - let _ = sender.send(Basic { nonce, balance }); - } - AccountListener::Code(sender) => { - let _ = sender.send(code.clone()); - } - } - } - continue - } - } - ProviderRequest::Storage(fut) => { - if let Poll::Ready((resp, addr, idx)) = fut.poll_unpin(cx) { - let value = resp.unwrap_or_else(|_| { - tracing::trace!("Failed to get storage for {} at {}", addr, idx); - Default::default() - }); - if let Some(acc) = pin.cache.write().get_mut(&addr) { - acc.storage.insert(idx, value); - } else { - // the account not fetched yet, we either add this value to the storage - // buffer of the request in progress or start the `get_account` request - match pin.account_requests.entry(addr) { - Entry::Occupied(mut entry) => { - entry.get_mut().1.insert(idx, value); - } - Entry::Vacant(entry) => { - let mut storage = BTreeMap::new(); - storage.insert(idx, value); - entry.insert((vec![], storage)); - pin.pending_requests.push(pin.get_account_req(addr)); - } - } - } - // notify all listeners - if let Some(listeners) = pin.storage_requests.remove(&(addr, idx)) { - listeners.into_iter().for_each(|l| { - let _ = l.send(value); - }) - } - continue - } - } - } - // not ready, insert and poll again - pin.pending_requests.push(request); - } - // the handler is finished if the request channel was closed and all requests are processed - if pin.incoming.is_done() && pin.pending_requests.is_empty() { - Poll::Ready(()) - } else { - Poll::Pending - } - } -} - -/// A cloneable backend type that shares access to the backend data with all its clones. -/// -/// This backend type is connected to the `BackendHandler` via a mpsc channel. The `BackendHandlers` -/// is spawned on a background thread and listens for incoming commands on the receiver half of the -/// channel. A `SharedBackend` holds a sender for that channel, which is `Clone`, so their can be -/// multiple `SharedBackend`s communicating with the same `BackendHandler`, hence this `Backend` -/// type is thread safe. -/// -/// All `Backend` trait functions are delegated as a `BackendRequest` via the channel to the -/// `BackendHandler`. All `BackendRequest` variants include a sender half of an additional channel -/// that is used by the `BackendHandler` to send the result of an executed `BackendRequest` back to -/// `SharedBackend`. -/// -/// The `BackendHandler` holds an ethers `Provider` to look up missing accounts or storage slots -/// from remote (e.g. infura). It detects duplicate requests from multiple `SharedBackend`s and -/// bundles them together, so that always only one provider request is executed. For example, there -/// are two `SharedBackend`s, `A` and `B`, both request the basic account info of account -/// `0xasd9sa7d...` at the same time. After the `BackendHandler` receives the request from `A`, it -/// sends a new provider request to the provider's endpoint, then it reads the identical request -/// from `B` and simply adds it as an additional listener for the request already in progress, -/// instead of sending another one. So that after the provider returns the response all listeners -/// (`A` and `B`) get notified. -#[derive(Debug, Clone)] -pub struct SharedBackend { - inner: SharedBackendInner, -} - -impl SharedBackend { - /// Spawns a new `BackendHandler` on a background thread that listens for requests from any - /// `SharedBackend`. Missing values get inserted in the `cache`. - /// - /// NOTE: this should be called with `Arc` - pub fn new( - provider: M, - cache: SharedCache, - vicinity: MemoryVicinity, - pin_block: Option, - ) -> Self - where - M: Middleware + Unpin + 'static + Clone, - { - let (tx, rx) = channel(1); - let handler = BackendHandler::new(provider, cache, rx, pin_block); - // spawn the provider handler to background - let rt = RuntimeOrHandle::new(); - std::thread::spawn(move || match rt { - RuntimeOrHandle::Runtime(runtime) => runtime.block_on(handler), - RuntimeOrHandle::Handle(handle) => handle.block_on(handler), - }); - - Self { inner: SharedBackendInner { vicinity: Arc::new(vicinity), backend: tx } } - } - - fn do_get_exists(&self, address: H160) -> eyre::Result { - let (sender, rx) = oneshot_channel(); - let req = BackendRequest::Exists(address, sender); - self.inner.backend.clone().try_send(req).map_err(|e| eyre::eyre!("{:?}", e))?; - Ok(rx.recv()?) - } - - fn do_get_basic(&self, address: H160) -> eyre::Result { - let (sender, rx) = oneshot_channel(); - let req = BackendRequest::Basic(address, sender); - self.inner.backend.clone().try_send(req).map_err(|e| eyre::eyre!("{:?}", e))?; - Ok(rx.recv()?) - } - - fn do_get_code(&self, address: H160) -> eyre::Result> { - let (sender, rx) = oneshot_channel(); - let req = BackendRequest::Code(address, sender); - self.inner.backend.clone().try_send(req).map_err(|e| eyre::eyre!("{:?}", e))?; - Ok(rx.recv()?) - } - - fn do_get_storage(&self, address: H160, index: H256) -> eyre::Result { - let (sender, rx) = oneshot_channel(); - let req = BackendRequest::Storage(address, index, sender); - self.inner.backend.clone().try_send(req).map_err(|e| eyre::eyre!("{:?}", e))?; - Ok(rx.recv()?) - } -} - -impl Backend for SharedBackend { - fn gas_price(&self) -> U256 { - self.inner.vicinity.gas_price - } - fn origin(&self) -> H160 { - self.inner.vicinity.origin - } - fn block_hash(&self, number: U256) -> H256 { - if number >= self.inner.vicinity.block_number || - self.inner.vicinity.block_number - number - U256::one() >= - U256::from(self.inner.vicinity.block_hashes.len()) - { - H256::default() - } else { - let index = (self.inner.vicinity.block_number - number - U256::one()).as_usize(); - self.inner.vicinity.block_hashes[index] - } - } - fn block_number(&self) -> U256 { - self.inner.vicinity.block_number - } - fn block_coinbase(&self) -> H160 { - self.inner.vicinity.block_coinbase - } - fn block_timestamp(&self) -> U256 { - self.inner.vicinity.block_timestamp - } - fn block_difficulty(&self) -> U256 { - self.inner.vicinity.block_difficulty - } - fn block_gas_limit(&self) -> U256 { - self.inner.vicinity.block_gas_limit - } - fn block_base_fee_per_gas(&self) -> U256 { - self.inner.vicinity.block_base_fee_per_gas - } - - fn chain_id(&self) -> U256 { - self.inner.vicinity.chain_id - } - - fn exists(&self, address: H160) -> bool { - self.do_get_exists(address).unwrap_or_else(|_| { - tracing::trace!("Failed to send/recv `exists` for {}", address); - Default::default() - }) - } - - fn basic(&self, address: H160) -> Basic { - self.do_get_basic(address).unwrap_or_else(|_| { - tracing::trace!("Failed to send/recv `basic` for {}", address); - Default::default() - }) - } - - fn code(&self, address: H160) -> Vec { - self.do_get_code(address).unwrap_or_else(|_| { - tracing::trace!("Failed to send/recv `code` for {}", address); - Default::default() - }) - } - - fn storage(&self, address: H160, index: TxHash) -> TxHash { - self.do_get_storage(address, index).unwrap_or_else(|_| { - tracing::trace!("Failed to send/recv `storage` for {} at {}", address, index); - Default::default() - }) - } - - fn original_storage(&self, address: H160, index: TxHash) -> Option { - Some(self.storage(address, index)) - } -} - -#[derive(Debug, Clone)] -struct SharedBackendInner { - vicinity: Arc, - backend: Sender, -} - -#[cfg(test)] -mod tests { - use crate::sputnik::vicinity; - use ethers::types::Address; - - use tokio::runtime::Runtime; - - use super::*; - - #[test] - fn shared_backend() { - let provider = ethers::providers::MAINNET.provider(); - // some rng contract from etherscan - let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap(); - - let rt = Runtime::new().unwrap(); - let vicinity = rt.block_on(vicinity(&provider, None, None, None)).unwrap(); - let cache = new_shared_cache(MemCache::default()); - - let backend = SharedBackend::new(Arc::new(provider), cache.clone(), vicinity, None); - - let idx = H256::from_low_u64_be(0u64); - let value = backend.storage(address, idx); - let account = backend.basic(address); - - let mem_acc = cache.read().get(&address).unwrap().clone(); - assert_eq!(account.balance, mem_acc.balance); - assert_eq!(account.nonce, mem_acc.nonce,); - assert_eq!(mem_acc.storage.len(), 1); - assert_eq!(mem_acc.storage.get(&idx).copied().unwrap(), value); - - let backend = backend; - let max_slots = 5; - let handle = std::thread::spawn(move || { - for i in 1..max_slots { - let idx = H256::from_low_u64_be(i); - let _ = backend.storage(address, idx); - } - }); - handle.join().unwrap(); - let mem_acc = cache.read().get(&address).unwrap().clone(); - assert_eq!(mem_acc.storage.len() as u64, max_slots); - } -} diff --git a/evm-adapters/src/sputnik/forked_backend/mod.rs b/evm-adapters/src/sputnik/forked_backend/mod.rs deleted file mode 100644 index e66cd2b3629b..000000000000 --- a/evm-adapters/src/sputnik/forked_backend/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod cache; -pub use cache::{new_shared_cache, MemCache, SharedBackend, SharedCache}; -pub mod rpc; -pub use rpc::ForkMemoryBackend; diff --git a/evm-adapters/src/sputnik/forked_backend/rpc.rs b/evm-adapters/src/sputnik/forked_backend/rpc.rs deleted file mode 100644 index 864fc0125840..000000000000 --- a/evm-adapters/src/sputnik/forked_backend/rpc.rs +++ /dev/null @@ -1,244 +0,0 @@ -//! Simple in-memory cache backend for use with forking providers -use std::{cell::RefCell, collections::BTreeMap}; - -use ethers::{ - providers::Middleware, - types::{Block, BlockId, BlockNumber, TxHash, H160, H256, U256}, -}; -use sputnik::backend::{Backend, Basic, MemoryAccount}; - -use crate::BlockingProvider; - -/// Memory backend with ability to fork another chain from an HTTP provider, storing all cache -/// values in a `BTreeMap` in memory. -// TODO: Add option to easily 1. impersonate accounts, 2. roll back to pinned block -// TODO: In order to improve speed, does it make sense to add a job which pre-fetches -// accounts speculatively? Or maybe do it for smart contract code which is typically the -// biggest issue? -// TODO: In order to improve speed, can we instead write a custom blocking provider which -// does not block_on in-line, but has a background thread that polls everything in parallel -// and just returns the results synchronously via some channel? -pub struct ForkMemoryBackend { - /// ethers middleware for querying on-chain data - pub provider: BlockingProvider, - /// The internal backend - pub backend: B, - /// cache state - // TODO: Actually cache values in memory. - // TODO: This should probably be abstracted away into something that efficiently - // also caches at disk etc. - pub cache: RefCell>, - /// The block to fetch data from. - // This is an `Option` so that we can have less code churn in the functions below - pin_block: Option, - /// The block at which we forked off - pin_block_meta: Block, - /// The chain id of the forked chain - chain_id: U256, -} - -impl ForkMemoryBackend -where - M::Error: 'static, -{ - pub fn new( - provider: M, - backend: B, - pin_block: Option, - init_cache: BTreeMap, - ) -> Self { - let provider = BlockingProvider::new(provider); - - // get the remaining block metadata - let (block, chain_id) = - provider.block_and_chainid(pin_block).expect("could not get block meta and chain id"); - - Self { - provider, - backend, - cache: RefCell::new(init_cache), - pin_block: pin_block.map(Into::into), - pin_block_meta: block, - chain_id, - } - } -} - -impl Backend for ForkMemoryBackend -where - M::Error: 'static, -{ - fn gas_price(&self) -> U256 { - self.backend.gas_price() - } - - fn origin(&self) -> H160 { - self.backend.origin() - } - - fn block_hash(&self, number: U256) -> H256 { - self.backend.block_hash(number) - } - - fn block_number(&self) -> U256 { - self.pin_block - .and_then(|block| match block { - BlockId::Number(num) => match num { - BlockNumber::Number(num) => Some(num.as_u64().into()), - _ => None, - }, - BlockId::Hash(_) => None, - }) - .unwrap_or_else(|| self.backend.block_number()) - } - - fn block_coinbase(&self) -> H160 { - self.pin_block_meta.author - } - - fn block_timestamp(&self) -> U256 { - self.pin_block_meta.timestamp - } - - fn block_difficulty(&self) -> U256 { - self.pin_block_meta.difficulty - } - - fn block_gas_limit(&self) -> U256 { - self.pin_block_meta.gas_limit - } - - fn block_base_fee_per_gas(&self) -> U256 { - self.pin_block_meta.base_fee_per_gas.unwrap_or_default() - } - - fn chain_id(&self) -> U256 { - self.chain_id - } - - fn exists(&self, address: H160) -> bool { - let mut exists = self.cache.borrow().contains_key(&address); - - // check non-zero balance - if !exists { - let mut cache = self.cache.borrow_mut(); - let account = cache.entry(address).or_insert_with(|| { - let res = self.provider.get_account(address, self.pin_block).unwrap_or_default(); - MemoryAccount { - nonce: res.0, - balance: res.1, - code: res.2.to_vec(), - storage: Default::default(), - } - }); - exists = account.balance != U256::zero() || - account.nonce != U256::zero() || - !account.code.is_empty(); - } - - exists - } - - fn basic(&self, address: H160) -> Basic { - let mut cache = self.cache.borrow_mut(); - let account = cache.entry(address).or_insert_with(|| { - let res = self.provider.get_account(address, self.pin_block).unwrap_or_default(); - MemoryAccount { - nonce: res.0, - balance: res.1, - code: res.2.to_vec(), - storage: Default::default(), - } - }); - Basic { balance: account.balance, nonce: account.nonce } - } - - fn code(&self, address: H160) -> Vec { - let mut cache = self.cache.borrow_mut(); - let account = cache.entry(address).or_insert_with(|| { - // println!("didnt have account code {:?}", address); - let res = self.provider.get_account(address, self.pin_block).unwrap_or_default(); - MemoryAccount { - nonce: res.0, - balance: res.1, - code: res.2.to_vec(), - storage: Default::default(), - } - }); - account.code.clone() - } - - fn storage(&self, address: H160, index: H256) -> H256 { - let mut cache = self.cache.borrow_mut(); - let account = cache.entry(address).or_insert_with(|| { - let res = self.provider.get_account(address, self.pin_block).unwrap_or_default(); - MemoryAccount { - nonce: res.0, - balance: res.1, - code: res.2.to_vec(), - storage: Default::default(), - } - }); - if let Some(val) = account.storage.get(&index) { - *val - } else { - let ret = - self.provider.get_storage_at(address, index, self.pin_block).unwrap_or_default(); - account.storage.insert(index, ret); - ret - } - } - - fn original_storage(&self, address: H160, index: H256) -> Option { - Some(self.storage(address, index)) - } -} - -#[cfg(test)] -mod tests { - - use ethers::types::Address; - use sputnik::Config; - use tokio::runtime::Runtime; - - use crate::{ - sputnik::{helpers::new_backend, vicinity, Executor, PRECOMPILES_MAP}, - test_helpers::COMPILED, - Evm, - }; - - use super::*; - - #[test] - fn forked_backend() { - let cfg = Config::london(); - let compiled = COMPILED.find("Greeter").expect("could not find contract"); - - let provider = ethers::providers::MAINNET.provider(); - let rt = Runtime::new().unwrap(); - let blk = Some(13292465); - let vicinity = rt.block_on(vicinity(&provider, None, blk, None)).unwrap(); - let backend = new_backend(&vicinity, Default::default()); - let backend = ForkMemoryBackend::new(provider, backend, blk, Default::default()); - - let precompiles = PRECOMPILES_MAP.clone(); - let mut evm = Executor::new(12_000_000, &cfg, &backend, &precompiles); - - let (addr, _, _, _) = - evm.deploy(Address::zero(), compiled.bytecode().unwrap().clone(), 0.into()).unwrap(); - - let (res, _, _, _) = evm - .call::( - Address::zero(), - addr, - "time()(uint256)", - (), - 0.into(), - compiled.abi, - ) - .unwrap(); - - // https://etherscan.io/block/13292465 - assert_eq!(res.as_u64(), 1632539668); - } -} diff --git a/evm-adapters/src/sputnik/mod.rs b/evm-adapters/src/sputnik/mod.rs deleted file mode 100644 index 055b95c7835b..000000000000 --- a/evm-adapters/src/sputnik/mod.rs +++ /dev/null @@ -1,286 +0,0 @@ -mod evm; -pub use evm::*; - -mod forked_backend; -pub use forked_backend::*; - -pub mod cheatcodes; -pub mod state; - -use ethers::{ - abi::RawLog, - providers::Middleware, - types::{Address, H160, H256, U256}, -}; - -use sputnik::{ - backend::MemoryVicinity, - executor::stack::{PrecompileFailure, PrecompileOutput, StackExecutor, StackState}, - Config, CreateScheme, ExitError, ExitReason, ExitSucceed, -}; - -use crate::{call_tracing::CallTraceArena, sputnik::cheatcodes::debugger::DebugArena}; - -pub use sputnik as sputnik_evm; -use sputnik_evm::executor::stack::PrecompileSet; - -/// Given an ethers provider and a block, it proceeds to construct a [`MemoryVicinity`] from -/// the live chain data returned by the provider. -pub async fn vicinity( - provider: &M, - override_chain_id: Option, - pin_block: Option, - origin: Option, -) -> Result { - let block_number = if let Some(pin_block) = pin_block { - pin_block - } else { - provider.get_block_number().await?.as_u64() - }; - let (gas_price, rpc_chain_id, block) = tokio::try_join!( - provider.get_gas_price(), - provider.get_chainid(), - provider.get_block(block_number) - )?; - let block = block.expect("block not found"); - - Ok(MemoryVicinity { - origin: origin.unwrap_or_default(), - chain_id: override_chain_id.map_or(rpc_chain_id, Into::into), - block_hashes: Vec::new(), - block_number: block.number.expect("block number not found").as_u64().into(), - block_coinbase: block.author, - block_difficulty: block.difficulty, - block_gas_limit: block.gas_limit, - block_timestamp: block.timestamp, - block_base_fee_per_gas: block.base_fee_per_gas.unwrap_or_default(), - gas_price, - }) -} - -/// Abstraction over the StackExecutor used inside of Sputnik, so that we can replace -/// it with one that implements HEVM-style cheatcodes (or other features). -pub trait SputnikExecutor { - fn config(&self) -> &Config; - fn state(&self) -> &S; - fn state_mut(&mut self) -> &mut S; - fn expected_revert(&self) -> Option<&[u8]>; - fn set_tracing_enabled(&mut self, enabled: bool) -> bool; - fn tracing_enabled(&self) -> bool; - fn debug_calls(&self) -> Vec; - fn all_logs(&self) -> Vec; - fn gas_left(&self) -> U256; - fn gas_used(&self) -> U256; - fn gas_refund(&self) -> U256; - fn transact_call( - &mut self, - caller: H160, - address: H160, - value: U256, - data: Vec, - gas_limit: u64, - access_list: Vec<(H160, Vec)>, - ) -> (ExitReason, Vec); - - fn transact_create( - &mut self, - caller: H160, - value: U256, - data: Vec, - gas_limit: u64, - access_list: Vec<(H160, Vec)>, - ) -> ExitReason; - - fn create_address(&self, caller: CreateScheme) -> Address; - - /// Returns a vector of raw logs that occurred during the previous VM - /// execution - fn raw_logs(&self) -> Vec; - - /// Gets a trace - fn traces(&self) -> Vec { - vec![] - } - - fn reset_traces(&mut self) {} - - /// Returns a vector of string parsed logs that occurred during the previous VM - /// execution - fn logs(&self) -> Vec; - - /// Clears all logs in the current EVM instance, so that subsequent calls to - /// `logs` do not print duplicate logs on shared EVM instances. - fn clear_logs(&mut self); -} - -// The implementation for the base Stack Executor just forwards to the internal methods. -#[allow(clippy::only_used_in_recursion)] -impl<'a, 'b, S: StackState<'a>, P: PrecompileSet> SputnikExecutor - for StackExecutor<'a, 'b, S, P> -{ - fn config(&self) -> &Config { - self.config() - } - - fn state(&self) -> &S { - self.state() - } - - fn state_mut(&mut self) -> &mut S { - self.state_mut() - } - - fn expected_revert(&self) -> Option<&[u8]> { - None - } - - fn set_tracing_enabled(&mut self, _enabled: bool) -> bool { - false - } - - fn tracing_enabled(&self) -> bool { - false - } - - fn debug_calls(&self) -> Vec { - vec![] - } - - fn all_logs(&self) -> Vec { - vec![] - } - - fn gas_left(&self) -> U256 { - // NB: We do this to avoid `function cannot return without recursing` - U256::from(self.state().metadata().gasometer().gas()) - } - - fn gas_used(&self) -> U256 { - U256::from(self.state().metadata().gasometer().total_used_gas()) - } - - fn gas_refund(&self) -> U256 { - U256::from(self.state().metadata().gasometer().refunded_gas()) - } - - fn transact_call( - &mut self, - caller: H160, - address: H160, - value: U256, - data: Vec, - gas_limit: u64, - access_list: Vec<(H160, Vec)>, - ) -> (ExitReason, Vec) { - self.transact_call(caller, address, value, data, gas_limit, access_list) - } - - fn transact_create( - &mut self, - caller: H160, - value: U256, - data: Vec, - gas_limit: u64, - access_list: Vec<(H160, Vec)>, - ) -> ExitReason { - self.transact_create(caller, value, data, gas_limit, access_list).0 - } - - fn create_address(&self, scheme: CreateScheme) -> Address { - self.create_address(scheme) - } - - // Empty impls for non-cheatcode handlers - fn logs(&self) -> Vec { - vec![] - } - - fn raw_logs(&self) -> Vec { - vec![] - } - - fn clear_logs(&mut self) {} -} - -use std::borrow::Cow; - -pub type PrecompileFn = - fn(&[u8], Option, &sputnik::Context, bool) -> Result; - -/// Precompiled contracts which should be provided when instantiating the EVM. -pub static PRECOMPILES: Lazy = Lazy::new(|| { - // We use the const to immediately choose the latest revision of available - // precompiles. Is this wrong maybe? - revm_precompiles::Precompiles::new::<3>() -}); - -// https://github.com/rust-blockchain/evm-tests/blob/d53b17989db45d76b5876b33db63bcaf367a53fa/jsontests/src/state.rs#L55 -// We need to do this because closures can only be coerced to `fn` types if they do not capture any -// variables -macro_rules! precompile_entry { - ($map:expr, $index:expr) => { - let x: fn( - &[u8], - Option, - &Context, - bool, - ) -> Result = - |input: &[u8], gas_limit: Option, _context: &Context, _is_static: bool| { - let precompile = PRECOMPILES.get(&H160::from_low_u64_be($index)).unwrap(); - crate::sputnik::exec(&precompile, input, gas_limit.unwrap()) - }; - $map.insert(H160::from_low_u64_be($index), x); - }; -} - -use once_cell::sync::Lazy; -use sputnik::Context; -use std::collections::BTreeMap; -/// Map of Address => [Precompile](PRECOMPILES) contracts -pub static PRECOMPILES_MAP: Lazy> = Lazy::new(|| { - let mut map = BTreeMap::new(); - precompile_entry!(map, 1); - precompile_entry!(map, 2); - precompile_entry!(map, 3); - precompile_entry!(map, 4); - precompile_entry!(map, 5); - precompile_entry!(map, 6); - precompile_entry!(map, 7); - precompile_entry!(map, 8); - precompile_entry!(map, 9); - map -}); - -/// Runs the provided precompile against the input data. -pub fn exec( - builtin: &revm_precompiles::Precompile, - input: &[u8], - gas_limit: u64, -) -> Result { - let res = match builtin { - revm_precompiles::Precompile::Standard(func) => func(input, gas_limit), - revm_precompiles::Precompile::Custom(func) => func(input, gas_limit), - }; - match res { - Ok(res) => { - let logs = res - .logs - .into_iter() - .map(|log| sputnik::backend::Log { - topics: log.topics, - data: log.data.to_vec(), - address: log.address, - }) - .collect(); - Ok(PrecompileOutput { - exit_status: ExitSucceed::Stopped, - output: res.output, - cost: res.cost, - logs, - }) - } - Err(_) => { - Err(PrecompileFailure::Error { exit_status: ExitError::Other(Cow::Borrowed("error")) }) - } - } -} diff --git a/evm-adapters/src/sputnik/state.rs b/evm-adapters/src/sputnik/state.rs deleted file mode 100644 index 1f8db5e759fe..000000000000 --- a/evm-adapters/src/sputnik/state.rs +++ /dev/null @@ -1,351 +0,0 @@ -use ethers::abi::ethereum_types::{H160, H256, U256}; -use parking_lot::RwLock; -use sputnik::{ - backend::{Apply, Backend, Basic, Log}, - executor::stack::{MemoryStackSubstate, StackState, StackSubstateMetadata}, - ExitError, Transfer, -}; -use std::{fmt::Debug, ops::Deref, sync::Arc}; - -/// A state that can be shared across threads -/// -/// This can can be used as global state. -pub type SharedState = Arc>; - -/// Create a new shareable state. -pub fn new_shared_state<'config, S: StackState<'config>>(state: S) -> SharedState { - Arc::new(RwLock::new(state)) -} - -/// A state that branches off from the shared state and operates according to the following rules: -/// -/// Reading: -/// - forked local state takes precedent over shared state: if the storage value is not present in -/// the local state, it queries the shared state. -/// -/// Writing: -/// - all memory altering operations will be applied to the local state -#[derive(Clone)] -pub struct ForkedState<'config, S> { - shared_state: SharedState, - substate: MemoryStackSubstate<'config>, -} - -impl<'config, S> Debug for ForkedState<'config, S> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ForkedState").field("substate", &self.substate).finish_non_exhaustive() - } -} - -impl<'config, S> ForkedState<'config, S> -where - S: StackState<'config>, -{ - /// Create a new forked state with the `SharedState` as root state - /// This will initialize a new, empty substate that will hold all modifications to the - /// shared_state, so that the shared state remains untouched. - pub fn new(shared_state: SharedState, metadata: StackSubstateMetadata<'config>) -> Self { - Self { shared_state, substate: MemoryStackSubstate::new(metadata) } - } - - #[must_use] - pub fn deconstruct( - self, - ) -> ( - impl IntoIterator>>, - impl IntoIterator, - ) { - self.substate.deconstruct(self.shared_state.read().deref()) - } - - pub fn withdraw(&mut self, address: H160, value: U256) -> Result<(), ExitError> { - self.substate.withdraw(address, value, self.shared_state.read().deref()) - } - - pub fn deposit(&mut self, address: H160, value: U256) { - self.substate.deposit(address, value, self.shared_state.read().deref()) - } -} - -impl<'config, S> Backend for ForkedState<'config, S> -where - S: StackState<'config>, -{ - fn gas_price(&self) -> U256 { - self.shared_state.read().gas_price() - } - fn origin(&self) -> H160 { - self.shared_state.read().origin() - } - fn block_hash(&self, number: U256) -> H256 { - self.shared_state.read().block_hash(number) - } - fn block_number(&self) -> U256 { - self.shared_state.read().block_number() - } - fn block_coinbase(&self) -> H160 { - self.shared_state.read().block_coinbase() - } - fn block_timestamp(&self) -> U256 { - self.shared_state.read().block_timestamp() - } - fn block_difficulty(&self) -> U256 { - self.shared_state.read().block_difficulty() - } - fn block_gas_limit(&self) -> U256 { - self.shared_state.read().block_gas_limit() - } - fn block_base_fee_per_gas(&self) -> U256 { - self.shared_state.read().block_base_fee_per_gas() - } - fn chain_id(&self) -> U256 { - self.shared_state.read().chain_id() - } - - fn exists(&self, address: H160) -> bool { - self.substate.known_account(address).is_some() || self.shared_state.read().exists(address) - } - - fn basic(&self, address: H160) -> Basic { - self.substate - .known_basic(address) - .unwrap_or_else(|| self.shared_state.read().basic(address)) - } - - fn code(&self, address: H160) -> Vec { - self.substate.known_code(address).unwrap_or_else(|| self.shared_state.read().code(address)) - } - - fn storage(&self, address: H160, key: H256) -> H256 { - self.substate - .known_storage(address, key) - .unwrap_or_else(|| self.shared_state.read().storage(address, key)) - } - - fn original_storage(&self, address: H160, key: H256) -> Option { - if let Some(value) = self.substate.known_original_storage(address, key) { - return Some(value) - } - self.shared_state.read().original_storage(address, key) - } -} - -impl<'config, S> StackState<'config> for ForkedState<'config, S> -where - S: StackState<'config>, -{ - fn metadata(&self) -> &StackSubstateMetadata<'config> { - self.substate.metadata() - } - - fn metadata_mut(&mut self) -> &mut StackSubstateMetadata<'config> { - self.substate.metadata_mut() - } - - fn enter(&mut self, gas_limit: u64, is_static: bool) { - self.substate.enter(gas_limit, is_static) - } - - fn exit_commit(&mut self) -> Result<(), ExitError> { - self.substate.exit_commit() - } - - fn exit_revert(&mut self) -> Result<(), ExitError> { - self.substate.exit_revert() - } - - fn exit_discard(&mut self) -> Result<(), ExitError> { - self.substate.exit_discard() - } - - fn is_empty(&self, address: H160) -> bool { - if let Some(known_empty) = self.substate.known_empty(address) { - return known_empty - } - - let basic = self.shared_state.read().basic(address); - basic.balance == U256::zero() && - basic.nonce == U256::zero() && - self.shared_state.read().code(address).is_empty() - } - - fn deleted(&self, address: H160) -> bool { - self.substate.deleted(address) - } - - fn is_cold(&self, address: H160) -> bool { - self.substate.is_cold(address) - } - - fn is_storage_cold(&self, address: H160, key: H256) -> bool { - self.substate.is_storage_cold(address, key) - } - - fn inc_nonce(&mut self, address: H160) { - self.substate.inc_nonce(address, self.shared_state.read().deref()); - } - - fn set_storage(&mut self, address: H160, key: H256, value: H256) { - self.substate.set_storage(address, key, value) - } - - fn reset_storage(&mut self, address: H160) { - self.substate.reset_storage(address, self.shared_state.read().deref()); - } - - fn log(&mut self, address: H160, topics: Vec, data: Vec) { - self.substate.log(address, topics, data); - } - - fn set_deleted(&mut self, address: H160) { - self.substate.set_deleted(address) - } - - fn set_code(&mut self, address: H160, code: Vec) { - self.substate.set_code(address, code, self.shared_state.read().deref()); - } - - fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError> { - self.substate.transfer(transfer, self.shared_state.read().deref()) - } - - fn reset_balance(&mut self, address: H160) { - self.substate.reset_balance(address, self.shared_state.read().deref()); - } - - fn touch(&mut self, address: H160) { - self.substate.touch(address, self.shared_state.read().deref()); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sputnik::{ - forked_backend::MemCache, helpers::new_vicinity, new_shared_cache, SharedBackend, - SharedCache, - }; - use ethers::abi::Address; - use once_cell::sync::Lazy; - use sputnik::{ - backend::{MemoryBackend, MemoryVicinity}, - executor::stack::MemoryStackState, - Config, - }; - - // We need a bunch of global static values in order to satisfy sputnik's lifetime requirements - // for `'static` so that we can Send them - static G_CONFIG: Lazy = Lazy::new(Config::istanbul); - static G_VICINITY: Lazy = Lazy::new(new_vicinity); - - // This is the root `Backend` that stores all root state - static G_BACKEND: Lazy = - Lazy::new(|| MemoryBackend::new(&*G_VICINITY, Default::default())); - - // Type that hold the global root storage type and a shareable Backend - struct GlobalBackend { - cache: SharedCache, - backend: SharedBackend, - } - - // this is pretty horrible but the sputnik types require 'static lifetime in order to be - // shareable - static G_FORKED_BACKEND: Lazy = Lazy::new(|| { - let cache = new_shared_cache(MemCache::default()); - let provider = ethers::providers::MAINNET.provider(); - let vicinity = G_VICINITY.clone(); - let backend = SharedBackend::new(Arc::new(provider), cache.clone(), vicinity, None); - GlobalBackend { cache, backend } - }); - - // this looks horrendous and is due to how sputnik borrows - fn setup_states() -> ( - SharedState>, - ForkedState<'static, MemoryStackState<'static, 'static, SharedBackend>>, - ) { - let gas_limit = 12_000_000; - let metadata = StackSubstateMetadata::new(gas_limit, &*G_CONFIG); - let state = MemoryStackState::new(metadata.clone(), &G_FORKED_BACKEND.backend); - - let shared_state = new_shared_state(state); - let forked_state = ForkedState::new(shared_state.clone(), metadata.clone()); - (shared_state, forked_state) - } - - #[test] - fn forked_shared_state_works() { - let (shared_state, mut forked_state) = setup_states(); - - // some rng contract from etherscan - let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap(); - - assert!(shared_state.read().exists(address)); - assert!(forked_state.exists(address)); - - let amount = shared_state.read().basic(address).balance; - assert_eq!(forked_state.basic(address).balance, amount); - - forked_state.deposit(address, amount); - assert_eq!(forked_state.basic(address).balance, amount * 2); - // shared state remains the same - assert_eq!(shared_state.read().basic(address).balance, amount); - assert_eq!(G_FORKED_BACKEND.cache.read().get(&address).unwrap().balance, amount); - } - - #[test] - fn can_spawn_state_to_thread() { - // some rng contract from etherscan - let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap(); - - let (shared_state, mut forked_state) = setup_states(); - - let amount = shared_state.read().basic(address).balance; - let t = std::thread::spawn(move || { - forked_state.deposit(address, amount); - assert_eq!(forked_state.basic(address).balance, amount * 2); - }); - t.join().unwrap(); - - // amount remains unchanged - assert_eq!(shared_state.read().basic(address).balance, amount); - } - - #[test] - fn shared_state_works() { - let gas_limit = 12_000_000; - let metadata = StackSubstateMetadata::new(gas_limit, &*G_CONFIG); - let state = MemoryStackState::new(metadata.clone(), &*G_BACKEND); - - let shared_state = new_shared_state(state); - let mut forked_state = ForkedState::new(shared_state.clone(), metadata.clone()); - - // deposit some funds in a new address - let address = Address::random(); - assert!(!shared_state.read().exists(address)); - assert!(!forked_state.exists(address)); - - let amount = 1337u64.into(); - shared_state.write().deposit(address, amount); - - assert!(shared_state.read().exists(address)); - assert!(forked_state.exists(address)); - assert_eq!(shared_state.read().basic(address).balance, amount); - assert_eq!(forked_state.basic(address).balance, amount); - - // double deposit in fork - forked_state.deposit(address, amount); - assert_eq!(forked_state.basic(address).balance, amount * 2); - // shared state remains the same - assert_eq!(shared_state.read().basic(address).balance, amount); - - let mut another_forked_state = ForkedState::new(shared_state.clone(), metadata); - let t = std::thread::spawn(move || { - assert_eq!(another_forked_state.basic(address).balance, amount); - another_forked_state.deposit(address, amount * 10); - }); - t.join().unwrap(); - - assert_eq!(forked_state.basic(address).balance, amount * 2); - assert_eq!(shared_state.read().basic(address).balance, amount); - } -} diff --git a/evm-adapters/testdata/CheatCodes.sol b/evm-adapters/testdata/CheatCodes.sol deleted file mode 100644 index 32308e4efc4d..000000000000 --- a/evm-adapters/testdata/CheatCodes.sol +++ /dev/null @@ -1,868 +0,0 @@ -// Taken from: -// https://github.com/dapphub/dapptools/blob/e41b6cd9119bbd494aba1236838b859f2136696b/src/dapp-tests/pass/cheatCodes.sol -pragma solidity ^0.8.10; -pragma experimental ABIEncoderV2; - -import "./DsTest.sol"; - -interface Hevm { - // Set block.timestamp (newTimestamp) - function warp(uint256) external; - // Set block.height (newHeight) - function roll(uint256) external; - // Set block.basefee (newBasefee) - function fee(uint256) external; - // Loads a storage slot from an address (who, slot) - function load(address,bytes32) external returns (bytes32); - // Stores a value to an address' storage slot, (who, slot, value) - function store(address,bytes32,bytes32) external; - // Signs data, (privateKey, digest) => (v, r, s) - function sign(uint256,bytes32) external returns (uint8,bytes32,bytes32); - // Gets address for a given private key, (privateKey) => (address) - function addr(uint256) external returns (address); - // Performs a foreign function call via terminal, (stringInputs) => (result) - function ffi(string[] calldata) external returns (bytes memory); - // Sets the *next* call's msg.sender to be the input address - function prank(address) external; - // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called - function startPrank(address) external; - // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input - function prank(address,address) external; - // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input - function startPrank(address,address) external; - // Resets subsequent calls' msg.sender to be `address(this)` - function stopPrank() external; - // Sets an address' balance, (who, newBalance) - function deal(address, uint256) external; - // Sets an address' code, (who, newCode) - function etch(address, bytes calldata) external; - // Expects an error on next call - function expectRevert(bytes calldata) external; - function expectRevert(bytes4) external; - // Record all storage reads and writes - function record() external; - // Gets all accessed reads and write slot from a recording session, for a given address - function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes); - // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). - // Call this function, then emit an event, then call a function. Internally after the call, we check if - // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) - function expectEmit(bool,bool,bool,bool) external; - // Mocks a call to an address, returning specified data. - // Calldata can either be strict or a partial match, e.g. if you only - // pass a Solidity selector to the expected calldata, then the entire Solidity - // function will be mocked. - function mockCall(address,bytes calldata,bytes calldata) external; - // Clears all mocked calls - function clearMockedCalls() external; - // Expect a call to an address with the specified calldata. - // Calldata can either be strict or a partial match - function expectCall(address,bytes calldata) external; - // Gets the code from an artifact file. Takes in the relative path to the json file - function getCode(string calldata) external returns (bytes memory); - // Labels an address in call traces - function label(address, string calldata) external; - // If the condition is false, discard this run's fuzz inputs and generate new ones - function assume(bool) external; -} - -contract HasStorage { - uint public slot0 = 10; -} - -// We add `assertEq` tests as well to ensure that our test runner checks the -// `failed` variable. -contract CheatCodes is DSTest { - address public store = address(new HasStorage()); - Hevm constant hevm = Hevm(HEVM_ADDRESS); - address public who = hevm.addr(1); - - // Warp - - function testWarp(uint128 jump) public { - uint pre = block.timestamp; - hevm.warp(block.timestamp + jump); - require(block.timestamp == pre + jump, "warp failed"); - } - - function testWarpAssertEq(uint128 jump) public { - uint pre = block.timestamp; - hevm.warp(block.timestamp + jump); - assertEq(block.timestamp, pre + jump); - } - - function testFailWarp(uint128 jump) public { - uint pre = block.timestamp; - hevm.warp(block.timestamp + jump); - require(block.timestamp == pre + jump + 1, "warp failed"); - } - - function testFailWarpAssert(uint128 jump) public { - uint pre = block.timestamp; - hevm.warp(block.timestamp + jump); - assertEq(block.timestamp, pre + jump + 1); - } - - // Fee - - // Sets the basefee - function testFee(uint256 fee) public { - hevm.fee(fee); - require(block.basefee == fee); - } - - // Roll - - // Underscore does not run the fuzz test?! - function testRoll(uint256 jump) public { - uint pre = block.number; - hevm.roll(block.number + jump); - require(block.number == pre + jump, "roll failed"); - require(blockhash(block.number) != 0x0); - } - - function testRollHash() public { - require(blockhash(block.number) == 0x0); - hevm.roll(5); - bytes32 hash = blockhash(5); - require(hash != 0x0); - - hevm.roll(10); - require(blockhash(10) != 0x0); - - // rolling back to 5 maintains the same hash - hevm.roll(5); - require(blockhash(5) == hash); - } - - function testFailRoll(uint32 jump) public { - uint pre = block.number; - hevm.roll(block.number + jump); - assertEq(block.number, pre + jump + 1); - } - - // function prove_warp_symbolic(uint128 jump) public { - // test_warp_concrete(jump); - // } - - - function test_store_load_concrete(uint x) public { - uint ten = uint(hevm.load(store, bytes32(0))); - assertEq(ten, 10); - - hevm.store(store, bytes32(0), bytes32(x)); - uint val = uint(hevm.load(store, bytes32(0))); - assertEq(val, x); - } - - // function prove_store_load_symbolic(uint x) public { - // test_store_load_concrete(x); - // } - - function test_sign_addr_digest(uint248 sk, bytes32 digest) public { - if (sk == 0) return; // invalid key - - (uint8 v, bytes32 r, bytes32 s) = hevm.sign(sk, digest); - address expected = hevm.addr(sk); - address actual = ecrecover(digest, v, r, s); - - assertEq(actual, expected); - } - - function test_sign_addr_message(uint248 sk, bytes memory message) public { - test_sign_addr_digest(sk, keccak256(message)); - } - - function testFail_sign_addr(uint sk, bytes32 digest) public { - uint badKey = sk + 1; - - (uint8 v, bytes32 r, bytes32 s) = hevm.sign(badKey, digest); - address expected = hevm.addr(sk); - address actual = ecrecover(digest, v, r, s); - - assertEq(actual, expected); - } - - function testFail_addr_zero_sk() public { - hevm.addr(0); - } - - function test_addr() public { - uint sk = 77814517325470205911140941194401928579557062014761831930645393041380819009408; - address expected = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; - - assertEq(hevm.addr(sk), expected); - } - - function testFFI() public { - string[] memory inputs = new string[](3); - inputs[0] = "echo"; - inputs[1] = "-n"; - inputs[2] = "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046163616200000000000000000000000000000000000000000000000000000000"; - - bytes memory res = hevm.ffi(inputs); - (string memory output) = abi.decode(res, (string)); - assertEq(output, "acab"); - } - - function testDeal() public { - address addr = address(1337); - hevm.deal(addr, 1337); - assertEq(addr.balance, 1337); - } - - function testPrank() public { - Prank prank = new Prank(); - address new_sender = address(1337); - address sender = msg.sender; - hevm.prank(new_sender); - prank.bar(new_sender); - prank.bar(address(this)); - } - - function testPrankConstructor() public { - address new_sender = address(1337); - hevm.prank(new_sender); - PrankConstructor prank2 = new PrankConstructor(address(1337)); - PrankConstructor prank3 = new PrankConstructor(address(this)); - } - - function testPrankStart() public { - Prank prank = new Prank(); - address new_sender = address(1337); - address sender = msg.sender; - hevm.startPrank(new_sender); - prank.bar(new_sender); - prank.bar(new_sender); - hevm.stopPrank(); - prank.bar(address(this)); - } - - function testPrankPayable() public { - Prank prank = new Prank(); - uint256 ownerBalance = address(this).balance; - - address new_sender = address(1337); - hevm.deal(new_sender, 10 ether); - - hevm.prank(new_sender); - prank.payableBar{value: 1 ether}(new_sender); - assertEq(new_sender.balance, 9 ether); - - hevm.startPrank(new_sender); - prank.payableBar{value: 1 ether}(new_sender); - hevm.stopPrank(); - assertEq(new_sender.balance, 8 ether); - - assertEq(ownerBalance, address(this).balance); - } - - function testPrankStartComplex() public { - // A -> B, B starts pranking, doesnt call stopPrank, A calls C calls D - // C -> D would be pranked - ComplexPrank complexPrank = new ComplexPrank(); - Prank prank = new Prank(); - complexPrank.uncompletedPrank(); - prank.bar(address(this)); - complexPrank.completePrank(prank); - } - - function testPrankDual() public { - Prank prank = new Prank(); - address new_sender = address(1337); - address sender = msg.sender; - hevm.prank(new_sender, new_sender); - prank.baz(new_sender, new_sender); - prank.baz(address(this), tx.origin); - } - - function testPrankConstructorDual() public { - address new_sender = address(1337); - hevm.prank(new_sender, new_sender); - PrankConstructorDual prank2 = new PrankConstructorDual(address(1337), address(1337)); - PrankConstructorDual prank3 = new PrankConstructorDual(address(this), tx.origin); - } - - function testPrankStartDual() public { - Prank prank = new Prank(); - address new_sender = address(1337); - address sender = msg.sender; - hevm.startPrank(new_sender, new_sender); - prank.baz(new_sender, new_sender); - prank.baz(new_sender, new_sender); - hevm.stopPrank(); - prank.baz(address(this), tx.origin); - } - - function testPrankStartComplexDual() public { - // A -> B, B starts pranking, doesnt call stopPrank, A calls C calls D - // C -> D would be pranked - ComplexPrank complexPrank = new ComplexPrank(); - Prank prank = new Prank(); - complexPrank.uncompletedPrankDual(); - prank.baz(address(this), tx.origin); - complexPrank.completePrankDual(prank); - } - - function testEtch() public { - address rewriteCode = address(1337); - - bytes memory newCode = hex"1337"; - hevm.etch(rewriteCode, newCode); - bytes memory n_code = getCode(rewriteCode); - assertEq(string(newCode), string(n_code)); - } - - function testExpectRevert() public { - ExpectRevert target = new ExpectRevert(); - hevm.expectRevert("Value too large"); - target.stringErr(101); - target.stringErr(99); - } - - function testExpectRevertConstructor() public { - hevm.expectRevert("Value too large Constructor"); - ExpectRevertConstructor target = new ExpectRevertConstructor(101); - ExpectRevertConstructor target2 = new ExpectRevertConstructor(99); - } - - function testExpectRevertBuiltin() public { - ExpectRevert target = new ExpectRevert(); - hevm.expectRevert(abi.encodeWithSignature("Panic(uint256)", 0x11)); - target.arithmeticErr(101); - } - - function testExpectCustomRevert() public { - ExpectRevert target = new ExpectRevert(); - bytes memory data = abi.encodePacked(bytes4(keccak256("InputTooLarge()"))); - hevm.expectRevert(data); - target.customErr(101); - target.customErr(99); - } - - function testCalleeExpectRevert() public { - ExpectRevert target = new ExpectRevert(); - hevm.expectRevert("Value too largeCallee"); - target.stringErrCall(101); - target.stringErrCall(99); - } - - function testFailExpectRevert() public { - ExpectRevert target = new ExpectRevert(); - hevm.expectRevert("Value too large"); - target.stringErr2(101); - } - - function testFailExpectRevert2() public { - ExpectRevert target = new ExpectRevert(); - hevm.expectRevert("Value too large"); - target.stringErr(99); - } - - function testRecordAccess() public { - RecordAccess target = new RecordAccess(); - hevm.record(); - RecordAccess2 target2 = target.record(); - (bytes32[] memory reads, bytes32[] memory writes) = hevm.accesses(address(target)); - (bytes32[] memory reads2, bytes32[] memory writes2) = hevm.accesses(address(target2)); - assertEq(reads.length, 2); // sstore has to do an sload to grab the original storage, so we effectively have 2 sloads - assertEq(writes.length, 1); - assertEq(reads[0], bytes32(uint256(1))); - assertEq(writes[0], bytes32(uint256(1))); - assertEq(reads2.length, 2); // sstore has to do an sload to grab the original storage, so we effectively have 2 sloads - assertEq(writes2.length, 1); - assertEq(reads2[0], bytes32(uint256(2))); - assertEq(writes2[0], bytes32(uint256(2))); - } - - event Transfer(address indexed from,address indexed to, uint256 amount); - function testExpectEmit() public { - ExpectEmit emitter = new ExpectEmit(); - // check topic 1, topic 2, and data are the same as the following emitted event - hevm.expectEmit(true,true,false,true); - emit Transfer(address(this), address(1337), 1337); - emitter.t(); - } - - function testFailDanglingExpectEmit() public { - ExpectEmit emitter = new ExpectEmit(); - // check topic 1, topic 2, and data are the same as the following emitted event - hevm.expectEmit(true,true,false,true); - emit Transfer(address(this), address(1337), 1337); - } - - function testExpectEmitMultiple() public { - ExpectEmit emitter = new ExpectEmit(); - hevm.expectEmit(true,true,false,true); - emit Transfer(address(this), address(1337), 1337); - hevm.expectEmit(true,true,false,true); - emit Transfer(address(this), address(1337), 1337); - emitter.t3(); - } - - function testExpectEmit2() public { - ExpectEmit emitter = new ExpectEmit(); - hevm.expectEmit(true,false,false,true); - emit Transfer(address(this), address(1338), 1337); - emitter.t(); - } - - function testExpectEmit3() public { - ExpectEmit emitter = new ExpectEmit(); - hevm.expectEmit(false,false,false,true); - emit Transfer(address(1338), address(1338), 1337); - emitter.t(); - } - - function testExpectEmit4() public { - ExpectEmit emitter = new ExpectEmit(); - hevm.expectEmit(true,true,true,false); - emit Transfer(address(this), address(1337), 1338); - emitter.t(); - } - - function testExpectEmit5() public { - ExpectEmit emitter = new ExpectEmit(); - hevm.expectEmit(true,true,true,false); - emit Transfer(address(this), address(1337), 1338); - emitter.t2(); - } - - function testFailExpectEmit() public { - ExpectEmit emitter = new ExpectEmit(); - hevm.expectEmit(true,true,false,true); - emit Transfer(address(this), address(1338), 1337); - emitter.t(); - } - - // Test should fail because the data is different - function testFailExpectEmitWithCall1() public { - ExpectEmit emitter = new ExpectEmit(); - hevm.deal(address(this), 1 ether); - hevm.expectEmit(true,true,false,true); - emit Transfer(address(this), address(1338), 1 gwei); - emitter.t4(payable(address(1337)), 100 gwei); - } - - - // Test should fail because, t5 doesn't emit - function testFailExpectEmitWithCall2() public { - ExpectEmit emitter = new ExpectEmit(); - hevm.deal(address(this), 1 ether); - hevm.expectEmit(true,true,false,true); - emit Transfer(address(this), address(1338), 100 gwei); - emitter.t5(payable(address(1337)), 100 gwei); - } - - // Test should fail if nothing is called - // after expectRevert - function testFailExpectRevert3() public { - hevm.expectRevert("revert"); - } - - function testMockArbitraryCall() public { - hevm.mockCall(address(0xbeef), abi.encode("wowee"), abi.encode("epic")); - (bool ok, bytes memory ret) = address(0xbeef).call(abi.encode("wowee")); - assertTrue(ok); - assertEq(abi.decode(ret, (string)), "epic"); - } - - function testMockContract() public { - MockMe target = new MockMe(); - - // pre-mock - assertEq(target.numberA(), 1); - assertEq(target.numberB(), 2); - - hevm.mockCall( - address(target), - abi.encodeWithSelector(target.numberB.selector), - abi.encode(10) - ); - - // post-mock - assertEq(target.numberA(), 1); - assertEq(target.numberB(), 10); - } - - function testMockInner() public { - MockMe inner = new MockMe(); - MockInner target = new MockInner(address(inner)); - - // pre-mock - assertEq(target.sum(), 3); - - hevm.mockCall( - address(inner), - abi.encodeWithSelector(inner.numberB.selector), - abi.encode(9) - ); - - // post-mock - assertEq(target.sum(), 10); - } - - function testMockSelector() public { - MockMe target = new MockMe(); - assertEq(target.add(5, 5), 10); - - hevm.mockCall( - address(target), - abi.encodeWithSelector(target.add.selector), - abi.encode(11) - ); - - assertEq(target.add(5, 5), 11); - } - - function testMockCalldata() public { - MockMe target = new MockMe(); - assertEq(target.add(5, 5), 10); - assertEq(target.add(6, 4), 10); - - hevm.mockCall( - address(target), - abi.encodeWithSelector(target.add.selector, 5, 5), - abi.encode(11) - ); - - assertEq(target.add(5, 5), 11); - assertEq(target.add(6, 4), 10); - } - - function testClearMockedCalls() public { - MockMe target = new MockMe(); - - hevm.mockCall( - address(target), - abi.encodeWithSelector(target.numberB.selector), - abi.encode(10) - ); - - assertEq(target.numberA(), 1); - assertEq(target.numberB(), 10); - - hevm.clearMockedCalls(); - - assertEq(target.numberA(), 1); - assertEq(target.numberB(), 2); - } - - function testExpectCallWithData() public { - MockMe target = new MockMe(); - hevm.expectCall( - address(target), - abi.encodeWithSelector(target.add.selector, 1, 2) - ); - target.add(1, 2); - } - - function testFailExpectCallWithData() public { - MockMe target = new MockMe(); - hevm.expectCall( - address(target), - abi.encodeWithSelector(target.add.selector, 1, 2) - ); - target.add(3, 3); - } - - function testExpectInnerCall() public { - MockMe inner = new MockMe(); - MockInner target = new MockInner(address(inner)); - - hevm.expectCall( - address(inner), - abi.encodeWithSelector(inner.numberB.selector) - ); - target.sum(); - } - - function testFailExpectInnerCall() public { - MockMe inner = new MockMe(); - MockInner target = new MockInner(address(inner)); - - hevm.expectCall( - address(inner), - abi.encodeWithSelector(inner.numberB.selector) - ); - - // this function does not call inner - target.hello(); - } - - function testExpectSelectorCall() public { - MockMe target = new MockMe(); - hevm.expectCall( - address(target), - abi.encodeWithSelector(target.add.selector) - ); - target.add(5, 5); - } - - function testFailExpectSelectorCall() public { - MockMe target = new MockMe(); - hevm.expectCall( - address(target), - abi.encodeWithSelector(target.add.selector) - ); - } - - function testFailExpectCallWithMoreParameters() public { - MockMe target = new MockMe(); - hevm.expectCall( - address(target), - abi.encodeWithSelector(target.add.selector, 3, 3, 3) - ); - target.add(3, 3); - } - - function testGetCode() public { - bytes memory contractCode = hevm.getCode("./testdata/Contract.json"); - assertEq( - string(contractCode), - string(bytes(hex"608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80637ddeef2414602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60006007905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056fea2646970667358221220521a806ba8927fda1a9b7bf0458b0a0abf456e4611953e01489bee91783418b064736f6c634300080a0033")) - ); - } - - function testLabel() public { - address bob = address(1337); - hevm.label(bob, "bob"); - bob.call{value: 100}(""); - } - - function testLabelInputReturn() public { - Label labeled = new Label(); - hevm.label(address(labeled), "MyCustomLabel"); - labeled.withInput(address(labeled)); - } - - function getCode(address who) internal returns (bytes memory o_code) { - assembly { - // retrieve the size of the code, this needs assembly - let size := extcodesize(who) - // allocate output byte array - this could also be done without assembly - // by using o_code = new bytes(size) - o_code := mload(0x40) - // new "memory end" including padding - mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) - // store length in memory - mstore(o_code, size) - // actually retrieve the code, this needs assembly - extcodecopy(who, add(o_code, 0x20), 0, size) - } - } -} - -contract Label { - function withInput(address labeled) public pure returns (address) { - return labeled; - } -} - -contract RecordAccess { - function record() public returns (RecordAccess2) { - assembly { - sstore(1, add(sload(1), 1)) - } - RecordAccess2 target2 = new RecordAccess2(); - target2.record(); - return target2; - } -} - -contract RecordAccess2 { - function record() public { - assembly { - sstore(2, add(sload(2), 1)) - } - } -} - -error InputTooLarge(); -contract ExpectRevert { - function stringErrCall(uint256 a) public returns (uint256) { - ExpectRevertCallee callee = new ExpectRevertCallee(); - uint256 amount = callee.stringErr(a); - return amount; - } - - function stringErr(uint256 a) public returns (uint256) { - require(a < 100, "Value too large"); - return a; - } - - function arithmeticErr(uint256 a) public returns (uint256) { - uint256 b = 100 - a; - return b; - } - - function stringErr2(uint256 a) public returns (uint256) { - require(a < 100, "Value too large2"); - return a; - } - - function customErr(uint256 a) public returns (uint256) { - if (a > 99) { - revert InputTooLarge(); - } - return a; - } -} - -contract ExpectRevertConstructor { - constructor(uint256 a) { - require(a < 100, "Value too large Constructor"); - } - - function a() public returns(uint256) { - return 1; - } -} - -contract ExpectRevertCallee { - function stringErr(uint256 a) public returns (uint256) { - require(a < 100, "Value too largeCallee"); - return a; - } - - function stringErr2(uint256 a) public returns (uint256) { - require(a < 100, "Value too large2Callee"); - return a; - } -} - -contract Prank { - function bar(address expectedMsgSender) public { - require(msg.sender == expectedMsgSender, "bad prank"); - InnerPrank inner = new InnerPrank(); - inner.bar(address(this)); - } - - function baz(address expectedMsgSender, address expectedOrigin) public { - require(msg.sender == expectedMsgSender, "bad prank"); - require(tx.origin == expectedOrigin, "bad prank origin"); - InnerPrank inner = new InnerPrank(); - inner.baz(address(this), expectedOrigin); - } - - function payableBar(address expectedMsgSender) payable public { - bar(expectedMsgSender); - } -} - -contract PrankConstructor { - constructor(address expectedMsgSender) { - require(msg.sender == expectedMsgSender, "bad prank"); - } - - function bar(address expectedMsgSender) public { - require(msg.sender == expectedMsgSender, "bad prank"); - InnerPrank inner = new InnerPrank(); - inner.bar(address(this)); - } -} - -contract PrankConstructorDual { - constructor(address expectedMsgSender, address expectedOrigin) { - require(msg.sender == expectedMsgSender, "bad prank"); - require(tx.origin == expectedOrigin, "bad prank origin"); - } - - function baz(address expectedMsgSender, address expectedOrigin) public { - require(msg.sender == expectedMsgSender, "bad prank"); - require(tx.origin == expectedOrigin, "bad prank origin"); - InnerPrank inner = new InnerPrank(); - inner.baz(address(this), expectedOrigin); - } -} - -contract InnerPrank { - function bar(address expectedMsgSender) public { - require(msg.sender == expectedMsgSender, "bad prank"); - } - - function baz(address expectedMsgSender, address expectedOrigin) public { - require(msg.sender == expectedMsgSender, "bad prank"); - require(tx.origin == expectedOrigin, "bad prank origin"); - } -} - -contract ComplexPrank { - Hevm hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - function uncompletedPrank() public { - hevm.startPrank(address(1337)); - } - - function uncompletedPrankDual() public { - hevm.startPrank(address(1337), address(1337)); - } - - function completePrank(Prank prank) public { - prank.bar(address(1337)); - hevm.stopPrank(); - prank.bar(address(this)); - } - - function completePrankDual(Prank prank) public { - prank.baz(address(1337), address(1337)); - hevm.stopPrank(); - prank.baz(address(this), tx.origin); - } -} - -contract ExpectEmit { - event Transfer(address indexed from,address indexed to, uint256 amount); - event Transfer2(address indexed from,address indexed to, uint256 amount); - function t() public { - emit Transfer(msg.sender, address(1337), 1337); - } - - function t2() public { - emit Transfer2(msg.sender, address(1337), 1337); - emit Transfer(msg.sender, address(1337), 1337); - } - - function t3() public { - emit Transfer(msg.sender, address(1337), 1337); - emit Transfer(msg.sender, address(1337), 1337); - } - - function t4(address payable to, uint256 amount) public { - (bool success, ) = to.call{value: amount, gas: 30_000}(new bytes(0)); - emit Transfer(msg.sender, address(1337), 100 gwei); - } - - function t5(address payable to, uint256 amount) public { - (bool success, ) = to.call{value: amount, gas: 30_000}(new bytes(0)); - } -} - -contract MockMe { - function numberA() public returns (uint256) { - return 1; - } - - function numberB() public returns (uint256) { - return 2; - } - - function add(uint256 a, uint256 b) public returns (uint256) { - return a + b; - } -} - -contract MockInner { - MockMe private inner; - - constructor(address _inner) { - inner = MockMe(_inner); - } - - function sum() public returns (uint256) { - return inner.numberA() + inner.numberB(); - } - - function hello() public returns (string memory) { - return "hi"; - } -} diff --git a/evm-adapters/testdata/ConsoleLogs.sol b/evm-adapters/testdata/ConsoleLogs.sol deleted file mode 100644 index f9fe140a0c9d..000000000000 --- a/evm-adapters/testdata/ConsoleLogs.sol +++ /dev/null @@ -1,59 +0,0 @@ -pragma solidity ^0.8.0; - -import "./console.sol"; - -contract ConsoleLogs { - function test_log() public { - console.log(0x1111111111111111111111111111111111111111); - console.log("Hi"); - console.log("Hi", "Hi"); - console.log(1337); - console.log(1337, 1245); - console.log("Hi", 1337); - } - - function test_log_types() public { - console.logString("String"); - console.logInt(1337); - console.logInt(-20); - console.logUint(1245); - console.logBool(true); - console.logAddress(address(0x1111111111111111111111111111111111111111)); - } - - function test_log_types_bytes() public { - console.logBytes("logBytes"); - console.logBytes(hex"fba3a4b5"); - console.logBytes1(hex"fb"); - console.logBytes2(hex"fba3"); - console.logBytes3(hex"fba3a4"); - console.logBytes4(hex"fba3a4b5"); - console.logBytes5(hex"fba3a4b5"); - console.logBytes6(hex"fba3a4b5"); - console.logBytes7(hex"fba3a4b5"); - console.logBytes8(hex"fba3a4b5"); - console.logBytes9(hex"fba3a4b5"); - console.logBytes10(hex"fba3a4b5"); - console.logBytes11(hex"fba3a4b5"); - console.logBytes12(hex"fba3a4b5"); - console.logBytes13(hex"fba3a4b5"); - console.logBytes14(hex"fba3a4b5"); - console.logBytes15(hex"fba3a4b5"); - console.logBytes16(hex"fba3a4b5"); - console.logBytes17(hex"fba3a4b5"); - console.logBytes18(hex"fba3a4b5"); - console.logBytes19(hex"fba3a4b5"); - console.logBytes20(hex"fba3a4b5"); - console.logBytes21(hex"fba3a4b5"); - console.logBytes22(hex"fba3a4b5"); - console.logBytes23(hex"fba3a4b5"); - console.logBytes24(hex"fba3a4b5"); - console.logBytes25(hex"fba3a4b5"); - console.logBytes26(hex"fba3a4b5"); - console.logBytes27(hex"fba3a4b5"); - console.logBytes28(hex"fba3a4b5"); - console.logBytes29(hex"fba3a4b5"); - console.logBytes30(hex"fba3a4b5"); - console.logBytes31(hex"fba3a4b5"); - console.logBytes32(hex"fba3a4b5"); - }} diff --git a/evm-adapters/testdata/Contract.json b/evm-adapters/testdata/Contract.json deleted file mode 100644 index 31903662419f..000000000000 --- a/evm-adapters/testdata/Contract.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "abi": [ - { - "type": "function", - "name": "someFunc", - "inputs": [], - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "constant": false, - "stateMutability": "pure" - } - ], - "bytecode": { - "object": "0x608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80637ddeef2414602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60006007905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056fea2646970667358221220521a806ba8927fda1a9b7bf0458b0a0abf456e4611953e01489bee91783418b064736f6c634300080a0033", - "sourceMap": "24597:616:0:-:0;;;24625:60;;;-1:-1:-1;;;;;;24625:60:0;24642:42;24625:60;;;24597:616;;;;;;;;;;;;;;;;", - "linkReferences": {} - }, - "deployed_bytecode": { - "object": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c80637ddeef2414602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60006007905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056fea2646970667358221220521a806ba8927fda1a9b7bf0458b0a0abf456e4611953e01489bee91783418b064736f6c634300080a0033", - "sourceMap": "24597:616:0:-:0;;;24625:60;;;-1:-1:-1;;;;;;24625:60:0;24642:42;24625:60;;;24597:616;;;;;;;;;;;;;;;;", - "linkReferences": {} - } -} \ No newline at end of file diff --git a/evm-adapters/testdata/DebugLogs.sol b/evm-adapters/testdata/DebugLogs.sol deleted file mode 100644 index b9e2e92dc06d..000000000000 --- a/evm-adapters/testdata/DebugLogs.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.8.0; - -import "./DsTest.sol"; - -contract DebugLogs is DSTest { - function test_log() public { - emit log("Hi"); - emit logs(hex"1234"); - emit log_address(0x1111111111111111111111111111111111111111); - emit log_bytes32(keccak256(abi.encodePacked("foo"))); - emit log_int(123); - emit log_uint(1234); - emit log_bytes(hex"4567"); - emit log_string("lol"); - emit log_named_address("addr", 0x2222222222222222222222222222222222222222); - emit log_named_bytes32("key", keccak256(abi.encodePacked("foo"))); - emit log_named_decimal_int("key", 123, 18); - emit log_named_decimal_int("key", -123, 18); - emit log_named_decimal_int("key", 1.0e18, 18); - emit log_named_decimal_int("key", -1.0e18, 18); - emit log_named_decimal_int("key", -123, 12); - emit log_named_decimal_int("key", -1.0e18, 12); - emit log_named_decimal_uint("key", 1234, 18); - emit log_named_decimal_uint("key", 1.0e18, 18); - emit log_named_decimal_uint("key", 1234, 12); - emit log_named_decimal_uint("key", 1.0e18, 12); - emit log_named_int("key", 123); - emit log_named_uint("key", 1234); - emit log_named_bytes("key", hex"4567"); - emit log_named_string("key", "lol"); - } - - function test_log_elsewhere() public { - OtherContract otherContract = new OtherContract(); - otherContract.test_log(); - } -} - -contract OtherContract is DSTest { - function test_log() public { - emit log_address(0x1111111111111111111111111111111111111111); - emit log("Hi"); - } -} diff --git a/evm-adapters/testdata/Fuzz.sol b/evm-adapters/testdata/Fuzz.sol deleted file mode 100644 index e5552b4a4159..000000000000 --- a/evm-adapters/testdata/Fuzz.sol +++ /dev/null @@ -1,7 +0,0 @@ -pragma solidity ^0.8.10; - -contract FuzzTests { - function testFuzzedRevert(uint256 x) public { - require(x == 5, "fuzztest-revert"); - } -} diff --git a/evm-adapters/testdata/GreetTest.sol b/evm-adapters/testdata/GreetTest.sol deleted file mode 100644 index 54955990d186..000000000000 --- a/evm-adapters/testdata/GreetTest.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.7.6; - -contract Greeter { - string public greeting; - - function greet(string memory _greeting) public { - greeting = _greeting; - } - - function time() public view returns (uint256) { - return block.timestamp; - } - - function gm() public { - greeting = "gm"; - } -} - -contract GreeterTestSetup { - Greeter greeter; - - function greeting() public view returns (string memory) { - return greeter.greeting(); - } - - function setUp() public { - greeter = new Greeter(); - } -} - -interface HEVM { - function warp(uint256 time) external; -} - -address constant HEVM_ADDRESS = - address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); - -contract GreeterTest is GreeterTestSetup { - HEVM constant hevm = HEVM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - function greet(string memory _greeting) public { - greeter.greet(_greeting); - } - - function testHevmTime() public { - uint256 val = 100; - hevm.warp(100); - uint256 timestamp = greeter.time(); - require(timestamp == val); - } - - // check the positive case - function testGreeting() public { - greeter.greet("yo"); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked("yo")), "not equal"); - } - - // check the unhappy case - function testFailGreeting() public { - greeter.greet("yo"); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked("hi")), "not equal to `hi`"); - } - - function testIsolation() public { - require(bytes(greeter.greeting()).length == 0); - } -} - -contract GmTest is GreeterTestSetup { - function testGm() public { - greeter.gm(); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked("gm")), "not equal"); - } -} diff --git a/evm-adapters/testdata/LargeContract.sol b/evm-adapters/testdata/LargeContract.sol deleted file mode 100644 index d07455e76d88..000000000000 --- a/evm-adapters/testdata/LargeContract.sol +++ /dev/null @@ -1,6 +0,0 @@ -pragma solidity >=0.4.0; - -contract LargeContract { - string public foo = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - -} diff --git a/evm-adapters/testdata/TestAssume.sol b/evm-adapters/testdata/TestAssume.sol deleted file mode 100644 index 65845a89bd1d..000000000000 --- a/evm-adapters/testdata/TestAssume.sol +++ /dev/null @@ -1,19 +0,0 @@ -pragma solidity 0.8.0; - -import "../../evm-adapters/testdata/DsTest.sol"; - -interface HEVM { - function assume(bool condition) external; -} - -address constant HEVM_ADDRESS = - address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); - - -contract TestAssume is DSTest { - HEVM constant hevm = HEVM(HEVM_ADDRESS); - function testAssume(uint8 x) public { - hevm.assume(x < 2**7); - assertTrue(x < 2**7); - } -} diff --git a/evm-adapters/testdata/Trace.sol b/evm-adapters/testdata/Trace.sol deleted file mode 100644 index 3d9b98d13f00..000000000000 --- a/evm-adapters/testdata/Trace.sol +++ /dev/null @@ -1,75 +0,0 @@ -pragma solidity ^0.8.0; - - -interface RecursiveCallee { - function recurseCall(uint256 neededDepth, uint256 depth) external returns (uint256); - function recurseCreate(uint256 neededDepth, uint256 depth) external returns (uint256); - function someCall() external; - function negativeNum() external returns (int256); -} - -contract RecursiveCall { - event Depth(uint256 depth); - event ChildDepth(uint256 childDepth); - event CreatedChild(uint256 childDepth); - Trace factory; - - constructor(address _factory) { - factory = Trace(_factory); - } - - function recurseCall(uint256 neededDepth, uint256 depth) public returns (uint256) { - if (depth == neededDepth) { - RecursiveCallee(address(this)).negativeNum(); - return neededDepth; - } - uint256 childDepth = RecursiveCallee(address(this)).recurseCall(neededDepth, depth + 1); - emit ChildDepth(childDepth); - RecursiveCallee(address(this)).someCall(); - emit Depth(depth); - return depth; - } - - function recurseCreate(uint256 neededDepth, uint256 depth) public returns (uint256) { - if (depth == neededDepth) { - return neededDepth; - } - RecursiveCall child = factory.create(); - emit CreatedChild(depth + 1); - uint256 childDepth = child.recurseCreate(neededDepth, depth + 1); - emit Depth(depth); - return depth; - } - - function someCall() public {} - - function negativeNum() public returns (int256) { - return -1000000000; - } -} - -contract Trace { - RecursiveCall first; - - function create() public returns (RecursiveCall) { - if (address(first) == address(0)) { - first = new RecursiveCall(address(this)); - return first; - } - return new RecursiveCall(address(this)); - } - - function recurseCall(uint256 neededDepth, uint256 depth) public returns (uint256) { - if (address(first) == address(0)) { - first = new RecursiveCall(address(this)); - } - return first.recurseCall(neededDepth, depth); - } - - function recurseCreate(uint256 neededDepth, uint256 depth) public returns (uint256) { - if (address(first) == address(0)) { - first = new RecursiveCall(address(this)); - } - return first.recurseCreate(neededDepth, depth); - } -} \ No newline at end of file diff --git a/evm-adapters/testdata/console.sol b/evm-adapters/testdata/console.sol deleted file mode 100644 index f6c518c98779..000000000000 --- a/evm-adapters/testdata/console.sol +++ /dev/null @@ -1,1532 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.22 <0.9.0; - -library console { - address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); - - function _sendLogPayload(bytes memory payload) private view { - uint256 payloadLength = payload.length; - address consoleAddress = CONSOLE_ADDRESS; - assembly { - let payloadStart := add(payload, 32) - let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) - } - } - - function log() internal view { - _sendLogPayload(abi.encodeWithSignature("log()")); - } - - function logInt(int p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); - } - - function logUint(uint p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); - } - - function logString(string memory p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); - } - - function logBool(bool p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); - } - - function logAddress(address p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); - } - - function logBytes(bytes memory p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); - } - - function logBytes1(bytes1 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); - } - - function logBytes2(bytes2 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); - } - - function logBytes3(bytes3 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); - } - - function logBytes4(bytes4 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); - } - - function logBytes5(bytes5 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); - } - - function logBytes6(bytes6 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); - } - - function logBytes7(bytes7 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); - } - - function logBytes8(bytes8 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); - } - - function logBytes9(bytes9 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); - } - - function logBytes10(bytes10 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); - } - - function logBytes11(bytes11 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); - } - - function logBytes12(bytes12 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); - } - - function logBytes13(bytes13 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); - } - - function logBytes14(bytes14 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); - } - - function logBytes15(bytes15 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); - } - - function logBytes16(bytes16 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); - } - - function logBytes17(bytes17 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); - } - - function logBytes18(bytes18 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); - } - - function logBytes19(bytes19 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); - } - - function logBytes20(bytes20 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); - } - - function logBytes21(bytes21 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); - } - - function logBytes22(bytes22 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); - } - - function logBytes23(bytes23 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); - } - - function logBytes24(bytes24 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); - } - - function logBytes25(bytes25 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); - } - - function logBytes26(bytes26 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); - } - - function logBytes27(bytes27 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); - } - - function logBytes28(bytes28 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); - } - - function logBytes29(bytes29 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); - } - - function logBytes30(bytes30 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); - } - - function logBytes31(bytes31 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); - } - - function logBytes32(bytes32 p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); - } - - function log(uint p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); - } - - function log(string memory p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); - } - - function log(bool p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); - } - - function log(address p0) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); - } - - function log(uint p0, uint p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); - } - - function log(uint p0, string memory p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); - } - - function log(uint p0, bool p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); - } - - function log(uint p0, address p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); - } - - function log(string memory p0, uint p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); - } - - function log(string memory p0, string memory p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); - } - - function log(string memory p0, bool p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); - } - - function log(string memory p0, address p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); - } - - function log(bool p0, uint p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); - } - - function log(bool p0, string memory p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); - } - - function log(bool p0, bool p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); - } - - function log(bool p0, address p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); - } - - function log(address p0, uint p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); - } - - function log(address p0, string memory p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); - } - - function log(address p0, bool p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); - } - - function log(address p0, address p1) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); - } - - function log(uint p0, uint p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); - } - - function log(uint p0, uint p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); - } - - function log(uint p0, uint p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); - } - - function log(uint p0, uint p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); - } - - function log(uint p0, string memory p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); - } - - function log(uint p0, string memory p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); - } - - function log(uint p0, string memory p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); - } - - function log(uint p0, string memory p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); - } - - function log(uint p0, bool p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); - } - - function log(uint p0, bool p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); - } - - function log(uint p0, bool p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); - } - - function log(uint p0, bool p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); - } - - function log(uint p0, address p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); - } - - function log(uint p0, address p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); - } - - function log(uint p0, address p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); - } - - function log(uint p0, address p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); - } - - function log(string memory p0, uint p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); - } - - function log(string memory p0, uint p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); - } - - function log(string memory p0, uint p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); - } - - function log(string memory p0, uint p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); - } - - function log(string memory p0, string memory p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); - } - - function log(string memory p0, string memory p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); - } - - function log(string memory p0, string memory p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); - } - - function log(string memory p0, string memory p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); - } - - function log(string memory p0, bool p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); - } - - function log(string memory p0, bool p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); - } - - function log(string memory p0, bool p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); - } - - function log(string memory p0, bool p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); - } - - function log(string memory p0, address p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); - } - - function log(string memory p0, address p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); - } - - function log(string memory p0, address p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); - } - - function log(string memory p0, address p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); - } - - function log(bool p0, uint p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); - } - - function log(bool p0, uint p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); - } - - function log(bool p0, uint p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); - } - - function log(bool p0, uint p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); - } - - function log(bool p0, string memory p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); - } - - function log(bool p0, string memory p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); - } - - function log(bool p0, string memory p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); - } - - function log(bool p0, string memory p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); - } - - function log(bool p0, bool p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); - } - - function log(bool p0, bool p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); - } - - function log(bool p0, bool p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); - } - - function log(bool p0, bool p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); - } - - function log(bool p0, address p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); - } - - function log(bool p0, address p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); - } - - function log(bool p0, address p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); - } - - function log(bool p0, address p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); - } - - function log(address p0, uint p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); - } - - function log(address p0, uint p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); - } - - function log(address p0, uint p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); - } - - function log(address p0, uint p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); - } - - function log(address p0, string memory p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); - } - - function log(address p0, string memory p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); - } - - function log(address p0, string memory p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); - } - - function log(address p0, string memory p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); - } - - function log(address p0, bool p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); - } - - function log(address p0, bool p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); - } - - function log(address p0, bool p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); - } - - function log(address p0, bool p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); - } - - function log(address p0, address p1, uint p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); - } - - function log(address p0, address p1, string memory p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); - } - - function log(address p0, address p1, bool p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); - } - - function log(address p0, address p1, address p2) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); - } - - function log(uint p0, uint p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, uint p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, string memory p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, bool p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); - } - - function log(uint p0, address p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, uint p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, string memory p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, bool p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); - } - - function log(string memory p0, address p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, uint p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, string memory p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, bool p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); - } - - function log(bool p0, address p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); - } - - function log(address p0, uint p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); - } - - function log(address p0, string memory p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); - } - - function log(address p0, bool p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, uint p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, uint p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, uint p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, uint p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, string memory p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, string memory p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, string memory p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, string memory p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, bool p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, bool p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, bool p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, bool p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, address p2, uint p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, address p2, string memory p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, address p2, bool p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); - } - - function log(address p0, address p1, address p2, address p3) internal view { - _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); - } - -} diff --git a/evm/Cargo.toml b/evm/Cargo.toml new file mode 100644 index 000000000000..94676aa4c128 --- /dev/null +++ b/evm/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "foundry-evm" +version = "0.2.0" +edition = "2021" + +# TODO: We can probably reduce dependencies here or in the forge crate +[dependencies] +foundry-utils = { path = "./../utils" } + +# Encoding/decoding +serde_json = "1.0.67" +serde = "1.0.130" +hex = "0.4.3" +ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full"] } + +# Error handling +eyre = "0.6.5" +thiserror = "1.0.29" + +# Logging +tracing = "0.1.26" +tracing-subscriber = "0.3" +tracing-error = "0.2.0" + +# Threading/futures +tokio = { version = "1.10.1" } +parking_lot = "0.12.0" +futures = "0.3.21" +once_cell = "1.9.0" + +# EVM +bytes = "1.1.0" +hashbrown = "0.12" +revm = { package = "revm", git = "https://github.com/bluealloy/revm", default-features = false, features = ["std", "k256", "with-serde"] } + +# Fuzzer +proptest = "1.0.0" + +# Display +ansi_term = "0.12.1" +url = "2.2.2" + +[dev-dependencies] +tempfile = "3.3.0" diff --git a/evm-adapters/testdata/console.json b/evm/abi/console.json similarity index 100% rename from evm-adapters/testdata/console.json rename to evm/abi/console.json diff --git a/evm/src/debug.rs b/evm/src/debug.rs new file mode 100644 index 000000000000..1dc62d18f547 --- /dev/null +++ b/evm/src/debug.rs @@ -0,0 +1,187 @@ +use crate::abi::HEVM_ABI; +use ethers::types::{Address, U256}; +use revm::{Memory, OpCode}; +use std::fmt::Display; + +/// An arena of [DebugNode]s +#[derive(Default, Debug, Clone)] +pub struct DebugArena { + /// The arena of nodes + pub arena: Vec, +} + +impl DebugArena { + /// Pushes a new debug node into the arena + pub fn push_node(&mut self, mut new_node: DebugNode) -> usize { + fn recursively_push( + arena: &mut Vec, + entry: usize, + mut new_node: DebugNode, + ) -> usize { + match new_node.depth { + // We found the parent node, add the new node as a child + _ if arena[entry].depth == new_node.depth - 1 => { + let id = arena.len(); + new_node.location = arena[entry].children.len(); + new_node.parent = Some(entry); + arena[entry].children.push(id); + arena.push(new_node); + id + } + // We haven't found the parent node, go deeper + _ => { + let child = *arena[entry].children.last().expect("Disconnected debug node"); + recursively_push(arena, child, new_node) + } + } + } + + if self.arena.is_empty() { + // This is the initial node at depth 0, so we just insert it. + self.arena.push(new_node); + 0 + } else if new_node.depth == 0 { + // This is another node at depth 0, for example instructions between calls. We insert + // it as a child of the original root node. + let id = self.arena.len(); + new_node.location = self.arena[0].children.len(); + new_node.parent = Some(0); + self.arena[0].children.push(id); + self.arena.push(new_node); + id + } else { + // We try to find the parent of this node recursively + recursively_push(&mut self.arena, 0, new_node) + } + } + + /// Recursively traverses the tree of debug nodes and flattens it into a [Vec] where each + /// item contains: + /// + /// - The address of the contract being executed + /// - A [Vec] of debug steps along that contract's execution path + /// - A boolean denoting whether this is a contract creation or not + /// + /// This makes it easy to pretty print the execution steps. + pub fn flatten(&self, entry: usize) -> Vec<(Address, Vec, bool)> { + let node = &self.arena[entry]; + + let mut flattened = vec![]; + if !node.steps.is_empty() { + flattened.push((node.address, node.steps.clone(), node.creation)); + } + flattened.extend(node.children.iter().flat_map(|child| self.flatten(*child))); + + flattened + } +} + +/// A node in the arena +#[derive(Default, Debug, Clone)] +pub struct DebugNode { + /// Parent node index in the arena + pub parent: Option, + /// Children node indexes in the arena + pub children: Vec, + /// Location in parent + pub location: usize, + /// Address context + pub address: Address, + /// Depth + pub depth: usize, + /// The debug steps + pub steps: Vec, + /// Whether the contract was created in this node or not + pub creation: bool, +} + +impl DebugNode { + pub fn new(address: Address, depth: usize, steps: Vec) -> Self { + Self { address, depth, steps, ..Default::default() } + } +} + +/// A `DebugStep` is a snapshot of the EVM's runtime state. +/// +/// It holds the current program counter (where in the program you are), +/// the stack and memory (prior to the opcodes execution), any bytes to be +/// pushed onto the stack, and the instruction counter for use with sourcemap. +#[derive(Debug, Clone)] +pub struct DebugStep { + /// The program counter + pub pc: usize, + /// Stack *prior* to running the associated opcode + pub stack: Vec, + /// Memory *prior* to running the associated opcode + pub memory: Memory, + /// Opcode to be executed + pub instruction: Instruction, + /// Optional bytes that are being pushed onto the stack + pub push_bytes: Option>, + /// Instruction counter, used to map this instruction to source code + pub ic: usize, + /// Cumulative gas usage + pub total_gas_used: u64, +} + +impl Default for DebugStep { + fn default() -> Self { + Self { + pc: 0, + stack: vec![], + memory: Memory::new(), + instruction: Instruction::OpCode(revm::opcode::INVALID), + push_bytes: None, + ic: 0, + total_gas_used: 0, + } + } +} + +impl DebugStep { + /// Pretty print the step's opcode + pub fn pretty_opcode(&self) -> String { + if let Some(push_bytes) = &self.push_bytes { + format!("{}(0x{})", self.instruction, hex::encode(push_bytes)) + } else { + self.instruction.to_string() + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum Instruction { + OpCode(u8), + Cheatcode([u8; 4]), +} + +impl From for Instruction { + fn from(op: u8) -> Instruction { + Instruction::OpCode(op) + } +} + +impl Display for Instruction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Instruction::OpCode(op) => write!( + f, + "{}", + OpCode::try_from_u8(*op).map_or_else( + || format!("UNDEFINED(0x{:02x})", op), + |opcode| opcode.as_str().to_string(), + ) + ), + Instruction::Cheatcode(cheat) => write!( + f, + "VM_{}", + &*HEVM_ABI + .functions() + .find(|func| func.short_signature() == *cheat) + .expect("unknown cheatcode found in debugger") + .name + .to_uppercase() + ), + } + } +} diff --git a/evm/src/decode.rs b/evm/src/decode.rs new file mode 100644 index 000000000000..e10fd3f430fb --- /dev/null +++ b/evm/src/decode.rs @@ -0,0 +1,48 @@ +//! Various utilities to decode test results +use crate::abi::ConsoleEvents::{self, *}; +use ethers::{abi::RawLog, contract::EthLogDecode}; + +/// Decode a set of logs, only returning logs from DSTest logging events and Hardhat's `console.log` +pub fn decode_console_logs(logs: &[RawLog]) -> Vec { + logs.iter().filter_map(decode_console_log).collect() +} + +/// Decode a single log. +/// +/// This function returns [None] if it is not a DSTest log or the result of a Hardhat +/// `console.log`. +pub fn decode_console_log(log: &RawLog) -> Option { + let decoded = match ConsoleEvents::decode_log(log).ok()? { + LogsFilter(inner) => format!("{}", inner.0), + LogBytesFilter(inner) => format!("{}", inner.0), + LogNamedAddressFilter(inner) => format!("{}: {:?}", inner.key, inner.val), + LogNamedBytes32Filter(inner) => { + format!("{}: 0x{}", inner.key, hex::encode(inner.val)) + } + LogNamedDecimalIntFilter(inner) => { + let (sign, val) = inner.val.into_sign_and_abs(); + format!( + "{}: {}{}", + inner.key, + sign, + ethers::utils::format_units(val, inner.decimals.as_u32()).unwrap() + ) + } + LogNamedDecimalUintFilter(inner) => { + format!( + "{}: {}", + inner.key, + ethers::utils::format_units(inner.val, inner.decimals.as_u32()).unwrap() + ) + } + LogNamedIntFilter(inner) => format!("{}: {:?}", inner.key, inner.val), + LogNamedUintFilter(inner) => format!("{}: {:?}", inner.key, inner.val), + LogNamedBytesFilter(inner) => { + format!("{}: 0x{}", inner.key, hex::encode(inner.val)) + } + LogNamedStringFilter(inner) => format!("{}: {}", inner.key, inner.val), + + e => e.to_string(), + }; + Some(decoded) +} diff --git a/evm-adapters/src/sputnik/cheatcodes/mod.rs b/evm/src/executor/abi.rs similarity index 92% rename from evm-adapters/src/sputnik/cheatcodes/mod.rs rename to evm/src/executor/abi.rs index 22ad14db43d4..adcc89101679 100644 --- a/evm-adapters/src/sputnik/cheatcodes/mod.rs +++ b/evm/src/executor/abi.rs @@ -1,53 +1,16 @@ -//! Hooks over Sputnik EVM execution which allow runtime logging and modification of chain state -//! from Solidity (cheatcodes). -pub mod memory_stackstate_owned; - -pub mod cheatcode_handler; -use std::collections::HashMap; - -pub use cheatcode_handler::CheatcodeHandler; - -pub mod backend; - -pub mod debugger; - -use ethers::types::{Address, Selector, H256, U256}; +use ethers::types::{Address, Selector, H160}; use once_cell::sync::Lazy; -use sputnik::backend::{Backend, MemoryAccount, MemoryBackend}; - -#[derive(Clone, Debug, Default)] -/// Cheatcodes can be used to control the EVM context during setup or runtime, -/// which can be useful for simulations or specialized unit tests -pub struct Cheatcodes { - /// The overridden block number - pub block_number: Option, - /// The overridden timestamp - pub block_timestamp: Option, - /// The overridden basefee - pub block_base_fee_per_gas: Option, - /// The overridden storage slots - pub accounts: HashMap, - /// The overriden tx.origin - pub origin: Option
, - /// The overridden block hashes, whenever `roll` gets - /// called. - pub block_hashes: HashMap, -} - -/// Extension trait over [`Backend`] which provides additional methods for interacting with the -/// state -pub trait BackendExt: Backend { - fn set_storage(&mut self, address: Address, slot: H256, value: H256); -} +use std::collections::HashMap; -impl<'a> BackendExt for MemoryBackend<'a> { - fn set_storage(&mut self, address: Address, slot: H256, value: H256) { - let account = self.state_mut().entry(address).or_insert_with(Default::default); - let slot = account.storage.entry(slot).or_insert_with(Default::default); - *slot = value; - } -} +/// The cheatcode handler address (0x7109709ECfa91a80626fF3989D68f67F5b1DD12D). +/// +/// This is the same address as the one used in DappTools's HEVM. +pub static CHEATCODE_ADDRESS: Address = H160([ + 0x71, 0x09, 0x70, 0x9E, 0xcf, 0xa9, 0x1a, 0x80, 0x62, 0x6f, 0xf3, 0x98, 0x9d, 0x68, 0xf6, 0x7f, + 0x5b, 0x1d, 0xd1, 0x2d, +]); +// Bindings for cheatcodes ethers::contract::abigen!( HEVM, r#"[ @@ -66,6 +29,7 @@ ethers::contract::abigen!( stopPrank() deal(address,uint256) etch(address,bytes) + expectRevert() expectRevert(bytes) expectRevert(bytes4) record() @@ -81,8 +45,17 @@ ethers::contract::abigen!( ); pub use hevm_mod::{HEVMCalls, HEVM_ABI}; +/// The Hardhat console address (0x000000000000000000636F6e736F6c652e6c6f67). +/// +/// See: https://github.com/nomiclabs/hardhat/blob/master/packages/hardhat-core/console.sol +pub static HARDHAT_CONSOLE_ADDRESS: Address = H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, + 0x2e, 0x6c, 0x6f, 0x67, +]); + +// Bindings for DS-style event logs ethers::contract::abigen!( - HevmConsole, + Console, r#"[ event log(string) event logs (bytes) @@ -100,20 +73,21 @@ ethers::contract::abigen!( event log_named_uint (string key, uint val) event log_named_bytes (string key, bytes val) event log_named_string (string key, string val) - ]"#, + ]"# ); -pub use hevmconsole_mod::HEVMCONSOLE_ABI; +pub use console_mod::{ConsoleEvents, CONSOLE_ABI}; -// Bindings for hardhat console -ethers::contract::abigen!(Console, "./testdata/console.json",); -pub use console_mod::CONSOLE_ABI; +// Bindings for Hardhat console +ethers::contract::abigen!(HardhatConsole, "./abi/console.json",); +pub use hardhatconsole_mod::HARDHATCONSOLE_ABI as HARDHAT_CONSOLE_ABI; /// If the input starts with a known `hardhat/console.log` `uint` selector, then this will replace /// it with the selector `abigen!` bindings expect. -pub fn patch_hardhat_console_log_selector(mut input: Vec) -> Vec { +pub fn patch_hardhat_console_selector(mut input: Vec) -> Vec { if input.len() < 4 { return input } + let selector = Selector::try_from(&input[..4]).unwrap(); if let Some(abigen_selector) = HARDHAT_CONSOLE_SELECTOR_PATCHES.get(&selector) { input.splice(..4, *abigen_selector); @@ -127,7 +101,7 @@ pub fn patch_hardhat_console_log_selector(mut input: Vec) -> Vec { /// This is a bit terrible but a workaround for the differing selectors used by hardhat and the call /// bindings which `abigen!` creates. `hardhat/console.log` logs its events in functions that accept /// `uint` manually as `abi.encodeWithSignature("log(int)", p0)`, but `abigen!` uses `uint256` for -/// its call bindings (`ConsoleCalls`) as generated by solc. +/// its call bindings (`HardhatConsoleCalls`) as generated by solc. pub static HARDHAT_CONSOLE_SELECTOR_PATCHES: Lazy> = Lazy::new(|| { HashMap::from([ // log(bool,uint256,uint256,address) @@ -648,7 +622,7 @@ mod tests { #[test] fn hardhat_console_path_works() { for (hh, abigen) in HARDHAT_CONSOLE_SELECTOR_PATCHES.iter() { - let patched = patch_hardhat_console_log_selector(hh.to_vec()); + let patched = patch_hardhat_console_selector(hh.to_vec()); assert_eq!(abigen.to_vec(), patched); } } diff --git a/evm/src/executor/builder.rs b/evm/src/executor/builder.rs new file mode 100644 index 000000000000..3bb2714398e9 --- /dev/null +++ b/evm/src/executor/builder.rs @@ -0,0 +1,168 @@ +use ethers::prelude::Provider; +use revm::{ + db::{DatabaseRef, EmptyDB}, + Env, SpecId, +}; +use std::path::PathBuf; + +use super::{fork::SharedBackend, inspector::InspectorStackConfig, Executor}; + +use ethers::types::{H160, H256, U256}; + +use crate::executor::fork::{BlockchainDb, BlockchainDbMeta}; + +use revm::AccountInfo; +use url::Url; + +#[derive(Default, Debug)] +pub struct ExecutorBuilder { + /// The execution environment configuration. + env: Env, + /// The configuration used to build an [InspectorStack]. + inspector_config: InspectorStackConfig, + fork: Option, +} + +#[derive(Clone, Debug)] +pub struct Fork { + /// Where to read the cached storage from + pub cache_path: Option, + /// The URL to a node for fetching remote state + pub url: String, + /// The block to fork against + pub pin_block: Option, + /// chain id retrieved from the endpoint + pub chain_id: u64, +} + +impl Fork { + /// Initialises the Storage Backend + /// + /// If configured, then this will initialise the backend with the storage cache + pub fn into_backend(self, env: &Env) -> SharedBackend { + let Fork { cache_path, url, pin_block, chain_id } = self; + + let host = Url::parse(&url) + .ok() + .and_then(|url| url.host().map(|host| host.to_string())) + .unwrap_or_else(|| url.clone()); + + let provider = Provider::try_from(url).expect("Failed to establish provider"); + + let mut meta = + BlockchainDbMeta { cfg_env: env.cfg.clone(), block_env: env.block.clone(), host }; + + // update the meta to match the forked config + meta.cfg_env.chain_id = chain_id.into(); + if let Some(pin) = pin_block { + meta.block_env.number = pin.into(); + } + + let db = BlockchainDb::new(meta, cache_path); + + SharedBackend::new(provider, db, pin_block.map(Into::into)) + } +} + +pub enum Backend { + Simple(EmptyDB), + Forked(SharedBackend), +} + +impl Backend { + /// Instantiates a new backend union based on whether there was or not a fork url specified + fn new(fork: Option, env: &Env) -> Self { + if let Some(fork) = fork { + Backend::Forked(fork.into_backend(env)) + } else { + Backend::Simple(EmptyDB()) + } + } +} + +impl DatabaseRef for Backend { + fn basic(&self, address: H160) -> AccountInfo { + match self { + Backend::Simple(inner) => inner.basic(address), + Backend::Forked(inner) => inner.basic(address), + } + } + + fn code_by_hash(&self, address: H256) -> bytes::Bytes { + match self { + Backend::Simple(inner) => inner.code_by_hash(address), + Backend::Forked(inner) => inner.code_by_hash(address), + } + } + + fn storage(&self, address: H160, index: U256) -> U256 { + match self { + Backend::Simple(inner) => inner.storage(address, index), + Backend::Forked(inner) => inner.storage(address, index), + } + } + + fn block_hash(&self, number: U256) -> H256 { + match self { + Backend::Simple(inner) => inner.block_hash(number), + Backend::Forked(inner) => inner.block_hash(number), + } + } +} + +impl ExecutorBuilder { + #[must_use] + pub fn new() -> Self { + Default::default() + } + + /// Enables cheatcodes on the executor. + #[must_use] + pub fn with_cheatcodes(mut self, ffi: bool) -> Self { + self.inspector_config.cheatcodes = true; + self.inspector_config.ffi = ffi; + self + } + + /// Enables tracing + #[must_use] + pub fn with_tracing(mut self) -> Self { + self.inspector_config.tracing = true; + self + } + + /// Enables the debugger + #[must_use] + pub fn with_debugger(mut self) -> Self { + self.inspector_config.debugger = true; + self + } + + /// Sets the EVM spec to use + #[must_use] + pub fn with_spec(mut self, spec: SpecId) -> Self { + self.env.cfg.spec_id = spec; + self + } + + /// Configure the execution environment (gas limit, chain spec, ...) + #[must_use] + pub fn with_config(mut self, env: Env) -> Self { + self.inspector_config.block = env.block.clone(); + self.env = env; + self + } + + /// Configure the executor's forking mode + #[must_use] + pub fn with_fork(mut self, fork: Option) -> Self { + self.fork = fork; + self + } + + /// Builds the executor as configured. + pub fn build(self) -> Executor { + let db = Backend::new(self.fork, &self.env); + Executor::new(db, self.env, self.inspector_config) + } +} diff --git a/evm/src/executor/fork/backend.rs b/evm/src/executor/fork/backend.rs new file mode 100644 index 000000000000..bb7c7c80b9f3 --- /dev/null +++ b/evm/src/executor/fork/backend.rs @@ -0,0 +1,567 @@ +//! Smart caching and deduplication of requests when using a forking provider +use revm::{db::DatabaseRef, AccountInfo, KECCAK_EMPTY}; + +use crate::executor::fork::BlockchainDb; +use ethers::{ + core::abi::ethereum_types::BigEndianHash, + providers::Middleware, + types::{Address, BlockId, Bytes, H160, H256, U256}, + utils::keccak256, +}; +use foundry_utils::RuntimeOrHandle; +use futures::{ + channel::mpsc::{channel, Receiver, Sender}, + stream::{Fuse, Stream, StreamExt}, + task::{Context, Poll}, + Future, FutureExt, +}; + +use std::{ + collections::{hash_map::Entry, HashMap}, + pin::Pin, + sync::mpsc::{channel as oneshot_channel, Sender as OneshotSender}, +}; +use tracing::trace; + +type AccountFuture = + Pin, Address)> + Send>>; +type StorageFuture = Pin, Address, U256)> + Send>>; +type BlockHashFuture = Pin, u64)> + Send>>; + +/// Request variants that are executed by the provider +enum ProviderRequest { + Account(AccountFuture), + Storage(StorageFuture), + BlockHash(BlockHashFuture), +} + +/// The Request type the Backend listens for +#[derive(Debug)] +enum BackendRequest { + Basic(Address, OneshotSender), + Storage(Address, U256, OneshotSender), + BlockHash(u64, OneshotSender), +} + +/// Handles an internal provider and listens for requests. +/// +/// This handler will remain active as long as it is reachable (request channel still open) and +/// requests are in progress. +#[must_use = "BackendHandler does nothing unless polled."] +struct BackendHandler { + provider: M, + /// Stores all the data. + db: BlockchainDb, + /// Requests currently in progress + pending_requests: Vec>, + /// Listeners that wait for a `get_account` related response + account_requests: HashMap>>, + /// Listeners that wait for a `get_storage_at` response + storage_requests: HashMap<(Address, U256), Vec>>, + /// Listeners that wait for a `get_block` response + block_requests: HashMap>>, + /// Incoming commands. + incoming: Fuse>, + /// shutdown signal + shutdown: Fuse>>, + /// The block to fetch data from. + // This is an `Option` so that we can have less code churn in the functions below + block_id: Option, +} + +impl BackendHandler +where + M: Middleware + Clone + 'static, +{ + fn new( + provider: M, + db: BlockchainDb, + rx: Receiver, + shutdown: Receiver>, + block_id: Option, + ) -> Self { + Self { + provider, + db, + pending_requests: Default::default(), + account_requests: Default::default(), + storage_requests: Default::default(), + block_requests: Default::default(), + incoming: rx.fuse(), + shutdown: shutdown.fuse(), + block_id, + } + } + + /// handle the request in queue in the future. + /// + /// We always check: + /// 1. if the requested value is already stored in the cache, then answer the sender + /// 2. otherwise, fetch it via the provider but check if a request for that value is already in + /// progress (e.g. another Sender just requested the same account) + fn on_request(&mut self, req: BackendRequest) { + match req { + BackendRequest::Basic(addr, sender) => { + trace!(target: "backendhandler", "received request basic address={:?}", addr); + let lock = self.db.accounts().read(); + let basic = lock.get(&addr).cloned(); + // release the lock + drop(lock); + if let Some(basic) = basic { + let _ = sender.send(basic); + } else { + self.request_account(addr, sender); + } + } + BackendRequest::BlockHash(number, sender) => { + let lock = self.db.block_hashes().read(); + let hash = lock.get(&number).cloned(); + // release the lock + drop(lock); + if let Some(hash) = hash { + let _ = sender.send(hash); + } else { + self.request_hash(number, sender); + } + } + BackendRequest::Storage(addr, idx, sender) => { + let lock = self.db.storage().read(); + let acc = lock.get(&addr); + let value = acc.and_then(|acc| acc.get(&idx).copied()); + // release the lock + drop(lock); + + // account is already stored in the cache + if let Some(value) = value { + let _ = sender.send(value); + } else { + // account present but not storage -> fetch storage + self.request_account_storage(addr, idx, sender); + } + } + } + } + + /// process a request for account's storage + fn request_account_storage( + &mut self, + address: Address, + idx: U256, + listener: OneshotSender, + ) { + match self.storage_requests.entry((address, idx)) { + Entry::Occupied(mut entry) => { + entry.get_mut().push(listener); + } + Entry::Vacant(entry) => { + trace!(target: "backendhandler", "preparing storage request, address={:?}, idx={}", address, idx); + entry.insert(vec![listener]); + let provider = self.provider.clone(); + let block_id = self.block_id; + let fut = Box::pin(async move { + // serialize & deserialize back to U256 + let idx_req = H256::from_uint(&idx); + let storage = provider.get_storage_at(address, idx_req, block_id).await; + let storage = + storage.map(|storage| storage.into_uint()).map_err(|err| eyre::eyre!(err)); + (storage, address, idx) + }); + self.pending_requests.push(ProviderRequest::Storage(fut)); + } + } + } + + /// returns the future that fetches the account data + fn get_account_req(&self, address: Address) -> ProviderRequest { + trace!(target: "backendhandler", "preparing account request, address={:?}", address); + let provider = self.provider.clone(); + let block_id = self.block_id; + let fut = Box::pin(async move { + let balance = provider.get_balance(address, block_id); + let nonce = provider.get_transaction_count(address, block_id); + let code = provider.get_code(address, block_id); + let resp = tokio::try_join!(balance, nonce, code).map_err(|err| eyre::eyre!(err)); + (resp, address) + }); + ProviderRequest::Account(fut) + } + + /// process a request for an account + fn request_account(&mut self, address: Address, listener: OneshotSender) { + match self.account_requests.entry(address) { + Entry::Occupied(mut entry) => { + entry.get_mut().push(listener); + } + Entry::Vacant(entry) => { + entry.insert(vec![listener]); + self.pending_requests.push(self.get_account_req(address)); + } + } + } + + /// process a request for a block hash + fn request_hash(&mut self, number: u64, listener: OneshotSender) { + match self.block_requests.entry(number) { + Entry::Occupied(mut entry) => { + entry.get_mut().push(listener); + } + Entry::Vacant(entry) => { + trace!(target: "backendhandler", "preparing block hash request, number={}", number); + entry.insert(vec![listener]); + let provider = self.provider.clone(); + let fut = Box::pin(async move { + let res = provider.get_block(number).await; + let block = res.ok().flatten(); + let block_hash = match block { + Some(block) => Ok(block + .hash + .expect("empty block hash on mined block, this should never happen")), + None => Err(eyre::eyre!("block {} not found", number)), + }; + (block_hash, number) + }); + self.pending_requests.push(ProviderRequest::BlockHash(fut)); + } + } + } +} + +impl Future for BackendHandler +where + M: Middleware + Clone + Unpin + 'static, +{ + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let pin = self.get_mut(); + + // receive new requests to delegate to the underlying provider + while let Poll::Ready(Some(req)) = Pin::new(&mut pin.incoming).poll_next(cx) { + pin.on_request(req) + } + + // poll all requests in progress + for n in (0..pin.pending_requests.len()).rev() { + let mut request = pin.pending_requests.swap_remove(n); + match &mut request { + ProviderRequest::Account(fut) => { + if let Poll::Ready((resp, addr)) = fut.poll_unpin(cx) { + // get the response + let (balance, nonce, code) = resp.unwrap_or_else(|_| { + trace!("Failed to get account for {}", addr); + Default::default() + }); + + // conver it to revm-style types + let (code, code_hash) = if !code.0.is_empty() { + (Some(code.0.clone()), keccak256(&code).into()) + } else { + (None, KECCAK_EMPTY) + }; + + // update the cache + let acc = AccountInfo { nonce: nonce.as_u64(), balance, code, code_hash }; + pin.db.accounts().write().insert(addr, acc.clone()); + + // notify all listeners + if let Some(listeners) = pin.account_requests.remove(&addr) { + listeners.into_iter().for_each(|l| { + let _ = l.send(acc.clone()); + }) + } + continue + } + } + ProviderRequest::Storage(fut) => { + if let Poll::Ready((resp, addr, idx)) = fut.poll_unpin(cx) { + let value = resp.unwrap_or_else(|_| { + trace!("Failed to get storage for {} at {}", addr, idx); + Default::default() + }); + + // update the cache + pin.db.storage().write().entry(addr).or_default().insert(idx, value); + + // notify all listeners + if let Some(listeners) = pin.storage_requests.remove(&(addr, idx)) { + listeners.into_iter().for_each(|l| { + let _ = l.send(value); + }) + } + continue + } + } + ProviderRequest::BlockHash(fut) => { + if let Poll::Ready((block_hash, number)) = fut.poll_unpin(cx) { + let value = block_hash.unwrap_or_else(|_| { + trace!("Failed to get block hash for {}", number); + Default::default() + }); + + // update the cache + pin.db.block_hashes().write().insert(number, value); + + // notify all listeners + if let Some(listeners) = pin.block_requests.remove(&number) { + listeners.into_iter().for_each(|l| { + let _ = l.send(value); + }) + } + continue + } + } + } + // not ready, insert and poll again + pin.pending_requests.push(request); + } + + // the handler is finished if the request channel was closed and all requests are processed + if pin.incoming.is_done() && pin.pending_requests.is_empty() { + if let Poll::Ready(Some(ack)) = Pin::new(&mut pin.shutdown).poll_next(cx) { + // effectively flushing the cached storage if any + pin.db.cache().flush(); + // signaling back + let _ = ack.send(()); + } + + if pin.shutdown.is_done() { + trace!(target: "backendhandler", "finished"); + return Poll::Ready(()) + } + } + Poll::Pending + } +} + +/// A cloneable backend type that shares access to the backend data with all its clones. +/// +/// This backend type is connected to the `BackendHandler` via a mpsc channel. The `BackendHandlers` +/// is spawned on a background thread and listens for incoming commands on the receiver half of the +/// channel. A `SharedBackend` holds a sender for that channel, which is `Clone`, so their can be +/// multiple `SharedBackend`s communicating with the same `BackendHandler`, hence this `Backend` +/// type is thread safe. +/// +/// All `Backend` trait functions are delegated as a `BackendRequest` via the channel to the +/// `BackendHandler`. All `BackendRequest` variants include a sender half of an additional channel +/// that is used by the `BackendHandler` to send the result of an executed `BackendRequest` back to +/// `SharedBackend`. +/// +/// The `BackendHandler` holds an ethers `Provider` to look up missing accounts or storage slots +/// from remote (e.g. infura). It detects duplicate requests from multiple `SharedBackend`s and +/// bundles them together, so that always only one provider request is executed. For example, there +/// are two `SharedBackend`s, `A` and `B`, both request the basic account info of account +/// `0xasd9sa7d...` at the same time. After the `BackendHandler` receives the request from `A`, it +/// sends a new provider request to the provider's endpoint, then it reads the identical request +/// from `B` and simply adds it as an additional listener for the request already in progress, +/// instead of sending another one. So that after the provider returns the response all listeners +/// (`A` and `B`) get notified. +#[derive(Debug, Clone)] +pub struct SharedBackend { + /// channel used for sending commands related to database operations + backend: Sender, + /// channel to ensure the [BackendHandler] shutdowns gracefully + /// + /// This is essentially used to sync the last [SharedBackend] with the [BackendHandler] + shutdown: Sender>, +} + +impl Drop for SharedBackend { + fn drop(&mut self) { + // disconnect the command channel + self.backend.disconnect(); + if self.backend.is_closed() { + // was the last sender, let the handler know and wait until it gracefully shut down + let (ack, rx) = oneshot_channel(); + if self.shutdown.try_send(ack).is_ok() { + let _ = rx.recv(); + } + } + } +} + +impl SharedBackend { + /// Spawns a new `BackendHandler` on a background thread that listens for requests from any + /// `SharedBackend`. Missing values get inserted in the `cache`. + /// + /// + /// NOTE: this should be called with `Arc` + pub fn new(provider: M, db: BlockchainDb, pin_block: Option) -> Self + where + M: Middleware + Unpin + 'static + Clone, + { + let (backend, backend_rx) = channel(1); + let (shutdown, shutdown_rx) = channel(1); + let handler = BackendHandler::new(provider, db, backend_rx, shutdown_rx, pin_block); + // spawn the provider handler to background + let rt = RuntimeOrHandle::new(); + trace!(target: "backendhandler", "spawning Backendhandler"); + std::thread::spawn(move || match rt { + RuntimeOrHandle::Runtime(runtime) => runtime.block_on(handler), + RuntimeOrHandle::Handle(handle) => handle.block_on(handler), + }); + + Self { backend, shutdown } + } + + fn do_get_basic(&self, address: Address) -> eyre::Result { + let (sender, rx) = oneshot_channel(); + let req = BackendRequest::Basic(address, sender); + self.backend.clone().try_send(req).map_err(|e| eyre::eyre!("{:?}", e))?; + Ok(rx.recv()?) + } + + fn do_get_storage(&self, address: Address, index: U256) -> eyre::Result { + let (sender, rx) = oneshot_channel(); + let req = BackendRequest::Storage(address, index, sender); + self.backend.clone().try_send(req).map_err(|e| eyre::eyre!("{:?}", e))?; + Ok(rx.recv()?) + } + + fn do_get_block_hash(&self, number: u64) -> eyre::Result { + let (sender, rx) = oneshot_channel(); + let req = BackendRequest::BlockHash(number, sender); + self.backend.clone().try_send(req).map_err(|e| eyre::eyre!("{:?}", e))?; + Ok(rx.recv()?) + } +} + +impl DatabaseRef for SharedBackend { + fn basic(&self, address: H160) -> AccountInfo { + self.do_get_basic(address).unwrap_or_else(|_| { + trace!("Failed to send/recv `basic` for {}", address); + Default::default() + }) + } + + fn code_by_hash(&self, _address: H256) -> bytes::Bytes { + panic!("Should not be called. Code is already loaded.") + } + + fn storage(&self, address: H160, index: U256) -> U256 { + self.do_get_storage(address, index).unwrap_or_else(|_| { + trace!("Failed to send/recv `storage` for {} at {}", address, index); + Default::default() + }) + } + + fn block_hash(&self, number: U256) -> H256 { + if number > U256::from(u64::MAX) { + return KECCAK_EMPTY + } + let number = number.as_u64(); + self.do_get_block_hash(number).unwrap_or_else(|_| { + trace!("Failed to send/recv `block_hash` for {}", number); + Default::default() + }) + } +} + +#[cfg(test)] +mod tests { + use crate::executor::{ + fork::{BlockchainDbMeta, JsonBlockCacheDB}, + Fork, + }; + use ethers::{ + providers::{Http, Provider}, + types::Address, + }; + + use std::{convert::TryFrom, path::PathBuf, sync::Arc}; + + use super::*; + const ENDPOINT: &str = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + + #[test] + fn shared_backend() { + let provider = Provider::::try_from(ENDPOINT).unwrap(); + let meta = BlockchainDbMeta { + cfg_env: Default::default(), + block_env: Default::default(), + host: ENDPOINT.to_string(), + }; + + let db = BlockchainDb::new(meta, None); + let backend = SharedBackend::new(Arc::new(provider), db.clone(), None); + + // some rng contract from etherscan + let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap(); + + let idx = U256::from(0u64); + let value = backend.storage(address, idx); + let account = backend.basic(address); + + let mem_acc = db.accounts().read().get(&address).unwrap().clone(); + assert_eq!(account.balance, mem_acc.balance); + assert_eq!(account.nonce, mem_acc.nonce); + let slots = db.storage().read().get(&address).unwrap().clone(); + assert_eq!(slots.len(), 1); + assert_eq!(slots.get(&idx).copied().unwrap(), value); + + let num = U256::from(10u64); + let hash = backend.block_hash(num); + let mem_hash = *db.block_hashes().read().get(&num.as_u64()).unwrap(); + assert_eq!(hash, mem_hash); + + let max_slots = 5; + let handle = std::thread::spawn(move || { + for i in 1..max_slots { + let idx = U256::from(i); + let _ = backend.storage(address, idx); + } + }); + handle.join().unwrap(); + let slots = db.storage().read().get(&address).unwrap().clone(); + assert_eq!(slots.len() as u64, max_slots); + } + + #[test] + fn can_read_cache() { + let cache_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/storage.json"); + let json = JsonBlockCacheDB::load(cache_path).unwrap(); + assert!(!json.db().accounts.read().is_empty()); + } + + #[test] + fn can_read_write_cache() { + let tmpdir = tempfile::tempdir().unwrap(); + let cache_path = tmpdir.path().join("storage.json"); + + let block_num = 14435000; + let env = revm::Env::default(); + + let fork = Fork { + cache_path: Some(cache_path.clone()), + url: ENDPOINT.to_string(), + pin_block: Some(block_num), + chain_id: 1, + }; + + let backend = fork.into_backend(&env); + + // some rng contract from etherscan + let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap(); + + let idx = U256::from(0u64); + let _value = backend.storage(address, idx); + let _account = backend.basic(address); + + // fill some slots + let num_slots = 10u64; + for idx in 1..num_slots { + let _ = backend.storage(address, idx.into()); + } + drop(backend); + + let meta = BlockchainDbMeta { + cfg_env: Default::default(), + block_env: revm::BlockEnv { number: block_num.into(), ..Default::default() }, + host: "mainnet.infura.io".to_string(), + }; + + let db = BlockchainDb::new(meta, Some(cache_path)); + assert!(db.accounts().read().contains_key(&address)); + assert!(db.storage().read().contains_key(&address)); + assert_eq!(db.storage().read().get(&address).unwrap().len(), num_slots as usize); + } +} diff --git a/evm/src/executor/fork/cache.rs b/evm/src/executor/fork/cache.rs new file mode 100644 index 000000000000..918644fc567f --- /dev/null +++ b/evm/src/executor/fork/cache.rs @@ -0,0 +1,227 @@ +//! Cache related abstraction +use ethers::types::{Address, H256, U256}; +use parking_lot::RwLock; +use revm::AccountInfo; +use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; +use std::{collections::BTreeMap, fs, io::BufWriter, path::PathBuf, sync::Arc}; +use tracing::{trace, trace_span, warn}; +use tracing_error::InstrumentResult; + +pub type StorageInfo = BTreeMap; + +/// A shareable Block database +#[derive(Clone, Debug)] +pub struct BlockchainDb { + /// Contains all the data + db: Arc, + /// metadata of the current config + meta: Arc>, + /// the cache that can be flushed + cache: Arc, +} + +impl BlockchainDb { + /// Creates a new instance of the [BlockchainDb] + /// + /// if a `cache_path` is provided it attempts to load a previously stored [JsonBlockCacheData] + /// and will try to use the cached entries it holds. + /// + /// This will return a new and empty [MemDb] if + /// - `cache_path` is `None` + /// - the file the `cache_path` points to, does not exist + /// - the file contains malformed data, or if it couldn't be read + /// - the provided `meta` differs from [BlockchainDbMeta] that's stored on disk + pub fn new(meta: BlockchainDbMeta, cache_path: Option) -> Self { + // read cache and check if metadata matches + let cache = cache_path + .as_ref() + .and_then(|p| { + JsonBlockCacheDB::load(p).ok().filter(|cache| { + if meta != *cache.meta().read() { + warn!(target:"cache", "non-matching block metadata"); + false + } else { + true + } + }) + }) + .unwrap_or_else(|| JsonBlockCacheDB::new(Arc::new(RwLock::new(meta)), cache_path)); + + Self { db: Arc::clone(cache.db()), meta: Arc::clone(cache.meta()), cache: Arc::new(cache) } + } + + /// Returns the map that holds the account related info + pub fn accounts(&self) -> &RwLock> { + &self.db.accounts + } + + /// Returns the map that holds the storage related info + pub fn storage(&self) -> &RwLock> { + &self.db.storage + } + + /// Returns the map that holds all the block hashes + pub fn block_hashes(&self) -> &RwLock> { + &self.db.block_hashes + } + + /// Returns the [revm::Env] related metadata + pub fn meta(&self) -> &Arc> { + &self.meta + } + + /// Returns the inner cache + pub fn cache(&self) -> &Arc { + &self.cache + } +} + +/// relevant identifying markers in the context of [BlockchainDb] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct BlockchainDbMeta { + pub cfg_env: revm::CfgEnv, + pub block_env: revm::BlockEnv, + pub host: String, +} + +/// In Memory cache containing all fetched accounts and storage slots +/// and their values from RPC +#[derive(Debug, Default)] +pub struct MemDb { + /// Account related data + pub accounts: RwLock>, + /// Storage related data + pub storage: RwLock>, + /// All retrieved block hashes + pub block_hashes: RwLock>, +} + +/// A [BlockCacheDB] that stores the cached content in a json file +#[derive(Debug)] +pub struct JsonBlockCacheDB { + /// Where this cache file is stored. + /// + /// If this is a [None] then caching is disabled + cache_path: Option, + /// Object that's stored in a json file + data: JsonBlockCacheData, +} + +impl JsonBlockCacheDB { + /// Creates a new instance. + fn new(meta: Arc>, cache_path: Option) -> Self { + Self { cache_path, data: JsonBlockCacheData { meta, data: Arc::new(Default::default()) } } + } + + /// Loads the contents of the diskmap file and returns the read object + /// + /// # Errors + /// This will fail if + /// - the `path` does not exist + /// - the format does not match [JsonBlockCacheData] + pub fn load(path: impl Into) -> eyre::Result { + let path = path.into(); + trace!(target: "cache", "reading json cache path={:?}", path); + let span = trace_span!("cache", "path={:?}", &path); + let _enter = span.enter(); + let file = std::fs::File::open(&path).in_current_span()?; + let file = std::io::BufReader::new(file); + let data = serde_json::from_reader(file).in_current_span()?; + Ok(Self { cache_path: Some(path), data }) + } + + /// Returns the [MemDb] it holds access to + pub fn db(&self) -> &Arc { + &self.data.data + } + + /// Metadata stored alongside the data + pub fn meta(&self) -> &Arc> { + &self.data.meta + } + + /// Returns `true` if this is a transient cache and nothing will be flushed + pub fn is_transient(&self) -> bool { + self.cache_path.is_none() + } + + /// Flushes the DB to disk if caching is enabled + pub fn flush(&self) { + // writes the data to a json file + if let Some(ref path) = self.cache_path { + trace!(target: "cache", "saving json cache path={:?}", path); + if let Some(parent) = path.parent() { + let _ = fs::create_dir_all(parent); + } + let _ = fs::File::create(path) + .map_err(|e| warn!(target: "cache", "Failed to open json cache for writing: {}", e)) + .and_then(|f| { + serde_json::to_writer(BufWriter::new(f), &self.data) + .map_err(|e| warn!(target: "cache" ,"Failed to write to json cache: {}", e)) + }); + } + } +} + +/// The Data the [JsonBlockCacheDB] can read and flush +/// +/// This will be deserialized in a JSON object with the keys: +/// `["meta", "accounts", "storage", "block_hashes"]` +#[derive(Debug)] +pub struct JsonBlockCacheData { + pub meta: Arc>, + pub data: Arc, +} + +impl Serialize for JsonBlockCacheData { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(4))?; + + let meta = self.meta.read(); + map.serialize_entry("meta", &*meta)?; + drop(meta); + + let accounts = self.data.accounts.read(); + map.serialize_entry("accounts", &*accounts)?; + drop(accounts); + + let storage = self.data.storage.read(); + map.serialize_entry("storage", &*storage)?; + drop(storage); + + let block_hashes = self.data.block_hashes.read(); + map.serialize_entry("block_hashes", &*block_hashes)?; + drop(block_hashes); + + map.end() + } +} + +impl<'de> Deserialize<'de> for JsonBlockCacheData { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct Data { + meta: BlockchainDbMeta, + accounts: BTreeMap, + storage: BTreeMap, + block_hashes: BTreeMap, + } + + let Data { meta, accounts, storage, block_hashes } = Data::deserialize(deserializer)?; + + Ok(JsonBlockCacheData { + meta: Arc::new(RwLock::new(meta)), + data: Arc::new(MemDb { + accounts: RwLock::new(accounts), + storage: RwLock::new(storage), + block_hashes: RwLock::new(block_hashes), + }), + }) + } +} diff --git a/evm/src/executor/fork/init.rs b/evm/src/executor/fork/init.rs new file mode 100644 index 000000000000..910f2eb74436 --- /dev/null +++ b/evm/src/executor/fork/init.rs @@ -0,0 +1,45 @@ +use ethers::{providers::Middleware, types::Address}; +use revm::{BlockEnv, CfgEnv, Env, TxEnv}; + +/// Initializes a REVM block environment based on a forked +/// ethereum provider. +pub async fn environment( + provider: &M, + override_chain_id: Option, + pin_block: Option, + origin: Address, +) -> Result { + let block_number = if let Some(pin_block) = pin_block { + pin_block + } else { + provider.get_block_number().await?.as_u64() + }; + let (gas_price, rpc_chain_id, block) = tokio::try_join!( + provider.get_gas_price(), + provider.get_chainid(), + provider.get_block(block_number) + )?; + let block = block.expect("block not found"); + + Ok(Env { + cfg: CfgEnv { + chain_id: override_chain_id.unwrap_or(rpc_chain_id.as_u64()).into(), + ..Default::default() + }, + block: BlockEnv { + number: block.number.expect("block number not found").as_u64().into(), + timestamp: block.timestamp, + coinbase: block.author, + difficulty: block.difficulty, + basefee: block.base_fee_per_gas.unwrap_or_default(), + gas_limit: block.gas_limit, + }, + tx: TxEnv { + caller: origin, + gas_price, + chain_id: Some(override_chain_id.unwrap_or(rpc_chain_id.as_u64())), + gas_limit: block.gas_limit.as_u64(), + ..Default::default() + }, + }) +} diff --git a/evm/src/executor/fork/mod.rs b/evm/src/executor/fork/mod.rs new file mode 100644 index 000000000000..aaa8398477de --- /dev/null +++ b/evm/src/executor/fork/mod.rs @@ -0,0 +1,8 @@ +mod backend; +pub use backend::SharedBackend; + +mod init; +pub use init::environment; + +mod cache; +pub use cache::{BlockchainDb, BlockchainDbMeta, JsonBlockCacheDB}; diff --git a/evm/src/executor/inspector/cheatcodes/env.rs b/evm/src/executor/inspector/cheatcodes/env.rs new file mode 100644 index 000000000000..7af17cff673c --- /dev/null +++ b/evm/src/executor/inspector/cheatcodes/env.rs @@ -0,0 +1,161 @@ +use std::collections::BTreeMap; + +use super::Cheatcodes; +use crate::abi::HEVMCalls; +use bytes::Bytes; +use ethers::{ + abi::{AbiEncode, Token, Tokenize}, + types::{Address, H256, U256}, + utils::keccak256, +}; +use revm::{Database, EVMData}; + +#[derive(Clone, Debug, Default)] +pub struct Prank { + /// Address of the contract that initiated the prank + pub prank_caller: Address, + /// Address of `tx.origin` when the prank was initiated + pub prank_origin: Address, + /// The address to assign to `msg.sender` + pub new_caller: Address, + /// The address to assign to `tx.origin` + pub new_origin: Option
, + /// The depth at which the prank was called + pub depth: u64, + /// Whether or not the prank stops by itself after the next call + pub single_call: bool, +} + +fn prank( + state: &mut Cheatcodes, + prank_caller: Address, + prank_origin: Address, + new_caller: Address, + new_origin: Option
, + depth: u64, + single_call: bool, +) -> Result { + let prank = Prank { prank_caller, prank_origin, new_caller, new_origin, depth, single_call }; + + if state.prank.is_some() { + return Err("You have an active prank already.".to_string().encode().into()) + } + + state.prank = Some(prank); + Ok(Bytes::new()) +} + +#[derive(Clone, Debug, Default)] +pub struct RecordAccess { + pub reads: BTreeMap>, + pub writes: BTreeMap>, +} + +fn start_record(state: &mut Cheatcodes) { + state.accesses = Some(Default::default()); +} + +fn accesses(state: &mut Cheatcodes, address: Address) -> Bytes { + if let Some(storage_accesses) = &mut state.accesses { + ethers::abi::encode(&[ + storage_accesses.reads.remove(&address).unwrap_or_default().into_tokens()[0].clone(), + storage_accesses.writes.remove(&address).unwrap_or_default().into_tokens()[0].clone(), + ]) + .into() + } else { + ethers::abi::encode(&[Token::Array(vec![]), Token::Array(vec![])]).into() + } +} + +pub fn apply( + state: &mut Cheatcodes, + data: &mut EVMData<'_, DB>, + caller: Address, + call: &HEVMCalls, +) -> Option> { + Some(match call { + HEVMCalls::Warp(inner) => { + data.env.block.timestamp = inner.0; + Ok(Bytes::new()) + } + HEVMCalls::Roll(inner) => { + data.env.block.number = inner.0; + Ok(Bytes::new()) + } + HEVMCalls::Fee(inner) => { + data.env.block.basefee = inner.0; + Ok(Bytes::new()) + } + HEVMCalls::Store(inner) => { + // TODO: Does this increase gas usage? + data.subroutine.load_account(inner.0, data.db); + data.subroutine.sstore(inner.0, inner.1.into(), inner.2.into(), data.db); + Ok(Bytes::new()) + } + HEVMCalls::Load(inner) => { + // TODO: Does this increase gas usage? + data.subroutine.load_account(inner.0, data.db); + let (val, _) = data.subroutine.sload(inner.0, inner.1.into(), data.db); + Ok(val.encode().into()) + } + HEVMCalls::Etch(inner) => { + let code = inner.1.clone(); + let hash = H256::from_slice(&keccak256(&code)); + + // TODO: Does this increase gas usage? + data.subroutine.load_account(inner.0, data.db); + data.subroutine.set_code(inner.0, code.0, hash); + Ok(Bytes::new()) + } + HEVMCalls::Deal(inner) => { + let who = inner.0; + let value = inner.1; + + // TODO: Does this increase gas usage? + data.subroutine.load_account(who, data.db); + let balance = data.subroutine.account(inner.0).info.balance; + + // TODO: We should probably upstream a `set_balance` function + if balance < value { + data.subroutine.balance_add(who, value - balance); + } else { + data.subroutine.balance_sub(who, balance - value); + } + Ok(Bytes::new()) + } + HEVMCalls::Prank0(inner) => { + prank(state, caller, data.env.tx.caller, inner.0, None, data.subroutine.depth(), true) + } + HEVMCalls::Prank1(inner) => prank( + state, + caller, + data.env.tx.caller, + inner.0, + Some(inner.1), + data.subroutine.depth(), + true, + ), + HEVMCalls::StartPrank0(inner) => { + prank(state, caller, data.env.tx.caller, inner.0, None, data.subroutine.depth(), false) + } + HEVMCalls::StartPrank1(inner) => prank( + state, + caller, + data.env.tx.caller, + inner.0, + Some(inner.1), + data.subroutine.depth(), + false, + ), + HEVMCalls::StopPrank(_) => { + state.prank = None; + Ok(Bytes::new()) + } + HEVMCalls::Record(_) => { + start_record(state); + Ok(Bytes::new()) + } + HEVMCalls::Accesses(inner) => Ok(accesses(state, inner.0)), + _ => return None, + }) +} diff --git a/evm/src/executor/inspector/cheatcodes/expect.rs b/evm/src/executor/inspector/cheatcodes/expect.rs new file mode 100644 index 000000000000..92e2c8875156 --- /dev/null +++ b/evm/src/executor/inspector/cheatcodes/expect.rs @@ -0,0 +1,189 @@ +use super::Cheatcodes; +use crate::abi::HEVMCalls; +use bytes::Bytes; +use ethers::{ + abi::{AbiEncode, RawLog}, + types::{Address, H160}, +}; +use revm::{return_ok, Database, EVMData, Return}; + +/// For some cheatcodes we may internally change the status of the call, i.e. in `expectRevert`. +/// Solidity will see a successful call and attempt to decode the return data. Therefore, we need +/// to populate the return with dummy bytes so the decode doesn't fail. +/// +/// 320 bytes was arbitrarily chosen because it is long enough for return values up to 10 words in +/// size. +static DUMMY_CALL_OUTPUT: [u8; 320] = [0u8; 320]; + +/// Same reasoning as [DUMMY_CALL_OUTPUT], but for creates. +static DUMMY_CREATE_ADDRESS: Address = + H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); + +#[derive(Clone, Debug, Default)] +pub struct ExpectedRevert { + /// The expected data returned by the revert + pub reason: Bytes, + /// The depth at which the revert is expected + pub depth: u64, +} + +fn expect_revert(state: &mut Cheatcodes, reason: Bytes, depth: u64) -> Result { + if state.expected_revert.is_some() { + Err("You must call another function prior to expecting a second revert." + .to_string() + .encode() + .into()) + } else { + state.expected_revert = Some(ExpectedRevert { reason, depth }); + Ok(Bytes::new()) + } +} + +pub fn handle_expect_revert( + is_create: bool, + expected_revert: &Bytes, + status: Return, + retdata: Bytes, +) -> Result<(Option
, Bytes), Bytes> { + if matches!(status, return_ok!()) { + return Err("Call did not revert as expected".to_string().encode().into()) + } + + if !expected_revert.is_empty() && retdata.is_empty() { + return Err("Call reverted as expected, but without data".to_string().encode().into()) + } + + let (err, actual_revert): (_, Bytes) = match retdata { + _ if retdata.len() >= 4 && retdata[0..4] == [8, 195, 121, 160] => { + // It's a revert string, so we do some conversion to perform the check + let decoded_data: Bytes = + ethers::abi::decode(&[ethers::abi::ParamType::Bytes], &retdata[4..]) + .expect("String error code, but data is not a string")[0] + .clone() + .into_bytes() + .expect("Cannot fail as this is bytes") + .into(); + + ( + format!( + "Error != expected error: '{}' != '{}'", + String::from_utf8_lossy(&decoded_data), + String::from_utf8_lossy(expected_revert) + ) + .encode() + .into(), + decoded_data, + ) + } + _ => ( + format!( + "Error != expected error: 0x{} != 0x{}", + hex::encode(&retdata), + hex::encode(&expected_revert) + ) + .encode() + .into(), + retdata, + ), + }; + + if actual_revert == expected_revert { + Ok(if is_create { + (Some(DUMMY_CREATE_ADDRESS), Bytes::new()) + } else { + (None, DUMMY_CALL_OUTPUT.to_vec().into()) + }) + } else { + Err(err) + } +} + +#[derive(Clone, Debug, Default)] +pub struct ExpectedEmit { + /// The depth at which we expect this emit to have occurred + pub depth: u64, + /// The log we expect + pub log: Option, + /// The checks to perform: + /// + /// ┌───────┬───────┬───────┬────┐ + /// │topic 1│topic 2│topic 3│data│ + /// └───────┴───────┴───────┴────┘ + pub checks: [bool; 4], + /// Whether the log was actually found in the subcalls + pub found: bool, +} + +pub fn handle_expect_emit(state: &mut Cheatcodes, log: RawLog) { + // Fill or check the expected emits + if let Some(next_expect_to_fill) = + state.expected_emits.iter_mut().find(|expect| expect.log.is_none()) + { + // We have unfilled expects, so we fill the first one + next_expect_to_fill.log = Some(log); + } else if let Some(next_expect) = state.expected_emits.iter_mut().find(|expect| !expect.found) { + // We do not have unfilled expects, so we try to match this log with the first unfound + // log that we expect + let expected = + next_expect.log.as_ref().expect("we should have a log to compare against here"); + if expected.topics[0] == log.topics[0] { + // Topic 0 matches so the amount of topics in the expected and actual log should + // match here + let topics_match = log + .topics + .iter() + .skip(1) + .enumerate() + .filter(|(i, _)| next_expect.checks[*i]) + .all(|(i, topic)| topic == &expected.topics[i + 1]); + + // Maybe check data + next_expect.found = if next_expect.checks[3] { + expected.data == log.data && topics_match + } else { + topics_match + }; + } + } +} + +pub fn apply( + state: &mut Cheatcodes, + data: &mut EVMData<'_, DB>, + call: &HEVMCalls, +) -> Option> { + Some(match call { + HEVMCalls::ExpectRevert0(_) => expect_revert(state, Bytes::new(), data.subroutine.depth()), + HEVMCalls::ExpectRevert1(inner) => { + expect_revert(state, inner.0.to_vec().into(), data.subroutine.depth()) + } + HEVMCalls::ExpectRevert2(inner) => { + expect_revert(state, inner.0.to_vec().into(), data.subroutine.depth()) + } + HEVMCalls::ExpectEmit(inner) => { + state.expected_emits.push(ExpectedEmit { + depth: data.subroutine.depth(), + checks: [inner.0, inner.1, inner.2, inner.3], + ..Default::default() + }); + Ok(Bytes::new()) + } + HEVMCalls::ExpectCall(inner) => { + state.expected_calls.entry(inner.0).or_default().push(inner.1.to_vec().into()); + Ok(Bytes::new()) + } + HEVMCalls::MockCall(inner) => { + state + .mocked_calls + .entry(inner.0) + .or_default() + .insert(inner.1.to_vec().into(), inner.2.to_vec().into()); + Ok(Bytes::new()) + } + HEVMCalls::ClearMockedCalls(_) => { + state.mocked_calls = Default::default(); + Ok(Bytes::new()) + } + _ => return None, + }) +} diff --git a/evm/src/executor/inspector/cheatcodes/ext.rs b/evm/src/executor/inspector/cheatcodes/ext.rs new file mode 100644 index 000000000000..55ae60d98e14 --- /dev/null +++ b/evm/src/executor/inspector/cheatcodes/ext.rs @@ -0,0 +1,91 @@ +use crate::abi::HEVMCalls; +use bytes::Bytes; +use ethers::{ + abi::{self, AbiEncode, Token}, + prelude::{artifacts::CompactContractBytecode, ProjectPathsConfig}, +}; +use serde::Deserialize; +use std::{fs::File, io::Read, path::Path, process::Command}; + +fn ffi(args: &[String]) -> Result { + let output = Command::new(&args[0]) + .args(&args[1..]) + .output() + .map_err(|err| err.to_string().encode())? + .stdout; + let output = unsafe { std::str::from_utf8_unchecked(&output) }; + let decoded = hex::decode(&output.trim().strip_prefix("0x").unwrap_or(output)) + .map_err(|err| err.to_string().encode())?; + + Ok(abi::encode(&[Token::Bytes(decoded.to_vec())]).into()) +} + +/// An enum which unifies the deserialization of Hardhat-style artifacts with Forge-style artifacts +/// to get their bytecode. +#[derive(Deserialize)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +enum ArtifactBytecode { + Hardhat(HardhatArtifact), + Forge(CompactContractBytecode), +} + +impl ArtifactBytecode { + fn into_inner(self) -> Option { + match self { + ArtifactBytecode::Hardhat(inner) => Some(inner.bytecode), + ArtifactBytecode::Forge(inner) => { + inner.bytecode.and_then(|bytecode| bytecode.object.into_bytes()) + } + } + } +} + +/// A thin wrapper around a Hardhat-style artifact that only extracts the bytecode. +#[derive(Deserialize)] +struct HardhatArtifact { + #[serde(deserialize_with = "ethers::solc::artifacts::deserialize_bytes")] + bytecode: ethers::types::Bytes, +} + +fn get_code(path: &str) -> Result { + let path = if path.ends_with(".json") { + Path::new(&path).to_path_buf() + } else { + let parts: Vec<&str> = path.split(':').collect(); + let file = parts[0]; + let contract_name = + if parts.len() == 1 { parts[0].replace(".sol", "") } else { parts[1].to_string() }; + let out_dir = ProjectPathsConfig::find_artifacts_dir(Path::new("./")); + out_dir.join(format!("{}/{}.json", file, contract_name)) + }; + + let mut buffer = String::new(); + File::open(path) + .map_err(|err| err.to_string().encode())? + .read_to_string(&mut buffer) + .map_err(|err| err.to_string().encode())?; + + let bytecode = serde_json::from_str::(&buffer) + .map_err(|err| err.to_string().encode())?; + + if let Some(bin) = bytecode.into_inner() { + Ok(abi::encode(&[Token::Bytes(bin.to_vec())]).into()) + } else { + Err("No bytecode for contract. Is it abstract or unlinked?".to_string().encode().into()) + } +} + +pub fn apply(ffi_enabled: bool, call: &HEVMCalls) -> Option> { + Some(match call { + HEVMCalls::Ffi(inner) => { + if !ffi_enabled { + Err("FFI disabled: run again with `--ffi` if you want to allow tests to call external scripts.".to_string().encode().into()) + } else { + ffi(&inner.0) + } + } + HEVMCalls::GetCode(inner) => get_code(&inner.0), + _ => return None, + }) +} diff --git a/evm/src/executor/inspector/cheatcodes/fuzz.rs b/evm/src/executor/inspector/cheatcodes/fuzz.rs new file mode 100644 index 000000000000..aef728313228 --- /dev/null +++ b/evm/src/executor/inspector/cheatcodes/fuzz.rs @@ -0,0 +1,14 @@ +use crate::{abi::HEVMCalls, fuzz::ASSUME_MAGIC_RETURN_CODE}; +use bytes::Bytes; +use revm::{Database, EVMData}; + +pub fn apply( + _: &mut EVMData<'_, DB>, + call: &HEVMCalls, +) -> Option> { + if let HEVMCalls::Assume(inner) = call { + Some(if inner.0 { Ok(Bytes::new()) } else { Err(ASSUME_MAGIC_RETURN_CODE.into()) }) + } else { + None + } +} diff --git a/evm/src/executor/inspector/cheatcodes/mod.rs b/evm/src/executor/inspector/cheatcodes/mod.rs new file mode 100644 index 000000000000..6e9737d872f5 --- /dev/null +++ b/evm/src/executor/inspector/cheatcodes/mod.rs @@ -0,0 +1,339 @@ +/// Cheatcodes related to the execution environment. +mod env; +pub use env::{Prank, RecordAccess}; +/// Assertion helpers (such as `expectEmit`) +mod expect; +pub use expect::{ExpectedEmit, ExpectedRevert}; +/// Cheatcodes that interact with the external environment (FFI etc.) +mod ext; +/// Cheatcodes that configure the fuzzer +mod fuzz; +/// Utility cheatcodes (`sign` etc.) +mod util; + +use self::expect::{handle_expect_emit, handle_expect_revert}; +use crate::{abi::HEVMCalls, executor::CHEATCODE_ADDRESS}; +use bytes::Bytes; +use ethers::{ + abi::{AbiDecode, AbiEncode, RawLog}, + types::{Address, H256}, +}; +use revm::{ + opcode, BlockEnv, CallInputs, CreateInputs, Database, EVMData, Gas, Inspector, Interpreter, + Return, +}; +use std::collections::BTreeMap; + +/// An inspector that handles calls to various cheatcodes, each with their own behavior. +/// +/// Cheatcodes can be called by contracts during execution to modify the VM environment, such as +/// mocking addresses, signatures and altering call reverts. +#[derive(Default)] +pub struct Cheatcodes { + /// Whether FFI is enabled or not + ffi: bool, + + /// The block environment + /// + /// Used in the cheatcode handler to overwrite the block environment separately from the + /// execution block environment. + pub block: Option, + + /// Address labels + pub labels: BTreeMap, + + /// Prank information + pub prank: Option, + + /// Expected revert information + pub expected_revert: Option, + + /// Recorded storage reads and writes + pub accesses: Option, + + /// Mocked calls + pub mocked_calls: BTreeMap>, + + /// Expected calls + pub expected_calls: BTreeMap>, + + /// Expected emits + pub expected_emits: Vec, +} + +impl Cheatcodes { + pub fn new(ffi: bool, block: BlockEnv) -> Self { + Self { ffi, block: Some(block), ..Default::default() } + } + + fn apply_cheatcode( + &mut self, + data: &mut EVMData<'_, DB>, + caller: Address, + call: &CallInputs, + ) -> Result { + // Decode the cheatcode call + let decoded = HEVMCalls::decode(&call.input).map_err(|err| err.to_string().encode())?; + + // TODO: Log the opcode for the debugger + env::apply(self, data, caller, &decoded) + .or_else(|| util::apply(self, data, &decoded)) + .or_else(|| expect::apply(self, data, &decoded)) + .or_else(|| fuzz::apply(data, &decoded)) + .or_else(|| ext::apply(self.ffi, &decoded)) + .ok_or_else(|| "Cheatcode was unhandled. This is a bug.".to_string().encode())? + } +} + +impl Inspector for Cheatcodes +where + DB: Database, +{ + fn call( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CallInputs, + _: bool, + ) -> (Return, Gas, Bytes) { + if call.contract == CHEATCODE_ADDRESS { + match self.apply_cheatcode(data, call.context.caller, call) { + Ok(retdata) => (Return::Return, Gas::new(call.gas_limit), retdata), + Err(err) => (Return::Revert, Gas::new(call.gas_limit), err), + } + } else { + // Handle expected calls + if let Some(expecteds) = self.expected_calls.get_mut(&call.contract) { + if let Some(found_match) = expecteds.iter().position(|expected| { + expected.len() <= call.input.len() && expected == &call.input[..expected.len()] + }) { + expecteds.remove(found_match); + } + } + + // Handle mocked calls + if let Some(mocks) = self.mocked_calls.get(&call.contract) { + if let Some(mock_retdata) = mocks.get(&call.input) { + return (Return::Return, Gas::new(call.gas_limit), mock_retdata.clone()) + } else if let Some((_, mock_retdata)) = + mocks.iter().find(|(mock, _)| *mock == &call.input[..mock.len()]) + { + return (Return::Return, Gas::new(call.gas_limit), mock_retdata.clone()) + } + } + + // Apply our prank + if let Some(prank) = &self.prank { + if data.subroutine.depth() >= prank.depth && + call.context.caller == prank.prank_caller + { + // At the target depth we set `msg.sender` + if data.subroutine.depth() == prank.depth { + call.context.caller = prank.new_caller; + call.transfer.source = prank.new_caller; + } + + // At the target depth, or deeper, we set `tx.origin` + if let Some(new_origin) = prank.new_origin { + data.env.tx.caller = new_origin; + } + } + } + + (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + } + } + + fn initialize_interp( + &mut self, + _: &mut Interpreter, + data: &mut EVMData<'_, DB>, + _: bool, + ) -> Return { + // When the first interpreter is initialized we've circumvented the balance and gas checks, + // so we apply our actual block data with the correct fees and all. + if let Some(block) = self.block.take() { + data.env.block = block; + } + + Return::Continue + } + + fn step(&mut self, interpreter: &mut Interpreter, _: &mut EVMData<'_, DB>, _: bool) -> Return { + // Record writes and reads if `record` has been called + if let Some(storage_accesses) = &mut self.accesses { + match interpreter.contract.code[interpreter.program_counter()] { + opcode::SLOAD => { + let key = try_or_continue!(interpreter.stack().peek(0)); + storage_accesses + .reads + .entry(interpreter.contract().address) + .or_insert_with(Vec::new) + .push(key); + } + opcode::SSTORE => { + let key = try_or_continue!(interpreter.stack().peek(0)); + + // An SSTORE does an SLOAD internally + storage_accesses + .reads + .entry(interpreter.contract().address) + .or_insert_with(Vec::new) + .push(key); + storage_accesses + .writes + .entry(interpreter.contract().address) + .or_insert_with(Vec::new) + .push(key); + } + _ => (), + } + } + + Return::Continue + } + + fn log(&mut self, _: &mut EVMData<'_, DB>, _: &Address, topics: &[H256], data: &Bytes) { + // Match logs if `expectEmit` has been called + if !self.expected_emits.is_empty() { + handle_expect_emit(self, RawLog { topics: topics.to_vec(), data: data.to_vec() }); + } + } + + fn call_end( + &mut self, + data: &mut EVMData<'_, DB>, + call: &CallInputs, + remaining_gas: Gas, + status: Return, + retdata: Bytes, + _: bool, + ) -> (Return, Gas, Bytes) { + if call.contract == CHEATCODE_ADDRESS { + return (status, remaining_gas, retdata) + } + + // Clean up pranks + if let Some(prank) = &self.prank { + data.env.tx.caller = prank.prank_origin; + if prank.single_call { + std::mem::take(&mut self.prank); + } + } + + // Handle expected reverts + if let Some(expected_revert) = &self.expected_revert { + if data.subroutine.depth() <= expected_revert.depth { + let expected_revert = std::mem::take(&mut self.expected_revert).unwrap(); + return match handle_expect_revert(false, &expected_revert.reason, status, retdata) { + Err(retdata) => (Return::Revert, remaining_gas, retdata), + Ok((_, retdata)) => (Return::Return, remaining_gas, retdata), + } + } + } + + // Handle expected emits at current depth + if !self + .expected_emits + .iter() + .filter(|expected| expected.depth == data.subroutine.depth()) + .all(|expected| expected.found) + { + return ( + Return::Revert, + remaining_gas, + "Log != expected log".to_string().encode().into(), + ) + } else { + // Clear the emits we expected at this depth that have been found + self.expected_emits.retain(|expected| !expected.found) + } + + // If the depth is 0, then this is the root call terminating + if data.subroutine.depth() == 0 { + // Handle expected calls that were not fulfilled + if let Some((address, expecteds)) = + self.expected_calls.iter().find(|(_, expecteds)| !expecteds.is_empty()) + { + return ( + Return::Revert, + remaining_gas, + format!( + "Expected a call to 0x{} with data {}, but got none", + address, + ethers::types::Bytes::from(expecteds[0].clone()) + ) + .encode() + .into(), + ) + } + + // Check if we have any leftover expected emits + if !self.expected_emits.is_empty() { + return ( + Return::Revert, + remaining_gas, + "Expected an emit, but no logs were emitted afterward" + .to_string() + .encode() + .into(), + ) + } + } + + (status, remaining_gas, retdata) + } + + fn create( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CreateInputs, + ) -> (Return, Option
, Gas, Bytes) { + // Apply our prank + if let Some(prank) = &self.prank { + if data.subroutine.depth() >= prank.depth && call.caller == prank.prank_caller { + // At the target depth we set `msg.sender` + if data.subroutine.depth() == prank.depth { + call.caller = prank.new_caller; + } + + // At the target depth, or deeper, we set `tx.origin` + if let Some(new_origin) = prank.new_origin { + data.env.tx.caller = new_origin; + } + } + } + + (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) + } + + fn create_end( + &mut self, + data: &mut EVMData<'_, DB>, + _: &CreateInputs, + status: Return, + address: Option
, + remaining_gas: Gas, + retdata: Bytes, + ) -> (Return, Option
, Gas, Bytes) { + // Clean up pranks + if let Some(prank) = &self.prank { + data.env.tx.caller = prank.prank_origin; + if prank.single_call { + std::mem::take(&mut self.prank); + } + } + + // Handle expected reverts + if let Some(expected_revert) = &self.expected_revert { + if data.subroutine.depth() <= expected_revert.depth { + let expected_revert = std::mem::take(&mut self.expected_revert).unwrap(); + return match handle_expect_revert(true, &expected_revert.reason, status, retdata) { + Err(retdata) => (Return::Revert, None, remaining_gas, retdata), + Ok((address, retdata)) => (Return::Return, address, remaining_gas, retdata), + } + } + } + + (status, address, remaining_gas, retdata) + } +} diff --git a/evm/src/executor/inspector/cheatcodes/util.rs b/evm/src/executor/inspector/cheatcodes/util.rs new file mode 100644 index 000000000000..136e1957566c --- /dev/null +++ b/evm/src/executor/inspector/cheatcodes/util.rs @@ -0,0 +1,65 @@ +use crate::abi::HEVMCalls; +use bytes::Bytes; +use ethers::{ + abi::AbiEncode, + prelude::{k256::ecdsa::SigningKey, LocalWallet, Signer}, + types::{H256, U256}, + utils, +}; +use revm::{Database, EVMData}; + +use super::Cheatcodes; + +fn addr(private_key: U256) -> Result { + if private_key.is_zero() { + return Err("Private key cannot be 0.".to_string().encode().into()) + } + + let mut bytes: [u8; 32] = [0; 32]; + private_key.to_big_endian(&mut bytes); + + let key = SigningKey::from_bytes(&bytes).map_err(|err| err.to_string().encode())?; + let addr = utils::secret_key_to_address(&key); + Ok(addr.encode().into()) +} + +fn sign(private_key: U256, digest: H256, chain_id: U256) -> Result { + if private_key.is_zero() { + return Err("Private key cannot be 0.".to_string().encode().into()) + } + + let mut bytes: [u8; 32] = [0; 32]; + private_key.to_big_endian(&mut bytes); + + let key = SigningKey::from_bytes(&bytes).map_err(|err| err.to_string().encode())?; + let wallet = LocalWallet::from(key).with_chain_id(chain_id.as_u64()); + + // The `ecrecover` precompile does not use EIP-155 + let sig = wallet.sign_hash(digest, false); + let recovered = sig.recover(digest).map_err(|err| err.to_string().encode())?; + + assert_eq!(recovered, wallet.address()); + + let mut r_bytes = [0u8; 32]; + let mut s_bytes = [0u8; 32]; + sig.r.to_big_endian(&mut r_bytes); + sig.s.to_big_endian(&mut s_bytes); + + Ok((sig.v, r_bytes, s_bytes).encode().into()) +} + +pub fn apply( + state: &mut Cheatcodes, + data: &mut EVMData<'_, DB>, + call: &HEVMCalls, +) -> Option> { + Some(match call { + HEVMCalls::Addr(inner) => addr(inner.0), + HEVMCalls::Sign(inner) => sign(inner.0, inner.1.into(), data.env.cfg.chain_id), + HEVMCalls::Label(inner) => { + state.labels.insert(inner.0, inner.1.clone()); + Ok(Bytes::new()) + } + _ => return None, + }) +} diff --git a/evm/src/executor/inspector/debugger.rs b/evm/src/executor/inspector/debugger.rs new file mode 100644 index 000000000000..bb3a9e0c6238 --- /dev/null +++ b/evm/src/executor/inspector/debugger.rs @@ -0,0 +1,223 @@ +use crate::{ + debug::{DebugArena, DebugNode, DebugStep, Instruction}, + executor::{ + inspector::utils::{gas_used, get_create_address}, + CHEATCODE_ADDRESS, + }, +}; +use bytes::Bytes; +use ethers::types::Address; +use revm::{ + opcode, spec_opcode_gas, CallInputs, CreateInputs, Database, EVMData, Gas, Inspector, + Interpreter, Memory, Return, SpecId, +}; +use std::collections::BTreeMap; + +/// An inspector that collects debug nodes on every step of the interpreter. +#[derive(Default, Debug)] +pub struct Debugger { + /// The arena of [DebugNode]s + pub arena: DebugArena, + /// The ID of the current [DebugNode]. + pub head: usize, + /// A mapping of program counters to instruction counters. + /// + /// The program counter keeps track of where we are in the contract bytecode as a whole, + /// including push bytes, while the instruction counter ignores push bytes. + /// + /// The instruction counter is used in Solidity source maps. + pub ic_map: BTreeMap>, + /// The amount of gas spent in the current gas block. + /// + /// REVM adds gas in blocks, so we need to keep track of this separately to get accurate gas + /// numbers on an opcode level. + /// + /// Gas blocks contain the gas costs of opcodes with a fixed cost. Dynamic costs are not + /// included in the gas block, and are instead added during execution of the contract. + pub current_gas_block: u64, + /// The amount of gas spent in the previous gas block. + /// + /// Costs for gas blocks are accounted for when *entering* the gas block, which also means that + /// every run of the interpreter will always start with a non-zero `gas.spend()`. + /// + /// For more information on gas blocks, see [current_gas_block]. + pub previous_gas_block: u64, +} + +impl Debugger { + /// Builds the instruction counter map for the given bytecode. + // TODO: Some of the same logic is performed in REVM, but then later discarded. We should + // investigate if we can reuse it + pub fn build_ic_map(&mut self, spec: SpecId, address: &Address, code: &Bytes) { + let opcode_infos = spec_opcode_gas(spec); + let mut ic_map: BTreeMap = BTreeMap::new(); + + let mut i = 0; + let mut cumulative_push_size = 0; + while i < code.len() { + let op = code[i]; + ic_map.insert(i, i - cumulative_push_size); + if opcode_infos[op as usize].is_push { + // Skip the push bytes. + // + // For more context on the math, see: https://github.com/bluealloy/revm/blob/007b8807b5ad7705d3cacce4d92b89d880a83301/crates/revm/src/interpreter/contract.rs#L114-L115 + i += (op - opcode::PUSH1 + 1) as usize; + cumulative_push_size += (op - opcode::PUSH1 + 1) as usize; + } + i += 1; + } + + self.ic_map.insert(*address, ic_map); + } + + /// Enters a new execution context. + pub fn enter(&mut self, depth: usize, address: Address, creation: bool) { + self.head = + self.arena.push_node(DebugNode { depth, address, creation, ..Default::default() }); + } + + /// Exits the current execution context, replacing it with the previous one. + pub fn exit(&mut self) { + if let Some(parent_id) = self.arena.arena[self.head].parent { + let DebugNode { depth, address, creation, .. } = self.arena.arena[parent_id]; + self.head = + self.arena.push_node(DebugNode { depth, address, creation, ..Default::default() }); + } + } +} + +impl Inspector for Debugger +where + DB: Database, +{ + fn call( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CallInputs, + _: bool, + ) -> (Return, Gas, Bytes) { + self.enter(data.subroutine.depth() as usize, call.contract, false); + if call.contract == CHEATCODE_ADDRESS { + self.arena.arena[self.head].steps.push(DebugStep { + memory: Memory::new(), + instruction: Instruction::Cheatcode( + call.input[0..4].try_into().expect("malformed cheatcode call"), + ), + ..Default::default() + }); + } + + (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + } + + fn initialize_interp( + &mut self, + interp: &mut Interpreter, + data: &mut EVMData<'_, DB>, + _: bool, + ) -> Return { + // TODO: This is rebuilt for all contracts every time. We should only run this if the IC + // map for a given address does not exist, *but* we need to account for the fact that the + // code given by the interpreter may either be the contract init code, or the runtime code. + self.build_ic_map( + data.env.cfg.spec_id, + &interp.contract().address, + &interp.contract().code, + ); + self.previous_gas_block = interp.contract.first_gas_block(); + Return::Continue + } + + fn step( + &mut self, + interpreter: &mut Interpreter, + data: &mut EVMData<'_, DB>, + _is_static: bool, + ) -> Return { + let pc = interpreter.program_counter(); + let op = interpreter.contract.code[pc]; + + // Get opcode information + let opcode_infos = spec_opcode_gas(data.env.cfg.spec_id); + let opcode_info = &opcode_infos[op as usize]; + + // Extract the push bytes + let push_size = if opcode_info.is_push { (op - opcode::PUSH1 + 1) as usize } else { 0 }; + let push_bytes = match push_size { + 0 => None, + n => { + let start = pc + 1; + let end = start + n; + Some(interpreter.contract.code[start..end].to_vec()) + } + }; + + // Calculate the current amount of gas used + let gas = interpreter.gas(); + let total_gas_spent = gas.spend() - self.previous_gas_block + self.current_gas_block; + if opcode_info.gas_block_end { + self.previous_gas_block = interpreter.contract.gas_block(pc); + self.current_gas_block = 0; + } else { + self.current_gas_block += opcode_info.gas; + } + + self.arena.arena[self.head].steps.push(DebugStep { + pc, + stack: interpreter.stack().data().clone(), + memory: interpreter.memory.clone(), + instruction: Instruction::OpCode(op), + push_bytes, + ic: *self + .ic_map + .get(&interpreter.contract().address) + .expect("no instruction counter map") + .get(&pc) + .expect("unknown ic for pc"), + total_gas_used: gas_used(data.env.cfg.spec_id, total_gas_spent, gas.refunded() as u64), + }); + + Return::Continue + } + + fn call_end( + &mut self, + _: &mut EVMData<'_, DB>, + _: &CallInputs, + gas: Gas, + status: Return, + retdata: Bytes, + _: bool, + ) -> (Return, Gas, Bytes) { + self.exit(); + + (status, gas, retdata) + } + + fn create( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CreateInputs, + ) -> (Return, Option
, Gas, Bytes) { + // TODO: Does this increase gas cost? + data.subroutine.load_account(call.caller, data.db); + let nonce = data.subroutine.account(call.caller).info.nonce; + self.enter(data.subroutine.depth() as usize, get_create_address(call, nonce), true); + + (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) + } + + fn create_end( + &mut self, + _: &mut EVMData<'_, DB>, + _: &CreateInputs, + status: Return, + address: Option
, + gas: Gas, + retdata: Bytes, + ) -> (Return, Option
, Gas, Bytes) { + self.exit(); + + (status, address, gas, retdata) + } +} diff --git a/evm/src/executor/inspector/logs.rs b/evm/src/executor/inspector/logs.rs new file mode 100644 index 000000000000..6b94b069266d --- /dev/null +++ b/evm/src/executor/inspector/logs.rs @@ -0,0 +1,74 @@ +use crate::executor::{ + patch_hardhat_console_selector, HardhatConsoleCalls, HARDHAT_CONSOLE_ADDRESS, +}; +use bytes::Bytes; +use ethers::{ + abi::{AbiDecode, RawLog, Token}, + types::{Address, H256}, +}; +use revm::{db::Database, CallInputs, EVMData, Gas, Inspector, Return}; + +/// An inspector that collects logs during execution. +/// +/// The inspector collects logs from the LOG opcodes as well as Hardhat-style logs. +#[derive(Default)] +pub struct LogCollector { + pub logs: Vec, +} + +impl LogCollector { + fn hardhat_log(&mut self, input: Vec) -> (Return, Bytes) { + // Patch the Hardhat-style selectors + let input = patch_hardhat_console_selector(input.to_vec()); + let decoded = match HardhatConsoleCalls::decode(&input) { + Ok(inner) => inner, + Err(err) => { + return ( + Return::Revert, + ethers::abi::encode(&[Token::String(err.to_string())]).into(), + ) + } + }; + + // Convert it to a DS-style `emit log(string)` event + self.logs.push(convert_hh_log_to_event(decoded)); + + (Return::Continue, Bytes::new()) + } +} + +impl Inspector for LogCollector +where + DB: Database, +{ + fn log(&mut self, _: &mut EVMData<'_, DB>, _: &Address, topics: &[H256], data: &Bytes) { + self.logs.push(RawLog { topics: topics.to_vec(), data: data.to_vec() }); + } + + fn call( + &mut self, + _: &mut EVMData<'_, DB>, + call: &mut CallInputs, + _: bool, + ) -> (Return, Gas, Bytes) { + if call.contract == HARDHAT_CONSOLE_ADDRESS { + let (status, reason) = self.hardhat_log(call.input.to_vec()); + (status, Gas::new(call.gas_limit), reason) + } else { + (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + } + } +} + +/// Converts a call to Hardhat's `console.log` to a DSTest `log(string)` event. +fn convert_hh_log_to_event(call: HardhatConsoleCalls) -> RawLog { + RawLog { + // This is topic 0 of DSTest's `log(string)` + topics: vec![H256::from_slice( + &hex::decode("41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50") + .unwrap(), + )], + // Convert the parameters of the call to their string representation for the log + data: ethers::abi::encode(&[Token::String(call.to_string())]), + } +} diff --git a/evm/src/executor/inspector/mod.rs b/evm/src/executor/inspector/mod.rs new file mode 100644 index 000000000000..bec689ed5cff --- /dev/null +++ b/evm/src/executor/inspector/mod.rs @@ -0,0 +1,54 @@ +#[macro_use] +mod utils; + +mod logs; +pub use logs::LogCollector; + +mod tracer; +pub use tracer::Tracer; + +mod debugger; +pub use debugger::Debugger; + +mod stack; +pub use stack::{InspectorData, InspectorStack}; + +mod cheatcodes; +pub use cheatcodes::Cheatcodes; + +use revm::BlockEnv; + +#[derive(Default, Clone, Debug)] +pub struct InspectorStackConfig { + /// Whether or not cheatcodes are enabled + pub cheatcodes: bool, + /// Whether or not the FFI cheatcode is enabled + pub ffi: bool, + /// The block environment + /// + /// Used in the cheatcode handler to overwrite the block environment separately from the + /// execution block environment. + pub block: BlockEnv, + /// Whether or not tracing is enabled + pub tracing: bool, + /// Whether or not the debugger is enabled + pub debugger: bool, +} + +impl InspectorStackConfig { + pub fn stack(&self) -> InspectorStack { + let mut stack = + InspectorStack { logs: Some(LogCollector::default()), ..Default::default() }; + + if self.cheatcodes { + stack.cheatcodes = Some(Cheatcodes::new(self.ffi, self.block.clone())); + } + if self.tracing { + stack.tracer = Some(Tracer::default()); + } + if self.debugger { + stack.debugger = Some(Debugger::default()); + } + stack + } +} diff --git a/evm/src/executor/inspector/stack.rs b/evm/src/executor/inspector/stack.rs new file mode 100644 index 000000000000..b041117d0421 --- /dev/null +++ b/evm/src/executor/inspector/stack.rs @@ -0,0 +1,252 @@ +use super::{Cheatcodes, Debugger, LogCollector, Tracer}; +use crate::{debug::DebugArena, trace::CallTraceArena}; +use bytes::Bytes; +use ethers::{ + abi::RawLog, + types::{Address, H256}, +}; +use revm::{db::Database, CallInputs, CreateInputs, EVMData, Gas, Inspector, Interpreter, Return}; +use std::collections::BTreeMap; + +/// Helper macro to call the same method on multiple inspectors without resorting to dynamic +/// dispatch +macro_rules! call_inspectors { + ($id:ident, [ $($inspector:expr),+ ], $call:block) => { + $({ + if let Some($id) = $inspector { + $call; + } + })+ + } +} + +pub struct InspectorData { + pub logs: Vec, + pub labels: BTreeMap, + pub traces: Option, + pub debug: Option, +} + +/// An inspector that calls multiple inspectors in sequence. +/// +/// If a call to an inspector returns a value other than [Return::Continue] (or equivalent) the +/// remaining inspectors are not called. +#[derive(Default)] +pub struct InspectorStack { + pub tracer: Option, + pub logs: Option, + pub cheatcodes: Option, + pub debugger: Option, +} + +impl InspectorStack { + pub fn collect_inspector_states(self) -> InspectorData { + InspectorData { + logs: self.logs.map(|logs| logs.logs).unwrap_or_default(), + labels: self.cheatcodes.map(|cheatcodes| cheatcodes.labels).unwrap_or_default(), + traces: self.tracer.map(|tracer| tracer.traces), + debug: self.debugger.map(|debugger| debugger.arena), + } + } +} + +impl Inspector for InspectorStack +where + DB: Database, +{ + fn initialize_interp( + &mut self, + interpreter: &mut Interpreter, + data: &mut EVMData<'_, DB>, + is_static: bool, + ) -> Return { + call_inspectors!( + inspector, + [&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes], + { + let status = inspector.initialize_interp(interpreter, data, is_static); + + // Allow inspectors to exit early + if status != Return::Continue { + return status + } + } + ); + + Return::Continue + } + + fn step( + &mut self, + interpreter: &mut Interpreter, + data: &mut EVMData<'_, DB>, + is_static: bool, + ) -> Return { + call_inspectors!( + inspector, + [&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes], + { + let status = inspector.step(interpreter, data, is_static); + + // Allow inspectors to exit early + if status != Return::Continue { + return status + } + } + ); + + Return::Continue + } + + fn log( + &mut self, + evm_data: &mut EVMData<'_, DB>, + address: &Address, + topics: &[H256], + data: &Bytes, + ) { + call_inspectors!(inspector, [&mut self.tracer, &mut self.logs, &mut self.cheatcodes], { + inspector.log(evm_data, address, topics, data); + }); + } + + fn step_end( + &mut self, + interpreter: &mut Interpreter, + data: &mut EVMData<'_, DB>, + is_static: bool, + status: Return, + ) -> Return { + call_inspectors!( + inspector, + [&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes], + { + let status = inspector.step_end(interpreter, data, is_static, status); + + // Allow inspectors to exit early + if status != Return::Continue { + return status + } + } + ); + + Return::Continue + } + + fn call( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CallInputs, + is_static: bool, + ) -> (Return, Gas, Bytes) { + call_inspectors!( + inspector, + [&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes], + { + let (status, gas, retdata) = inspector.call(data, call, is_static); + + // Allow inspectors to exit early + if status != Return::Continue { + return (status, gas, retdata) + } + } + ); + + (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + } + + fn call_end( + &mut self, + data: &mut EVMData<'_, DB>, + call: &CallInputs, + remaining_gas: Gas, + status: Return, + retdata: Bytes, + is_static: bool, + ) -> (Return, Gas, Bytes) { + call_inspectors!( + inspector, + [&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes], + { + let (new_status, new_gas, new_retdata) = inspector.call_end( + data, + call, + remaining_gas, + status, + retdata.clone(), + is_static, + ); + + // If the inspector returns a different status we assume it wants to tell us + // something + if new_status != status { + return (new_status, new_gas, new_retdata) + } + } + ); + + (status, remaining_gas, retdata) + } + + fn create( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CreateInputs, + ) -> (Return, Option
, Gas, Bytes) { + call_inspectors!( + inspector, + [&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes], + { + let (status, addr, gas, retdata) = inspector.create(data, call); + + // Allow inspectors to exit early + if status != Return::Continue { + return (status, addr, gas, retdata) + } + } + ); + + (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) + } + + fn create_end( + &mut self, + data: &mut EVMData<'_, DB>, + call: &CreateInputs, + status: Return, + address: Option
, + remaining_gas: Gas, + retdata: Bytes, + ) -> (Return, Option
, Gas, Bytes) { + call_inspectors!( + inspector, + [&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes], + { + let (new_status, new_address, new_gas, new_retdata) = inspector.create_end( + data, + call, + status, + address, + remaining_gas, + retdata.clone(), + ); + + if new_status != status { + return (new_status, new_address, new_gas, new_retdata) + } + } + ); + + (status, address, remaining_gas, retdata) + } + + fn selfdestruct(&mut self) { + call_inspectors!( + inspector, + [&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes], + { + Inspector::::selfdestruct(inspector); + } + ); + } +} diff --git a/evm/src/executor/inspector/tracer.rs b/evm/src/executor/inspector/tracer.rs new file mode 100644 index 000000000000..2d7c951717e8 --- /dev/null +++ b/evm/src/executor/inspector/tracer.rs @@ -0,0 +1,153 @@ +use crate::{ + executor::{ + inspector::utils::{gas_used, get_create_address}, + HARDHAT_CONSOLE_ADDRESS, + }, + trace::{ + CallTrace, CallTraceArena, LogCallOrder, RawOrDecodedCall, RawOrDecodedLog, + RawOrDecodedReturnData, + }, +}; +use bytes::Bytes; +use ethers::{ + abi::RawLog, + types::{Address, H256, U256}, +}; +use revm::{return_ok, CallInputs, CreateInputs, Database, EVMData, Gas, Inspector, Return}; + +/// An inspector that collects call traces. +#[derive(Default, Debug)] +pub struct Tracer { + pub trace_stack: Vec, + pub traces: CallTraceArena, +} + +impl Tracer { + pub fn start_trace( + &mut self, + depth: usize, + address: Address, + data: Vec, + value: U256, + created: bool, + ) { + self.trace_stack.push(self.traces.push_trace( + 0, + CallTrace { + depth, + address, + created, + data: RawOrDecodedCall::Raw(data), + value, + ..Default::default() + }, + )); + } + + pub fn fill_trace(&mut self, success: bool, cost: u64, output: Vec) { + let trace = &mut self.traces.arena + [self.trace_stack.pop().expect("more traces were filled than started")] + .trace; + trace.success = success; + trace.gas_cost = cost; + trace.output = RawOrDecodedReturnData::Raw(output); + } +} + +impl Inspector for Tracer +where + DB: Database, +{ + fn call( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CallInputs, + _: bool, + ) -> (Return, Gas, Bytes) { + if call.contract != HARDHAT_CONSOLE_ADDRESS { + self.start_trace( + data.subroutine.depth() as usize, + call.contract, + call.input.to_vec(), + call.transfer.value, + false, + ); + } + + (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + } + + fn log(&mut self, _: &mut EVMData<'_, DB>, _: &Address, topics: &[H256], data: &Bytes) { + let node = &mut self.traces.arena[*self.trace_stack.last().expect("no ongoing trace")]; + node.ordering.push(LogCallOrder::Log(node.logs.len())); + node.logs + .push(RawOrDecodedLog::Raw(RawLog { topics: topics.to_vec(), data: data.to_vec() })); + } + + fn call_end( + &mut self, + data: &mut EVMData<'_, DB>, + call: &CallInputs, + gas: Gas, + status: Return, + retdata: Bytes, + _: bool, + ) -> (Return, Gas, Bytes) { + if call.contract != HARDHAT_CONSOLE_ADDRESS { + self.fill_trace( + matches!(status, return_ok!()), + gas_used(data.env.cfg.spec_id, gas.spend(), gas.refunded() as u64), + retdata.to_vec(), + ); + } + + (status, gas, retdata) + } + + fn create( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CreateInputs, + ) -> (Return, Option
, Gas, Bytes) { + // TODO: Does this increase gas cost? + data.subroutine.load_account(call.caller, data.db); + let nonce = data.subroutine.account(call.caller).info.nonce; + self.start_trace( + data.subroutine.depth() as usize, + get_create_address(call, nonce), + call.init_code.to_vec(), + call.value, + true, + ); + + (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) + } + + fn create_end( + &mut self, + data: &mut EVMData<'_, DB>, + _: &CreateInputs, + status: Return, + address: Option
, + gas: Gas, + retdata: Bytes, + ) -> (Return, Option
, Gas, Bytes) { + let code = match address { + Some(address) => data + .subroutine + .account(address) + .info + .code + .as_ref() + .map_or(vec![], |code| code.to_vec()), + None => vec![], + }; + self.fill_trace( + matches!(status, return_ok!()), + gas_used(data.env.cfg.spec_id, gas.spend(), gas.refunded() as u64), + code, + ); + + (status, address, gas, retdata) + } +} diff --git a/evm/src/executor/inspector/utils.rs b/evm/src/executor/inspector/utils.rs new file mode 100644 index 000000000000..5ea3a39e8732 --- /dev/null +++ b/evm/src/executor/inspector/utils.rs @@ -0,0 +1,36 @@ +use ethers::{ + types::Address, + utils::{get_contract_address, get_create2_address}, +}; +use revm::{CreateInputs, CreateScheme, SpecId}; + +/// Returns [Return::Continue] on an error, discarding the error. +/// +/// Useful for inspectors that read state that might be invalid, but do not want to emit +/// appropriate errors themselves, instead opting to continue. +macro_rules! try_or_continue { + ($e:expr) => { + match $e { + Ok(v) => v, + Err(_) => return Return::Continue, + } + }; +} + +/// Get the address of a contract creation +pub fn get_create_address(call: &CreateInputs, nonce: u64) -> Address { + match call.scheme { + CreateScheme::Create => get_contract_address(call.caller, nonce), + CreateScheme::Create2 { salt } => { + let mut buffer: [u8; 4 * 8] = [0; 4 * 8]; + salt.to_big_endian(&mut buffer); + get_create2_address(call.caller, buffer, call.init_code.clone()) + } + } +} + +/// Get the gas used, accounting for refunds +pub fn gas_used(spec: SpecId, spent: u64, refunded: u64) -> u64 { + let refund_quotient = if SpecId::enabled(spec, SpecId::LONDON) { 5 } else { 2 }; + spent - (refunded).min(spent / refund_quotient) +} diff --git a/evm/src/executor/mod.rs b/evm/src/executor/mod.rs new file mode 100644 index 000000000000..f9c7c3be051d --- /dev/null +++ b/evm/src/executor/mod.rs @@ -0,0 +1,492 @@ +/// ABIs used internally in the executor +pub mod abi; +pub use abi::{ + patch_hardhat_console_selector, HardhatConsoleCalls, CHEATCODE_ADDRESS, CONSOLE_ABI, + HARDHAT_CONSOLE_ABI, HARDHAT_CONSOLE_ADDRESS, +}; + +/// Executor configuration +pub mod opts; + +/// Executor inspectors +pub mod inspector; + +/// Forking provider +pub mod fork; + +/// Executor builder +pub mod builder; +pub use builder::{ExecutorBuilder, Fork}; + +/// Executor EVM spec identifiers +pub use revm::SpecId; + +/// Executor database trait +pub use revm::db::DatabaseRef; + +use self::inspector::{InspectorData, InspectorStackConfig}; +use crate::{debug::DebugArena, trace::CallTraceArena, CALLER}; +use bytes::Bytes; +use ethers::{ + abi::{Abi, Detokenize, RawLog, Tokenize}, + prelude::{decode_function_data, encode_function_data, Address, U256}, +}; +use eyre::Result; +use foundry_utils::IntoFunction; +use hashbrown::HashMap; +use revm::{ + db::{CacheDB, DatabaseCommit, EmptyDB}, + return_ok, Account, BlockEnv, CreateScheme, Env, Return, TransactOut, TransactTo, TxEnv, EVM, +}; +use std::collections::BTreeMap; + +/// A mapping of addresses to their changed state. +pub type StateChangeset = HashMap; + +#[derive(thiserror::Error, Debug)] +pub enum EvmError { + /// Error which occurred during execution of a transaction + #[error("Execution reverted: {reason} (gas: {gas})")] + Execution { + reverted: bool, + reason: String, + gas: u64, + stipend: u64, + logs: Vec, + traces: Option, + debug: Option, + labels: BTreeMap, + state_changeset: Option, + }, + /// Error which occurred during ABI encoding/decoding + #[error(transparent)] + AbiError(#[from] ethers::contract::AbiError), + /// Any other error. + #[error(transparent)] + Eyre(#[from] eyre::Error), +} + +/// The result of a deployment. +#[derive(Debug)] +pub struct DeployResult { + /// The address of the deployed contract + pub address: Address, + /// The gas cost of the deployment + pub gas: u64, + /// The logs emitted during the deployment + pub logs: Vec, + /// The traces of the deployment + pub traces: Option, + /// The debug nodes of the call + pub debug: Option, +} + +/// The result of a call. +#[derive(Debug)] +pub struct CallResult { + /// Whether the call reverted or not + pub reverted: bool, + /// The decoded result of the call + pub result: D, + /// The gas used for the call + pub gas: u64, + /// The initial gas stipend for the transaction + pub stipend: u64, + /// The logs emitted during the call + pub logs: Vec, + /// The labels assigned to addresses during the call + pub labels: BTreeMap, + /// The traces of the call + pub traces: Option, + /// The debug nodes of the call + pub debug: Option, + /// The changeset of the state. + /// + /// This is only present if the changed state was not committed to the database (i.e. if you + /// used `call` and `call_raw` not `call_committing` or `call_raw_committing`). + pub state_changeset: Option, +} + +/// The result of a raw call. +#[derive(Debug)] +pub struct RawCallResult { + /// The status of the call + status: Return, + /// Whether the call reverted or not + pub reverted: bool, + /// The raw result of the call + pub result: Bytes, + /// The gas used for the call + pub gas: u64, + /// The initial gas stipend for the transaction + pub stipend: u64, + /// The logs emitted during the call + pub logs: Vec, + /// The labels assigned to addresses during the call + pub labels: BTreeMap, + /// The traces of the call + pub traces: Option, + /// The debug nodes of the call + pub debug: Option, + /// The changeset of the state. + /// + /// This is only present if the changed state was not committed to the database (i.e. if you + /// used `call` and `call_raw` not `call_committing` or `call_raw_committing`). + pub state_changeset: Option, +} + +impl Default for RawCallResult { + fn default() -> Self { + Self { + status: Return::Continue, + reverted: false, + result: Bytes::new(), + gas: 0, + stipend: 0, + logs: Vec::new(), + labels: BTreeMap::new(), + traces: None, + debug: None, + state_changeset: None, + } + } +} + +pub struct Executor { + // Note: We do not store an EVM here, since we are really + // only interested in the database. REVM's `EVM` is a thin + // wrapper around spawning a new EVM on every call anyway, + // so the performance difference should be negligible. + // + // Also, if we stored the VM here we would still need to + // take `&mut self` when we are not committing to the database, since + // we need to set `evm.env`. + pub(crate) db: CacheDB, + env: Env, + inspector_config: InspectorStackConfig, +} + +impl Executor +where + DB: DatabaseRef, +{ + pub fn new(inner_db: DB, env: Env, inspector_config: InspectorStackConfig) -> Self { + let mut db = CacheDB::new(inner_db); + + // Need to create a non-empty contract on the cheatcodes address so `extcodesize` checks + // does not fail + db.insert_cache( + CHEATCODE_ADDRESS, + revm::AccountInfo { code: Some(Bytes::from_static(&[1])), ..Default::default() }, + ); + + Executor { db, env, inspector_config } + } + + /// Set the balance of an account. + pub fn set_balance(&mut self, address: Address, amount: U256) { + let mut account = self.db.basic(address); + account.balance = amount; + + self.db.insert_cache(address, account); + } + + /// Gets the balance of an account + pub fn get_balance(&self, address: Address) -> U256 { + self.db.basic(address).balance + } + + /// Set the nonce of an account. + pub fn set_nonce(&mut self, address: Address, nonce: u64) { + let mut account = self.db.basic(address); + account.nonce = nonce; + + self.db.insert_cache(address, account); + } + + /// Calls the `setUp()` function on a contract. + pub fn setup(&mut self, address: Address) -> std::result::Result, EvmError> { + self.call_committing::<(), _, _>(*CALLER, address, "setUp()", (), 0.into(), None) + } + + /// Performs a call to an account on the current state of the VM. + /// + /// The state after the call is persisted. + pub fn call_committing( + &mut self, + from: Address, + to: Address, + func: F, + args: T, + value: U256, + abi: Option<&Abi>, + ) -> std::result::Result, EvmError> { + let func = func.into(); + let calldata = Bytes::from(encode_function_data(&func, args)?.to_vec()); + let RawCallResult { + result, + status, + reverted, + gas, + stipend, + logs, + labels, + traces, + debug, + state_changeset, + } = self.call_raw_committing(from, to, calldata, value)?; + match status { + return_ok!() => { + let result = decode_function_data(&func, result, false)?; + Ok(CallResult { + reverted, + result, + gas, + stipend, + logs, + labels, + traces, + debug, + state_changeset, + }) + } + _ => { + let reason = foundry_utils::decode_revert(result.as_ref(), abi) + .unwrap_or_else(|_| format!("{:?}", status)); + Err(EvmError::Execution { + reverted, + reason, + gas, + stipend, + logs, + traces, + debug, + labels, + state_changeset, + }) + } + } + } + + /// Performs a raw call to an account on the current state of the VM. + /// + /// The state after the call is persisted. + pub fn call_raw_committing( + &mut self, + from: Address, + to: Address, + calldata: Bytes, + value: U256, + ) -> Result { + let stipend = stipend(&calldata, self.env.cfg.spec_id); + + // Build VM + let mut evm = EVM::new(); + evm.env = self.build_env(from, TransactTo::Call(to), calldata, value); + evm.database(&mut self.db); + + // Run the call + let mut inspector = self.inspector_config.stack(); + let (status, out, gas, _) = evm.inspect_commit(&mut inspector); + let result = match out { + TransactOut::Call(data) => data, + _ => Bytes::default(), + }; + + // Persist the changed block environment + self.inspector_config.block = evm.env.block.clone(); + + let InspectorData { logs, labels, traces, debug } = inspector.collect_inspector_states(); + Ok(RawCallResult { + status, + reverted: !matches!(status, return_ok!()), + result, + gas, + stipend, + logs: logs.to_vec(), + labels, + traces, + debug, + state_changeset: None, + }) + } + + /// Performs a call to an account on the current state of the VM. + /// + /// The state after the call is not persisted. + pub fn call( + &self, + from: Address, + to: Address, + func: F, + args: T, + value: U256, + abi: Option<&Abi>, + ) -> std::result::Result, EvmError> { + let func = func.into(); + let calldata = Bytes::from(encode_function_data(&func, args)?.to_vec()); + let RawCallResult { + result, + status, + reverted, + gas, + stipend, + logs, + labels, + traces, + debug, + state_changeset, + } = self.call_raw(from, to, calldata, value)?; + match status { + return_ok!() => { + let result = decode_function_data(&func, result, false)?; + Ok(CallResult { + reverted, + result, + gas, + stipend, + logs, + labels, + traces, + debug, + state_changeset, + }) + } + _ => { + let reason = foundry_utils::decode_revert(result.as_ref(), abi) + .unwrap_or_else(|_| format!("{:?}", status)); + Err(EvmError::Execution { + reverted, + reason, + gas, + stipend, + logs, + traces, + debug, + labels, + state_changeset, + }) + } + } + } + + /// Performs a raw call to an account on the current state of the VM. + /// + /// The state after the call is not persisted. + pub fn call_raw( + &self, + from: Address, + to: Address, + calldata: Bytes, + value: U256, + ) -> Result { + let stipend = stipend(&calldata, self.env.cfg.spec_id); + + // Build VM + let mut evm = EVM::new(); + evm.env = self.build_env(from, TransactTo::Call(to), calldata, value); + evm.database(&self.db); + + // Run the call + let mut inspector = self.inspector_config.stack(); + let (status, out, gas, state_changeset, _) = evm.inspect_ref(&mut inspector); + let result = match out { + TransactOut::Call(data) => data, + _ => Bytes::default(), + }; + + let InspectorData { logs, labels, traces, debug } = inspector.collect_inspector_states(); + Ok(RawCallResult { + status, + reverted: !matches!(status, return_ok!()), + result, + gas, + stipend, + logs: logs.to_vec(), + labels, + traces, + debug, + state_changeset: Some(state_changeset), + }) + } + + /// Deploys a contract and commits the new state to the underlying database. + pub fn deploy(&mut self, from: Address, code: Bytes, value: U256) -> Result { + let mut evm = EVM::new(); + evm.env = self.build_env(from, TransactTo::Create(CreateScheme::Create), code, value); + evm.database(&mut self.db); + + let mut inspector = self.inspector_config.stack(); + let (status, out, gas, _) = evm.inspect_commit(&mut inspector); + let address = match out { + TransactOut::Create(_, Some(addr)) => addr, + // TODO: We should have better error handling logic in the test runner + // regarding deployments in general + _ => eyre::bail!("deployment failed: {:?}", status), + }; + let InspectorData { logs, traces, debug, .. } = inspector.collect_inspector_states(); + + Ok(DeployResult { address, gas, logs, traces, debug }) + } + + /// Check if a call to a test contract was successful. + /// + /// This function checks both the VM status of the call and DSTest's `failed`. + /// + /// DSTest will not revert inside its `assertEq`-like functions which allows + /// to test multiple assertions in 1 test function while also preserving logs. + /// + /// Instead it sets `failed` to `true` which we must check. + pub fn is_success( + &self, + address: Address, + reverted: bool, + state_changeset: StateChangeset, + should_fail: bool, + ) -> bool { + // Construct a new VM with the state changeset + let mut db = CacheDB::new(EmptyDB()); + db.insert_cache(address, self.db.basic(address)); + db.commit(state_changeset); + let executor = Executor::new(db, self.env.clone(), self.inspector_config.clone()); + + let mut success = !reverted; + if success { + // Check if a DSTest assertion failed + let call = + executor.call::(*CALLER, address, "failed()(bool)", (), 0.into(), None); + + if let Ok(CallResult { result: failed, .. }) = call { + success = !failed; + } + } + + should_fail ^ success + } + + fn build_env(&self, caller: Address, transact_to: TransactTo, data: Bytes, value: U256) -> Env { + Env { + cfg: self.env.cfg.clone(), + // We always set the gas price to 0 so we can execute the transaction regardless of + // network conditions - the actual gas price is kept in `self.block` and is applied by + // the cheatcode handler if it is enabled + block: BlockEnv { basefee: 0.into(), ..self.env.block.clone() }, + tx: TxEnv { + caller, + transact_to, + data, + value, + // As above, we set the gas price to 0. + gas_price: 0.into(), + gas_priority_fee: None, + ..self.env.tx.clone() + }, + } + } +} + +/// Calculates the initial gas stipend for a transaction +fn stipend(calldata: &[u8], spec: SpecId) -> u64 { + let non_zero_data_cost = if SpecId::enabled(spec, SpecId::ISTANBUL) { 16 } else { 68 }; + calldata.iter().fold(21000, |sum, byte| sum + if *byte == 0 { 4 } else { non_zero_data_cost }) +} diff --git a/evm/src/executor/opts.rs b/evm/src/executor/opts.rs new file mode 100644 index 000000000000..67d5ea9cddbc --- /dev/null +++ b/evm/src/executor/opts.rs @@ -0,0 +1,134 @@ +use ethers::{ + providers::{Middleware, Provider}, + types::{Address, U256}, +}; +use foundry_utils::RuntimeOrHandle; +use revm::{BlockEnv, CfgEnv, SpecId, TxEnv}; +use serde::{Deserialize, Serialize}; + +use super::fork::environment; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct EvmOpts { + #[serde(flatten)] + pub env: Env, + + /// fetch state over a remote instead of starting from empty state + #[serde(rename = "eth_rpc_url")] + pub fork_url: Option, + + /// pins the block number for the state fork + pub fork_block_number: Option, + + /// Disables storage caching entirely. + pub no_storage_caching: bool, + + /// the initial balance of each deployed test contract + pub initial_balance: U256, + + /// the address which will be executing all tests + pub sender: Address, + + /// enables the FFI cheatcode + pub ffi: bool, + + /// Verbosity mode of EVM output as number of occurences + pub verbosity: u8, +} + +impl EvmOpts { + pub fn evm_env(&self) -> revm::Env { + if let Some(ref fork_url) = self.fork_url { + let rt = RuntimeOrHandle::new(); + let provider = + Provider::try_from(fork_url.as_str()).expect("could not instantiated provider"); + let fut = + environment(&provider, self.env.chain_id, self.fork_block_number, self.sender); + match rt { + RuntimeOrHandle::Runtime(runtime) => runtime.block_on(fut), + RuntimeOrHandle::Handle(handle) => handle.block_on(fut), + } + .expect("could not instantiate forked environment") + } else { + revm::Env { + block: BlockEnv { + number: self.env.block_number.into(), + coinbase: self.env.block_coinbase, + timestamp: self.env.block_timestamp.into(), + difficulty: self.env.block_difficulty.into(), + basefee: self.env.block_base_fee_per_gas.into(), + gas_limit: self.env.block_gas_limit.unwrap_or(self.env.gas_limit).into(), + }, + cfg: CfgEnv { + chain_id: self.env.chain_id.unwrap_or(99).into(), + spec_id: SpecId::LONDON, + perf_all_precompiles_have_balance: false, + }, + tx: TxEnv { + gas_price: self.env.gas_price.into(), + gas_limit: self.env.block_gas_limit.unwrap_or(self.env.gas_limit), + caller: self.sender, + ..Default::default() + }, + } + } + } + + /// Returns the configured chain id, which will be + /// - the value of `chain_id` if set + /// - mainnet if `fork_url` contains "mainnet" + /// - the chain if `fork_url` is set and the endpoints returned its chain id successfully + /// - mainnet otherwise + pub fn get_chain_id(&self) -> u64 { + use ethers::types::Chain; + if let Some(id) = self.env.chain_id { + return id + } + if let Some(ref url) = self.fork_url { + if url.contains("mainnet") { + tracing::trace!("auto detected mainnet chain from url {}", url); + return Chain::Mainnet as u64 + } + let provider = Provider::try_from(url.as_str()) + .unwrap_or_else(|_| panic!("Failed to establish provider to {}", url)); + + if let Ok(id) = foundry_utils::RuntimeOrHandle::new().block_on(provider.get_chainid()) { + return id.as_u64() + } + } + Chain::Mainnet as u64 + } +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct Env { + /// the block gas limit + pub gas_limit: u64, + + /// the chainid opcode value + pub chain_id: Option, + + /// the tx.gasprice value during EVM execution + pub gas_price: u64, + + /// the base fee in a block + pub block_base_fee_per_gas: u64, + + /// the tx.origin value during EVM execution + pub tx_origin: Address, + + /// the block.coinbase value during EVM execution + pub block_coinbase: Address, + + /// the block.timestamp value during EVM execution + pub block_timestamp: u64, + + /// the block.number value during EVM execution" + pub block_number: u64, + + /// the block.difficulty value during EVM execution + pub block_difficulty: u64, + + /// the block.gaslimit value during EVM execution + pub block_gas_limit: Option, +} diff --git a/evm/src/fuzz/mod.rs b/evm/src/fuzz/mod.rs new file mode 100644 index 000000000000..782d0120d9a8 --- /dev/null +++ b/evm/src/fuzz/mod.rs @@ -0,0 +1,275 @@ +mod strategies; + +pub use proptest::test_runner::{Config as FuzzConfig, Reason}; + +use crate::{ + executor::{Executor, RawCallResult}, + trace::CallTraceArena, +}; +use ethers::{ + abi::{Abi, Function, RawLog, Token}, + types::{Address, Bytes}, +}; +use proptest::test_runner::{TestCaseError, TestError, TestRunner}; +use revm::db::DatabaseRef; +use serde::{Deserialize, Serialize}; +use std::{cell::RefCell, collections::BTreeMap, fmt}; +use strategies::{ + build_initial_state, collect_state_from_call, fuzz_calldata, fuzz_calldata_from_state, + EvmFuzzState, +}; + +/// Magic return code for the `assume` cheatcode +pub const ASSUME_MAGIC_RETURN_CODE: &[u8] = b"FOUNDRY::ASSUME"; + +/// Wrapper around an [`Executor`] which provides fuzzing support using [`proptest`](https://docs.rs/proptest/1.0.0/proptest/). +/// +/// After instantiation, calling `fuzz` will proceed to hammer the deployed smart contract with +/// inputs, until it finds a counterexample. The provided [`TestRunner`] contains all the +/// configuration which can be overridden via [environment variables](https://docs.rs/proptest/1.0.0/proptest/test_runner/struct.Config.html) +pub struct FuzzedExecutor<'a, DB: DatabaseRef> { + /// The VM + executor: &'a Executor, + /// The fuzzer + runner: TestRunner, + /// The account that calls tests + sender: Address, +} + +impl<'a, DB> FuzzedExecutor<'a, DB> +where + DB: DatabaseRef, +{ + /// Instantiates a fuzzed executor given a testrunner + pub fn new(executor: &'a Executor, runner: TestRunner, sender: Address) -> Self { + Self { executor, runner, sender } + } + + /// Fuzzes the provided function, assuming it is available at the contract at `address` + /// If `should_fail` is set to `true`, then it will stop only when there's a success + /// test case. + /// + /// Returns a list of all the consumed gas and calldata of every fuzz case + pub fn fuzz( + &self, + func: &Function, + address: Address, + should_fail: bool, + errors: Option<&Abi>, + ) -> FuzzTestResult { + // Stores the consumed gas and calldata of every successful fuzz call + let cases: RefCell> = RefCell::new(Default::default()); + + // Stores the result and calldata of the last failed call, if any. + let counterexample: RefCell<(Bytes, RawCallResult)> = RefCell::new(Default::default()); + + // Stores fuzz state for use with [fuzz_calldata_from_state] + let state: EvmFuzzState = build_initial_state(&self.executor.db); + + // TODO: We should have a `FuzzerOpts` struct where we can configure the fuzzer. When we + // have that, we should add a way to configure strategy weights + let strat = proptest::strategy::Union::new_weighted(vec![ + (60, fuzz_calldata(func.clone())), + (40, fuzz_calldata_from_state(func.clone(), state.clone())), + ]); + tracing::debug!(func = ?func.name, should_fail, "fuzzing"); + let run_result = self.runner.clone().run(&strat, |calldata| { + let call = self + .executor + .call_raw(self.sender, address, calldata.0.clone(), 0.into()) + .expect("could not make raw evm call"); + let state_changeset = + call.state_changeset.as_ref().expect("we should have a state changeset"); + + // Build fuzzer state + collect_state_from_call(&call.logs, state_changeset, state.clone()); + + // When assume cheat code is triggered return a special string "FOUNDRY::ASSUME" + if call.result.as_ref() == ASSUME_MAGIC_RETURN_CODE { + return Err(TestCaseError::reject("ASSUME: Too many rejects")) + } + + let success = self.executor.is_success( + address, + call.reverted, + state_changeset.clone(), + should_fail, + ); + + if success { + cases.borrow_mut().push(FuzzCase { + calldata, + gas: call.gas, + stipend: call.stipend, + }); + Ok(()) + } else { + // We cannot use the calldata returned by the test runner in `TestError::Fail`, + // since that input represents the last run case, which may not correspond with our + // failure - when a fuzz case fails, proptest will try to run at least one more + // case to find a minimal failure case. + *counterexample.borrow_mut() = (calldata, call); + Err(TestCaseError::fail( + match foundry_utils::decode_revert( + counterexample.borrow().1.result.as_ref(), + errors, + ) { + Ok(e) => e, + Err(_) => "".to_string(), + }, + )) + } + }); + + let (calldata, call) = counterexample.into_inner(); + let mut result = FuzzTestResult { + cases: FuzzedCases::new(cases.into_inner()), + success: run_result.is_ok(), + reason: None, + counterexample: None, + logs: call.logs, + traces: call.traces, + labeled_addresses: call.labels, + }; + + match run_result { + Err(TestError::Abort(reason)) => { + result.reason = Some(reason.to_string()); + } + Err(TestError::Fail(reason, _)) => { + let reason = reason.to_string(); + result.reason = if reason.is_empty() { None } else { Some(reason) }; + + let args = func + .decode_input(&calldata.as_ref()[4..]) + .expect("could not decode fuzzer inputs"); + result.counterexample = Some(CounterExample { calldata, args }); + } + _ => (), + } + + result + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CounterExample { + pub calldata: Bytes, + + #[serde(skip)] + pub args: Vec, +} + +impl fmt::Display for CounterExample { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let args = foundry_utils::format_tokens(&self.args).collect::>().join(", "); + write!(f, "calldata=0x{}, args=[{}]", hex::encode(&self.calldata), args) + } +} + +/// The outcome of a fuzz test +#[derive(Debug)] +pub struct FuzzTestResult { + /// Every successful fuzz test case + pub cases: FuzzedCases, + + /// Whether the test case was successful. This means that the transaction executed + /// properly, or that there was a revert and that the test was expected to fail + /// (prefixed with `testFail`) + pub success: bool, + + /// If there was a revert, this field will be populated. Note that the test can + /// still be successful (i.e self.success == true) when it's expected to fail. + pub reason: Option, + + /// Minimal reproduction test case for failing fuzz tests + pub counterexample: Option, + + /// Any captured & parsed as strings logs along the test's execution which should + /// be printed to the user. + pub logs: Vec, + + /// Traces + pub traces: Option, + + /// Labeled addresses + pub labeled_addresses: BTreeMap, +} + +/// Container type for all successful test cases +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(transparent)] +pub struct FuzzedCases { + cases: Vec, +} + +impl FuzzedCases { + pub fn new(mut cases: Vec) -> Self { + cases.sort_by_key(|c| c.gas); + Self { cases } + } + + pub fn cases(&self) -> &[FuzzCase] { + &self.cases + } + + pub fn into_cases(self) -> Vec { + self.cases + } + + /// Returns the median gas of all test cases + pub fn median_gas(&self, with_stipend: bool) -> u64 { + let mid = self.cases.len() / 2; + self.cases + .get(mid) + .map(|c| if with_stipend { c.gas } else { c.gas - c.stipend }) + .unwrap_or_default() + } + + /// Returns the average gas use of all test cases + pub fn mean_gas(&self, with_stipend: bool) -> u64 { + if self.cases.is_empty() { + return 0 + } + + (self + .cases + .iter() + .map(|c| if with_stipend { c.gas as u128 } else { (c.gas - c.stipend) as u128 }) + .sum::() / + self.cases.len() as u128) as u64 + } + + /// Returns the case with the highest gas usage + pub fn highest(&self) -> Option<&FuzzCase> { + self.cases.last() + } + + /// Returns the case with the lowest gas usage + pub fn lowest(&self) -> Option<&FuzzCase> { + self.cases.first() + } + + /// Returns the highest amount of gas spent on a fuzz case + pub fn highest_gas(&self, with_stipend: bool) -> u64 { + self.highest() + .map(|c| if with_stipend { c.gas } else { c.gas - c.stipend }) + .unwrap_or_default() + } + + /// Returns the lowest amount of gas spent on a fuzz case + pub fn lowest_gas(&self) -> u64 { + self.lowest().map(|c| c.gas).unwrap_or_default() + } +} + +/// Data of a single fuzz test case +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FuzzCase { + /// The calldata used for this fuzz test + pub calldata: Bytes, + /// Consumed gas + pub gas: u64, + /// The initial gas stipend for the transaction + pub stipend: u64, +} diff --git a/evm/src/fuzz/strategies/calldata.rs b/evm/src/fuzz/strategies/calldata.rs new file mode 100644 index 000000000000..be9e24a7289b --- /dev/null +++ b/evm/src/fuzz/strategies/calldata.rs @@ -0,0 +1,18 @@ +use super::fuzz_param; +use ethers::{abi::Function, types::Bytes}; +use proptest::prelude::{BoxedStrategy, Strategy}; + +/// Given a function, it returns a strategy which generates valid calldata +/// for that function's input types. +pub fn fuzz_calldata(func: Function) -> BoxedStrategy { + // We need to compose all the strategies generated for each parameter in all + // possible combinations + let strats = func.inputs.iter().map(|input| fuzz_param(&input.kind)).collect::>(); + + strats + .prop_map(move |tokens| { + tracing::trace!(input = ?tokens); + func.encode_input(&tokens).unwrap().into() + }) + .boxed() +} diff --git a/evm/src/fuzz/strategies/mod.rs b/evm/src/fuzz/strategies/mod.rs new file mode 100644 index 000000000000..4c5d31d6835b --- /dev/null +++ b/evm/src/fuzz/strategies/mod.rs @@ -0,0 +1,13 @@ +mod uint; +pub use uint::UintStrategy; + +mod param; +pub use param::{fuzz_param, fuzz_param_from_state}; + +mod calldata; +pub use calldata::fuzz_calldata; + +mod state; +pub use state::{ + build_initial_state, collect_state_from_call, fuzz_calldata_from_state, EvmFuzzState, +}; diff --git a/evm/src/fuzz/strategies/param.rs b/evm/src/fuzz/strategies/param.rs new file mode 100644 index 000000000000..e86b15e85c86 --- /dev/null +++ b/evm/src/fuzz/strategies/param.rs @@ -0,0 +1,142 @@ +use ethers::{ + abi::{ParamType, Token, Tokenizable}, + types::{Address, Bytes, I256, U256}, +}; +use proptest::prelude::*; + +use super::state::EvmFuzzState; + +/// The max length of arrays we fuzz for is 256. +pub const MAX_ARRAY_LEN: usize = 256; + +/// Given a parameter type, returns a strategy for generating values for that type. +/// +/// Works with ABI Encoder v2 tuples. +pub fn fuzz_param(param: &ParamType) -> impl Strategy { + match param { + ParamType::Address => { + // The key to making this work is the `boxed()` call which type erases everything + // https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html + any::<[u8; 20]>().prop_map(|x| Address::from_slice(&x).into_token()).boxed() + } + ParamType::Bytes => any::>().prop_map(|x| Bytes::from(x).into_token()).boxed(), + // For ints and uints we sample from a U256, then wrap it to the correct size with a + // modulo operation. Note that this introduces modulo bias, but it can be removed with + // rejection sampling if it's determined the bias is too severe. Rejection sampling may + // slow down tests as it resamples bad values, so may want to benchmark the performance + // hit and weigh that against the current bias before implementing + ParamType::Int(n) => match n / 8 { + 32 => any::<[u8; 32]>() + .prop_map(move |x| I256::from_raw(U256::from(&x)).into_token()) + .boxed(), + y @ 1..=31 => any::<[u8; 32]>() + .prop_map(move |x| { + // Generate a uintN in the correct range, then shift it to the range of intN + // by subtracting 2^(N-1) + let uint = U256::from(&x) % U256::from(2).pow(U256::from(y * 8)); + let max_int_plus1 = U256::from(2).pow(U256::from(y * 8 - 1)); + let num = I256::from_raw(uint.overflowing_sub(max_int_plus1).0); + num.into_token() + }) + .boxed(), + _ => panic!("unsupported solidity type int{}", n), + }, + ParamType::Uint(n) => { + super::UintStrategy::new(*n, vec![]).prop_map(|x| x.into_token()).boxed() + } + ParamType::Bool => any::().prop_map(|x| x.into_token()).boxed(), + ParamType::String => any::>() + .prop_map(|x| Token::String(unsafe { std::str::from_utf8_unchecked(&x).to_string() })) + .boxed(), + ParamType::Array(param) => proptest::collection::vec(fuzz_param(param), 0..MAX_ARRAY_LEN) + .prop_map(Token::Array) + .boxed(), + ParamType::FixedBytes(size) => (0..*size as u64) + .map(|_| any::()) + .collect::>() + .prop_map(Token::FixedBytes) + .boxed(), + ParamType::FixedArray(param, size) => (0..*size as u64) + .map(|_| fuzz_param(param).prop_map(|param| param.into_token())) + .collect::>() + .prop_map(Token::FixedArray) + .boxed(), + ParamType::Tuple(params) => { + params.iter().map(fuzz_param).collect::>().prop_map(Token::Tuple).boxed() + } + } +} + +/// Given a parameter type, returns a strategy for generating values for that type, given some EVM +/// fuzz state. +/// +/// Works with ABI Encoder v2 tuples. +pub fn fuzz_param_from_state(param: &ParamType, state: EvmFuzzState) -> BoxedStrategy { + // These are to comply with lifetime requirements + let state_len = state.borrow().len(); + let s = state.clone(); + + // Select a value from the state + let value = any::() + .prop_map(move |index| index.index(state_len)) + .prop_map(move |index| *s.borrow().iter().nth(index).unwrap()); + + // Convert the value based on the parameter type + match param { + ParamType::Address => { + value.prop_map(move |value| Address::from_slice(&value[12..]).into_token()).boxed() + } + ParamType::Bytes => value.prop_map(move |value| Bytes::from(value).into_token()).boxed(), + ParamType::Int(n) => match n / 8 { + 32 => { + value.prop_map(move |value| I256::from_raw(U256::from(value)).into_token()).boxed() + } + y @ 1..=31 => value + .prop_map(move |value| { + // Generate a uintN in the correct range, then shift it to the range of intN + // by subtracting 2^(N-1) + let uint = U256::from(value) % U256::from(2usize).pow(U256::from(y * 8)); + let max_int_plus1 = U256::from(2usize).pow(U256::from(y * 8 - 1)); + let num = I256::from_raw(uint.overflowing_sub(max_int_plus1).0); + num.into_token() + }) + .boxed(), + _ => panic!("unsupported solidity type int{}", n), + }, + ParamType::Uint(n) => match n / 8 { + 32 => value.prop_map(move |value| U256::from(value).into_token()).boxed(), + y @ 1..=31 => value + .prop_map(move |value| { + (U256::from(value) % (U256::from(2usize).pow(U256::from(y * 8)))).into_token() + }) + .boxed(), + _ => panic!("unsupported solidity type uint{}", n), + }, + ParamType::Bool => value.prop_map(move |value| Token::Bool(value[31] == 1)).boxed(), + ParamType::String => value + .prop_map(move |value| { + Token::String(unsafe { std::str::from_utf8_unchecked(&value[..]).to_string() }) + }) + .boxed(), + ParamType::Array(param) => { + proptest::collection::vec(fuzz_param_from_state(param, state), 0..MAX_ARRAY_LEN) + .prop_map(Token::Array) + .boxed() + } + ParamType::FixedBytes(size) => { + let size = *size; + value.prop_map(move |value| Token::FixedBytes(value[32 - size..].to_vec())).boxed() + } + ParamType::FixedArray(param, size) => { + proptest::collection::vec(fuzz_param_from_state(param, state), 0..*size) + .prop_map(Token::FixedArray) + .boxed() + } + ParamType::Tuple(params) => params + .iter() + .map(|p| fuzz_param_from_state(p, state.clone())) + .collect::>() + .prop_map(Token::Tuple) + .boxed(), + } +} diff --git a/evm/src/fuzz/strategies/state.rs b/evm/src/fuzz/strategies/state.rs new file mode 100644 index 000000000000..2ef824cb832f --- /dev/null +++ b/evm/src/fuzz/strategies/state.rs @@ -0,0 +1,151 @@ +use super::fuzz_param_from_state; +use crate::executor::StateChangeset; +use bytes::Bytes; +use ethers::{ + abi::{Function, RawLog}, + types::{H256, U256}, +}; +use proptest::prelude::{BoxedStrategy, Strategy}; +use revm::{ + db::{CacheDB, DatabaseRef}, + opcode, spec_opcode_gas, SpecId, +}; +use std::{cell::RefCell, collections::HashSet, io::Write, rc::Rc}; + +/// A set of arbitrary 32 byte data from the VM used to generate values for the strategy. +/// +/// Wrapped in a shareable container. +pub type EvmFuzzState = Rc>>; + +/// Given a function and some state, it returns a strategy which generated valid calldata for the +/// given function's input types, based on state taken from the EVM. +pub fn fuzz_calldata_from_state( + func: Function, + state: EvmFuzzState, +) -> BoxedStrategy { + let strats = func + .inputs + .iter() + .map(|input| fuzz_param_from_state(&input.kind, state.clone())) + .collect::>(); + + strats + .prop_map(move |tokens| { + tracing::trace!(input = ?tokens); + func.encode_input(&tokens).unwrap().into() + }) + .no_shrink() + .boxed() +} + +/// Builds the initial [EvmFuzzState] from a database. +pub fn build_initial_state(db: &CacheDB) -> EvmFuzzState { + let mut state: HashSet<[u8; 32]> = HashSet::new(); + for (address, storage) in db.storage() { + let info = db.basic(*address); + + // Insert basic account information + state.insert(H256::from(*address).into()); + state.insert(u256_to_h256(info.balance).into()); + state.insert(u256_to_h256(U256::from(info.nonce)).into()); + + // Insert storage + for (slot, value) in storage { + state.insert(u256_to_h256(*slot).into()); + state.insert(u256_to_h256(*value).into()); + } + } + + Rc::new(RefCell::new(state)) +} + +/// Collects state changes from a [StateChangeset] and logs into an [EvmFuzzState]. +pub fn collect_state_from_call( + logs: &[RawLog], + state_changeset: &StateChangeset, + state: EvmFuzzState, +) { + let state = &mut *state.borrow_mut(); + + for (address, account) in state_changeset { + // Insert basic account information + state.insert(H256::from(*address).into()); + state.insert(u256_to_h256(account.info.balance).into()); + state.insert(u256_to_h256(U256::from(account.info.nonce)).into()); + + // Insert storage + for (slot, value) in &account.storage { + state.insert(u256_to_h256(*slot).into()); + state.insert(u256_to_h256(*value).into()); + } + + // Insert push bytes + if let Some(code) = &account.info.code { + for push_byte in collect_push_bytes(code.clone()) { + state.insert(push_byte); + } + } + + // Insert log topics and data + for log in logs { + log.topics.iter().for_each(|topic| { + state.insert(topic.0); + }); + log.data.chunks(32).for_each(|chunk| { + let mut buffer: [u8; 32] = [0; 32]; + let _ = (&mut buffer[..]) + .write(chunk) + .expect("log data chunk was larger than 32 bytes"); + state.insert(buffer); + }); + } + } +} + +/// The maximum number of bytes we will look at in bytecodes to find push bytes (24 KiB). +/// +/// This is to limit the performance impact of fuzz tests that might deploy arbitrarily sized +/// bytecode (as is the case with Solmate). +const PUSH_BYTE_ANALYSIS_LIMIT: usize = 24 * 1024; + +/// Collects all push bytes from the given bytecode. +fn collect_push_bytes(code: Bytes) -> Vec<[u8; 32]> { + let mut bytes: Vec<[u8; 32]> = Vec::new(); + + // We use [SpecId::LATEST] since we do not really care what spec it is - we are not interested + // in gas costs. + let opcode_infos = spec_opcode_gas(SpecId::LATEST); + + let mut i = 0; + while i < code.len().min(PUSH_BYTE_ANALYSIS_LIMIT) { + let op = code[i]; + if opcode_infos[op as usize].is_push { + let push_size = (op - opcode::PUSH1 + 1) as usize; + let push_start = i + 1; + let push_end = push_start + push_size; + + // As a precaution, if a fuzz test deploys malformed bytecode (such as using `CREATE2`) + // this will terminate the loop early. + if push_start > code.len() || push_end > code.len() { + return bytes + } + + let mut buffer: [u8; 32] = [0; 32]; + let _ = (&mut buffer[..]) + .write(&code[push_start..push_end]) + .expect("push was larger than 32 bytes"); + bytes.push(buffer); + i += push_size; + } + i += 1; + } + + bytes +} + +/// Small helper function to convert [U256] into [H256]. +fn u256_to_h256(u: U256) -> H256 { + let mut h = H256::default(); + u.to_little_endian(h.as_mut()); + h +} diff --git a/evm-adapters/src/fuzz/strategies.rs b/evm/src/fuzz/strategies/uint.rs similarity index 98% rename from evm-adapters/src/fuzz/strategies.rs rename to evm/src/fuzz/strategies/uint.rs index 4f2979bf4b48..eb8db2448262 100644 --- a/evm-adapters/src/fuzz/strategies.rs +++ b/evm/src/fuzz/strategies/uint.rs @@ -1,4 +1,4 @@ -use ethers_core::rand::Rng; +use ethers::core::rand::Rng; use proptest::{ strategy::{NewTree, Strategy, ValueTree}, test_runner::TestRunner, @@ -7,7 +7,7 @@ use proptest::{ use ethers::types::U256; /// Value tree for unsigned ints (up to uint256). -/// This is very similar to proptest::BinarySearch +/// This is very similar to [proptest::BinarySearch] pub struct UintValueTree { /// Lower base lo: U256, diff --git a/evm/src/lib.rs b/evm/src/lib.rs new file mode 100644 index 000000000000..22a9cd53d04c --- /dev/null +++ b/evm/src/lib.rs @@ -0,0 +1,22 @@ +/// Decoding helpers +pub mod decode; + +/// Call trace arena, decoding and formatting +pub mod trace; + +/// Debugger data structures +pub mod debug; + +/// Forge test execution backends +pub mod executor; +pub use executor::abi; + +/// Fuzzing wrapper for executors +pub mod fuzz; + +// Re-exports +pub use ethers::types::Address; +pub use hashbrown::HashMap; + +use once_cell::sync::Lazy; +pub static CALLER: Lazy
= Lazy::new(Address::random); diff --git a/evm/src/trace/decoder.rs b/evm/src/trace/decoder.rs new file mode 100644 index 000000000000..e9e443448465 --- /dev/null +++ b/evm/src/trace/decoder.rs @@ -0,0 +1,239 @@ +use super::{ + CallTraceArena, RawOrDecodedCall, RawOrDecodedLog, RawOrDecodedReturnData, TraceIdentifier, +}; +use crate::abi::{CHEATCODE_ADDRESS, CONSOLE_ABI, HEVM_ABI}; +use ethers::{ + abi::{Abi, Address, Event, Function, Token}, + types::H256, +}; +use foundry_utils::format_token; +use std::collections::BTreeMap; + +/// The call trace decoder. +/// +/// The decoder collects address labels and ABIs from any number of [TraceIdentifier]s, which it +/// then uses to decode the call trace. +/// +/// Note that a call trace decoder is required for each new set of traces, since addresses in +/// different sets might overlap. +#[derive(Default, Debug)] +pub struct CallTraceDecoder { + /// Addresses identified to be a specific contract. + /// + /// The values are in the form `":"`. + pub contracts: BTreeMap, + /// Address labels + pub labels: BTreeMap, + /// A mapping of addresses to their known functions + pub functions: BTreeMap<[u8; 4], Vec>, + /// All known events + pub events: BTreeMap, + /// All known errors + pub errors: Abi, +} + +impl CallTraceDecoder { + /// Creates a new call trace decoder. + /// + /// The call trace decoder always knows how to decode calls to the cheatcode address, as well + /// as DSTest-style logs. + pub fn new() -> Self { + Self { + contracts: BTreeMap::new(), + labels: [(CHEATCODE_ADDRESS, "VM".to_string())].into(), + functions: HEVM_ABI + .functions() + .map(|func| (func.short_signature(), vec![func.clone()])) + .collect::>>(), + events: CONSOLE_ABI + .events() + .map(|event| (event.signature(), event.clone())) + .collect::>(), + errors: Abi::default(), + } + } + + /// Creates a new call trace decoder with predetermined address labels. + pub fn new_with_labels(labels: BTreeMap) -> Self { + let mut info = Self::new(); + for (address, label) in labels.into_iter() { + info.labels.insert(address, label); + } + info + } + + /// Identify unknown addresses in the specified call trace using the specified identifier. + /// + /// Unknown contracts are contracts that either lack a label or an ABI. + pub fn identify(&mut self, trace: &CallTraceArena, identifier: &impl TraceIdentifier) { + trace.addresses_iter().for_each(|(address, code)| { + // We only try to identify addresses with missing data + if self.labels.contains_key(address) && self.contracts.contains_key(address) { + return + } + + let (contract, label, abi) = identifier.identify_address(address, code); + if let Some(contract) = contract { + self.contracts.entry(*address).or_insert(contract); + } + + if let Some(label) = label { + self.labels.entry(*address).or_insert(label); + } + + if let Some(abi) = abi { + // Store known functions for the address + abi.functions() + .map(|func| (func.short_signature(), func.clone())) + .for_each(|(sig, func)| self.functions.entry(sig).or_default().push(func)); + + // Flatten events from all ABIs + abi.events().map(|event| (event.signature(), event.clone())).for_each( + |(sig, event)| { + self.events.insert(sig, event); + }, + ); + + // Flatten errors from all ABIs + abi.errors().for_each(|error| { + let entry = self + .errors + .errors + .entry(error.name.clone()) + .or_insert_with(Default::default); + entry.push(error.clone()); + }); + } + }); + } + + pub fn decode(&self, traces: &mut CallTraceArena) { + for node in traces.arena.iter_mut() { + // Set contract name + if let Some(contract) = self.contracts.get(&node.trace.address) { + node.trace.contract = Some(contract.clone()); + } + + // Set label + if let Some(label) = self.labels.get(&node.trace.address) { + node.trace.label = Some(label.clone()); + } + + // Decode call + if let RawOrDecodedCall::Raw(bytes) = &node.trace.data { + if bytes.len() >= 4 { + if let Some(funcs) = self.functions.get(&bytes[0..4]) { + // This is safe because (1) we would not have an entry for the given + // selector if no functions with that selector were added and (2) the same + // selector implies the function has the same name and inputs. + let func = &funcs[0]; + + // Decode inputs + let inputs = if !bytes[4..].is_empty() { + if node.trace.address == CHEATCODE_ADDRESS { + // Try to decode cheatcode inputs in a more custom way + self.decode_cheatcode_inputs(func, bytes).unwrap_or_else(|| { + func.decode_input(&bytes[4..]) + .expect("bad function input decode") + .iter() + .map(|token| self.apply_label(token)) + .collect() + }) + } else { + func.decode_input(&bytes[4..]) + .expect("bad function input decode") + .iter() + .map(|token| self.apply_label(token)) + .collect() + } + } else { + Vec::new() + }; + node.trace.data = RawOrDecodedCall::Decoded(func.name.clone(), inputs); + + if let RawOrDecodedReturnData::Raw(bytes) = &node.trace.output { + if !bytes.is_empty() { + if node.trace.success { + if let Some(tokens) = funcs + .iter() + .find_map(|func| func.decode_output(&bytes[..]).ok()) + { + node.trace.output = RawOrDecodedReturnData::Decoded( + tokens + .iter() + .map(|token| self.apply_label(token)) + .collect::>() + .join(", "), + ); + } + } else if let Ok(decoded_error) = + foundry_utils::decode_revert(&bytes[..], Some(&self.errors)) + { + node.trace.output = RawOrDecodedReturnData::Decoded(format!( + r#""{}""#, + decoded_error + )); + } + } + } + } + } else { + node.trace.data = RawOrDecodedCall::Decoded("fallback".to_string(), Vec::new()); + + if let RawOrDecodedReturnData::Raw(bytes) = &node.trace.output { + if !node.trace.success { + if let Ok(decoded_error) = + foundry_utils::decode_revert(&bytes[..], Some(&self.errors)) + { + node.trace.output = RawOrDecodedReturnData::Decoded(format!( + r#""{}""#, + decoded_error + )); + } + } + } + } + } + + // Decode events + node.logs.iter_mut().for_each(|log| { + if let RawOrDecodedLog::Raw(raw_log) = log { + if let Some(event) = self.events.get(&raw_log.topics[0]) { + if let Ok(decoded) = event.parse_log(raw_log.clone()) { + *log = RawOrDecodedLog::Decoded( + event.name.clone(), + decoded + .params + .into_iter() + .map(|param| (param.name, self.apply_label(¶m.value))) + .collect(), + ) + } + } + } + }); + } + } + + fn apply_label(&self, token: &Token) -> String { + match token { + Token::Address(addr) => { + if let Some(label) = self.labels.get(addr) { + format!("{}: [{:?}]", label, addr) + } else { + format_token(token) + } + } + _ => format_token(token), + } + } + + fn decode_cheatcode_inputs(&self, func: &Function, data: &[u8]) -> Option> { + match func.name.as_str() { + "expectRevert" => foundry_utils::decode_revert(data, Some(&self.errors)) + .ok() + .map(|decoded| vec![decoded]), + _ => None, + } + } +} diff --git a/evm/src/trace/identifier.rs b/evm/src/trace/identifier.rs new file mode 100644 index 000000000000..0d0481de72cf --- /dev/null +++ b/evm/src/trace/identifier.rs @@ -0,0 +1,75 @@ +use ethers::abi::{Abi, Address}; +use std::collections::BTreeMap; + +/// Trace identifiers figure out what ABIs and labels belong to all the addresses of the trace. +pub trait TraceIdentifier { + /// Attempts to identify an address in one or more call traces. + /// + /// The tuple is of the format `(contract, label, abi)`, where `contract` is intended to be of + /// the format `":"`, e.g. `"Foo.json:Foo"`. + fn identify_address( + &self, + address: &Address, + code: Option<&Vec>, + ) -> (Option, Option, Option<&Abi>); +} + +/// The local trace identifier keeps track of addresses that are instances of local contracts. +pub struct LocalTraceIdentifier { + local_contracts: BTreeMap, (String, Abi)>, +} + +impl LocalTraceIdentifier { + pub fn new(known_contracts: &BTreeMap)>) -> Self { + Self { + local_contracts: known_contracts + .iter() + .map(|(name, (abi, runtime_code))| { + (runtime_code.clone(), (name.clone(), abi.clone())) + }) + .collect(), + } + } +} + +impl TraceIdentifier for LocalTraceIdentifier { + fn identify_address( + &self, + _: &Address, + code: Option<&Vec>, + ) -> (Option, Option, Option<&Abi>) { + if let Some(code) = code { + if let Some((_, (name, abi))) = self + .local_contracts + .iter() + .find(|(known_code, _)| diff_score(known_code, code) < 0.1) + { + (Some(name.clone()), Some(name.clone()), Some(abi)) + } else { + (None, None, None) + } + } else { + (None, None, None) + } + } +} + +/// Very simple fuzzy matching of contract bytecode. +/// +/// Will fail for small contracts that are essentially all immutable variables. +fn diff_score(a: &[u8], b: &[u8]) -> f64 { + let cutoff_len = usize::min(a.len(), b.len()); + if cutoff_len == 0 { + return 1.0 + } + + let a = &a[..cutoff_len]; + let b = &b[..cutoff_len]; + let mut diff_chars = 0; + for i in 0..cutoff_len { + if a[i] != b[i] { + diff_chars += 1; + } + } + diff_chars as f64 / cutoff_len as f64 +} diff --git a/evm/src/trace/mod.rs b/evm/src/trace/mod.rs new file mode 100644 index 000000000000..17574b65c20a --- /dev/null +++ b/evm/src/trace/mod.rs @@ -0,0 +1,373 @@ +/// Call trace address identifiers. +/// +/// Identifiers figure out what ABIs and labels belong to all the addresses of the trace. +pub mod identifier; +pub use identifier::TraceIdentifier; + +mod decoder; +pub use decoder::CallTraceDecoder; + +use crate::abi::CHEATCODE_ADDRESS; +use ansi_term::Colour; +use ethers::{ + abi::{Address, RawLog}, + types::U256, +}; +use serde::{Deserialize, Serialize}; +use std::fmt::{self, Write}; + +/// An arena of [CallTraceNode]s +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CallTraceArena { + /// The arena of nodes + pub arena: Vec, +} + +impl Default for CallTraceArena { + fn default() -> Self { + CallTraceArena { arena: vec![Default::default()] } + } +} + +impl CallTraceArena { + /// Pushes a new trace into the arena, returning the trace ID + pub fn push_trace(&mut self, entry: usize, new_trace: CallTrace) -> usize { + match new_trace.depth { + // The entry node, just update it + 0 => { + let node = &mut self.arena[0]; + node.trace.update(new_trace); + 0 + } + // We found the parent node, add the new trace as a child + _ if self.arena[entry].trace.depth == new_trace.depth - 1 => { + let id = self.arena.len(); + + let trace_location = self.arena[entry].children.len(); + self.arena[entry].ordering.push(LogCallOrder::Call(trace_location)); + let node = + CallTraceNode { parent: Some(entry), trace: new_trace, ..Default::default() }; + self.arena.push(node); + self.arena[entry].children.push(id); + + id + } + // We haven't found the parent node, go deeper + _ => self.push_trace( + *self.arena[entry].children.last().expect("Disconnected trace"), + new_trace, + ), + } + } + + pub fn addresses_iter(&self) -> impl Iterator>)> { + self.arena.iter().map(|node| { + let code = if node.trace.created { + if let RawOrDecodedReturnData::Raw(bytes) = &node.trace.output { + Some(bytes) + } else { + None + } + } else { + None + }; + + (&node.trace.address, code) + }) + } +} + +const PIPE: &str = " │ "; +const EDGE: &str = " └─ "; +const BRANCH: &str = " ├─ "; +const CALL: &str = "→ "; +const RETURN: &str = "← "; + +impl fmt::Display for CallTraceArena { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn inner( + arena: &CallTraceArena, + writer: &mut (impl Write + ?Sized), + idx: usize, + left: &str, + child: &str, + ) -> fmt::Result { + let node = &arena.arena[idx]; + + // Display trace header + writeln!(writer, "{}{}", left, node.trace)?; + + // Display logs and subcalls + let left_prefix = format!("{}{}", child, BRANCH); + let right_prefix = format!("{}{}", child, PIPE); + for child in &node.ordering { + match child { + LogCallOrder::Log(index) => { + let mut log = String::new(); + write!(log, "{}", node.logs[*index])?; + + // Prepend our tree structure symbols to each line of the displayed log + log.lines().enumerate().try_for_each(|(i, line)| { + writeln!( + writer, + "{}{}", + if i == 0 { &left_prefix } else { &right_prefix }, + line + ) + })?; + } + LogCallOrder::Call(index) => { + inner(arena, writer, node.children[*index], &left_prefix, &right_prefix)?; + } + } + } + + // Display trace return data + let color = trace_color(&node.trace); + write!(writer, "{}{}", child, EDGE)?; + write!(writer, "{}", color.paint(RETURN))?; + if node.trace.created { + if let RawOrDecodedReturnData::Raw(bytes) = &node.trace.output { + writeln!(writer, "{} bytes of code", bytes.len())?; + } else { + unreachable!("We should never have decoded calldata for contract creations"); + } + } else { + writeln!(writer, "{}", node.trace.output)?; + } + + Ok(()) + } + + inner(self, f, 0, " ", " ") + } +} + +/// A raw or decoded log. +#[derive(Debug, Clone)] +pub enum RawOrDecodedLog { + /// A raw log + Raw(RawLog), + /// A decoded log. + /// + /// The first member of the tuple is the event name, and the second is a vector of decoded + /// parameters. + Decoded(String, Vec<(String, String)>), +} + +impl fmt::Display for RawOrDecodedLog { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RawOrDecodedLog::Raw(log) => { + for (i, topic) in log.topics.iter().enumerate() { + writeln!( + f, + "{:>13}: {}", + if i == 0 { "emit topic 0".to_string() } else { format!("topic {}", i) }, + Colour::Cyan.paint(format!("0x{}", hex::encode(&topic))) + )?; + } + + write!( + f, + " data: {}", + Colour::Cyan.paint(format!("0x{}", hex::encode(&log.data))) + ) + } + RawOrDecodedLog::Decoded(name, params) => { + let params = params + .iter() + .map(|(name, value)| format!("{}: {}", name, value)) + .collect::>() + .join(", "); + + write!(f, "emit {}({})", Colour::Cyan.paint(name.clone()), params) + } + } + } +} + +/// Ordering enum for calls and logs +/// +/// i.e. if Call 0 occurs before Log 0, it will be pushed into the `CallTraceNode`'s ordering before +/// the log. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum LogCallOrder { + Log(usize), + Call(usize), +} + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +/// A node in the arena +pub struct CallTraceNode { + /// Parent node index in the arena + pub parent: Option, + /// Children node indexes in the arena + pub children: Vec, + /// This node's index in the arena + pub idx: usize, + /// The call trace + pub trace: CallTrace, + /// Logs + #[serde(skip)] + pub logs: Vec, + /// Ordering of child calls and logs + pub ordering: Vec, +} + +// TODO: Maybe unify with output +/// Raw or decoded calldata. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum RawOrDecodedCall { + /// Raw calldata + Raw(Vec), + /// Decoded calldata. + /// + /// The first element in the tuple is the function name, and the second element is a vector of + /// decoded parameters. + Decoded(String, Vec), +} + +impl Default for RawOrDecodedCall { + fn default() -> Self { + RawOrDecodedCall::Raw(Vec::new()) + } +} + +/// Raw or decoded return data. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum RawOrDecodedReturnData { + /// Raw return data + Raw(Vec), + /// Decoded return data + Decoded(String), +} + +impl Default for RawOrDecodedReturnData { + fn default() -> Self { + RawOrDecodedReturnData::Raw(Vec::new()) + } +} + +impl fmt::Display for RawOrDecodedReturnData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self { + RawOrDecodedReturnData::Raw(bytes) => { + if bytes.is_empty() { + write!(f, "()") + } else { + write!(f, "0x{}", hex::encode(&bytes)) + } + } + RawOrDecodedReturnData::Decoded(decoded) => write!(f, "{}", decoded.clone()), + } + } +} + +/// A trace of a call. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +pub struct CallTrace { + /// The depth of the call + pub depth: usize, + /// Whether the call was successful + pub success: bool, + /// The name of the contract, if any. + /// + /// The format is `":"` for easy lookup in local contracts. + /// + /// This member is not used by the core call tracing functionality (decoding/displaying). The + /// intended use case is for other components that may want to process traces by specific + /// contracts (e.g. gas reports). + pub contract: Option, + /// The label for the destination address, if any + pub label: Option, + /// The destination address of the call + pub address: Address, + /// Whether the call was a contract creation or not + pub created: bool, + /// The value tranferred in the call + pub value: U256, + /// The calldata for the call, or the init code for contract creations + pub data: RawOrDecodedCall, + /// The return data of the call if this was not a contract creation, otherwise it is the + /// runtime bytecode of the created contract + pub output: RawOrDecodedReturnData, + /// The gas cost of the call + pub gas_cost: u64, +} + +impl CallTrace { + /// Updates a trace given another trace + fn update(&mut self, new_trace: Self) { + self.success = new_trace.success; + self.address = new_trace.address; + self.created = new_trace.created; + self.value = new_trace.value; + self.data = new_trace.data; + self.output = new_trace.output; + self.address = new_trace.address; + self.gas_cost = new_trace.gas_cost; + } +} + +impl fmt::Display for CallTrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.created { + write!( + f, + "[{}] {}{} {}@{:?}", + self.gas_cost, + Colour::Yellow.paint(CALL), + Colour::Yellow.paint("new"), + self.label.as_ref().unwrap_or(&"".to_string()), + self.address + )?; + } else { + let (func, inputs) = match &self.data { + RawOrDecodedCall::Raw(bytes) => { + // We assume that the fallback function (`data.len() < 4`) counts as decoded + // calldata + assert!(bytes.len() >= 4); + (hex::encode(&bytes[0..4]), hex::encode(&bytes[4..])) + } + RawOrDecodedCall::Decoded(func, inputs) => (func.clone(), inputs.join(", ")), + }; + + let color = trace_color(self); + write!( + f, + "[{}] {}::{}{}({})", + self.gas_cost, + color.paint(self.label.as_ref().unwrap_or(&self.address.to_string())), + color.paint(func), + if !self.value.is_zero() { + format!("{{value: {}}}", self.value) + } else { + "".to_string() + }, + inputs + )?; + } + + Ok(()) + } +} + +/// Specifies the kind of trace. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum TraceKind { + Deployment, + Setup, + Execution, +} + +/// Chooses the color of the trace depending on the destination address and status of the call. +fn trace_color(trace: &CallTrace) -> Colour { + if trace.address == CHEATCODE_ADDRESS { + Colour::Blue + } else if trace.success { + Colour::Green + } else { + Colour::Red + } +} diff --git a/evm/test-data/storage.json b/evm/test-data/storage.json new file mode 100644 index 000000000000..ba12e7de0e21 --- /dev/null +++ b/evm/test-data/storage.json @@ -0,0 +1,41 @@ +{ + "meta": { + "cfg_env": { + "chain_id": "0x1", + "spec_id": "LATEST", + "perf_all_precompiles_have_balance": false + }, + "block_env": { + "number": "0xdc42b8", + "coinbase": "0x0000000000000000000000000000000000000000", + "timestamp": "0x1", + "difficulty": "0x0", + "basefee": "0x0", + "gas_limit": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + }, + "host": "mainnet.infura.io" + }, + "accounts": { + "0x63091244180ae240c87d1f528f5f269134cb07b3": { + "balance": "0x0", + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": null, + "nonce": 0 + } + }, + "storage": { + "0x63091244180ae240c87d1f528f5f269134cb07b3": { + "0x0": "0x0", + "0x1": "0x0", + "0x2": "0x0", + "0x3": "0x0", + "0x4": "0x0", + "0x5": "0x0", + "0x6": "0x0", + "0x7": "0x0", + "0x8": "0x0", + "0x9": "0x0" + } + }, + "block_hashes": {} +} \ No newline at end of file diff --git a/fmt/Cargo.toml b/fmt/Cargo.toml index e748c1c432ef..ccef530618d8 100644 --- a/fmt/Cargo.toml +++ b/fmt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "forge-fmt" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Foundry's solidity formatting and linting support" diff --git a/forge/Cargo.toml b/forge/Cargo.toml index 9bd1186bab05..8a1111c12d8b 100644 --- a/forge/Cargo.toml +++ b/forge/Cargo.toml @@ -1,14 +1,12 @@ [package] name = "forge" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] foundry-utils = { path = "./../utils" } -evm-adapters = { path = "./../evm-adapters", features = ["sputnik", "sputnik-helpers"] } +foundry-evm = { path = "./../evm" } ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full"] } eyre = "0.6.5" @@ -18,16 +16,15 @@ serde = "1.0.130" regex = { version = "1.5.4", default-features = false } hex = "0.4.3" glob = "0.3.0" -# TODO: Trim +# TODO: Trim down tokio = { version = "1.10.1" } tracing = "0.1.26" -tracing-subscriber = "0.2.20" +tracing-subscriber = "0.3" proptest = "1.0.0" rayon = "1.5" rlp = "0.5.1" - -# load sputnik for parallel evm usage -sputnik = { package = "evm", default-features = false, git = "https://github.com/rust-blockchain/evm", features = ["std"] } +once_cell = "1.9.0" +comfy-table = "5.0.0" [dev-dependencies] ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full", "solc-tests"] } diff --git a/forge/README.md b/forge/README.md index fc453331cc44..31f5babe6580 100644 --- a/forge/README.md +++ b/forge/README.md @@ -268,6 +268,7 @@ interface Hevm { // Sets an address' code, (who, newCode) function etch(address, bytes calldata) external; // Expects an error on next call + function expectRevert() external; function expectRevert(bytes calldata) external; function expectRevert(bytes4) external; // Record all storage reads and writes diff --git a/evm-adapters/src/gas_report.rs b/forge/src/gas_report.rs similarity index 65% rename from evm-adapters/src/gas_report.rs rename to forge/src/gas_report.rs index 0fac08ee9379..db8197a854ee 100644 --- a/evm-adapters/src/gas_report.rs +++ b/forge/src/gas_report.rs @@ -1,16 +1,12 @@ -use crate::CallTraceArena; -use ethers::{ - abi::Abi, - types::{H160, U256}, +use crate::{ + executor::{CHEATCODE_ADDRESS, HARDHAT_CONSOLE_ADDRESS}, + trace::{CallTraceArena, RawOrDecodedCall, TraceKind}, }; +use comfy_table::{modifiers::UTF8_ROUND_CORNERS, presets::UTF8_FULL, *}; +use ethers::types::U256; use serde::{Deserialize, Serialize}; use std::{collections::BTreeMap, fmt::Display}; -#[cfg(feature = "sputnik")] -use crate::sputnik::cheatcodes::cheatcode_handler::{CHEATCODE_ADDRESS, CONSOLE_ADDRESS}; - -use comfy_table::{modifiers::UTF8_ROUND_CORNERS, presets::UTF8_FULL, *}; - #[derive(Default, Debug, Serialize, Deserialize)] pub struct GasReport { pub report_for: Vec, @@ -38,75 +34,58 @@ impl GasReport { Self { report_for, ..Default::default() } } - pub fn analyze( - &mut self, - traces: &[CallTraceArena], - identified_contracts: &BTreeMap, - ) { + pub fn analyze(&mut self, traces: &[(TraceKind, CallTraceArena)]) { let report_for_all = self.report_for.is_empty() || self.report_for.iter().any(|s| s == "*"); - traces.iter().for_each(|trace| { - self.analyze_trace(trace, identified_contracts, report_for_all); + traces.iter().for_each(|(_, trace)| { + self.analyze_trace(trace, report_for_all); }); } - fn analyze_trace( - &mut self, - trace: &CallTraceArena, - identified_contracts: &BTreeMap, - report_for_all: bool, - ) { - self.analyze_node(trace.entry, trace, identified_contracts, report_for_all); + fn analyze_trace(&mut self, trace: &CallTraceArena, report_for_all: bool) { + self.analyze_node(0, trace, report_for_all); } - fn analyze_node( - &mut self, - node_index: usize, - arena: &CallTraceArena, - identified_contracts: &BTreeMap, - report_for_all: bool, - ) { + fn analyze_node(&mut self, node_index: usize, arena: &CallTraceArena, report_for_all: bool) { let node = &arena.arena[node_index]; let trace = &node.trace; - #[cfg(feature = "sputnik")] - if trace.addr == *CHEATCODE_ADDRESS || trace.addr == *CONSOLE_ADDRESS { + if trace.address == CHEATCODE_ADDRESS || trace.address == HARDHAT_CONSOLE_ADDRESS { return } - if let Some((name, abi)) = identified_contracts.get(&trace.addr) { + if let Some(name) = &trace.contract { let report_for = self.report_for.iter().any(|s| s == name); - if !report_for && abi.functions().any(|func| func.name == "IS_TEST") { - // do nothing - } else if report_for || report_for_all { - // report for this contract - let mut contract = + if report_for || report_for_all { + let mut contract_report = self.contracts.entry(name.to_string()).or_insert_with(Default::default); - if trace.created { - contract.gas = trace.cost.into(); - contract.size = trace.data.len().into(); - } else if trace.data.len() >= 4 { - let func = - abi.functions().find(|func| func.short_signature() == trace.data[0..4]); - - if let Some(func) = func { - let function = contract + match &trace.data { + RawOrDecodedCall::Raw(bytes) if trace.created => { + contract_report.gas = trace.gas_cost.into(); + contract_report.size = bytes.len().into(); + } + // TODO: More robust test contract filtering + RawOrDecodedCall::Decoded(func, _) if !func.starts_with("test") => { + let function_report = contract_report .functions - .entry(func.name.clone()) + .entry(func.clone()) .or_insert_with(Default::default); - function.calls.push(trace.cost.into()); + function_report.calls.push(trace.gas_cost.into()); } + _ => (), } } } + node.children.iter().for_each(|index| { - self.analyze_node(*index, arena, identified_contracts, report_for_all); + self.analyze_node(*index, arena, report_for_all); }); } - pub fn finalize(&mut self) { - self.contracts.iter_mut().for_each(|(_name, contract)| { - contract.functions.iter_mut().for_each(|(_name, func)| { + #[must_use] + pub fn finalize(mut self) -> Self { + self.contracts.iter_mut().for_each(|(_, contract)| { + contract.functions.iter_mut().for_each(|(_, func)| { func.calls.sort(); func.min = func.calls.first().cloned().unwrap_or_default(); func.max = func.calls.last().cloned().unwrap_or_default(); @@ -125,6 +104,7 @@ impl GasReport { }; }); }); + self } } diff --git a/forge/src/lib.rs b/forge/src/lib.rs index 6d288439f72f..b0625bf5bd45 100644 --- a/forge/src/lib.rs +++ b/forge/src/lib.rs @@ -1,6 +1,11 @@ +/// Gas reports +pub mod gas_report; + +/// The Forge test runner mod runner; pub use runner::{ContractRunner, TestKind, TestKindGas, TestResult}; +/// Forge test runners for multiple contracts mod multi_runner; pub use multi_runner::{MultiContractRunner, MultiContractRunnerBuilder}; @@ -10,44 +15,62 @@ pub trait TestFilter { fn matches_path(&self, path: impl AsRef) -> bool; } +/// The Forge EVM backend +pub use foundry_evm::*; + #[cfg(test)] pub mod test_helpers { - use super::*; + use crate::TestFilter; use ethers::{ - prelude::Lazy, - solc::{AggregatedCompilerOutput, Project, ProjectPathsConfig}, - types::U256, + prelude::{Lazy, ProjectCompileOutput}, + solc::{Project, ProjectPathsConfig}, + types::{Address, U256}, }; - use evm_adapters::{ - evm_opts::{Env, EvmOpts, EvmType}, - sputnik::helpers::VICINITY, - FAUCET_ACCOUNT, + use foundry_evm::{ + executor::{ + builder::Backend, + opts::{Env, EvmOpts}, + DatabaseRef, Executor, ExecutorBuilder, + }, + fuzz::FuzzedExecutor, + CALLER, }; - use sputnik::backend::MemoryBackend; + use std::str::FromStr; - pub static COMPILED: Lazy = Lazy::new(|| { - // NB: should we add a test-helper function that makes creating these - // ephemeral projects easier? - let paths = - ProjectPathsConfig::builder().root("testdata").sources("testdata").build().unwrap(); + pub static COMPILED: Lazy = Lazy::new(|| { + let paths = ProjectPathsConfig::builder() + .root("../testdata") + .sources("../testdata") + .build() + .unwrap(); let project = Project::builder().paths(paths).ephemeral().no_artifacts().build().unwrap(); - project.compile().unwrap().output() + project.compile().unwrap() }); pub static EVM_OPTS: Lazy = Lazy::new(|| EvmOpts { - env: Env { gas_limit: 18446744073709551615, chain_id: Some(99), ..Default::default() }, + env: Env { + gas_limit: 18446744073709551615, + chain_id: Some(99), + tx_origin: Address::from_str("00a329c0648769a73afac7f9381e08fb43dbea72").unwrap(), + ..Default::default() + }, + sender: Address::from_str("00a329c0648769a73afac7f9381e08fb43dbea72").unwrap(), initial_balance: U256::MAX, - evm_type: EvmType::Sputnik, + ffi: true, ..Default::default() }); - pub static BACKEND: Lazy> = Lazy::new(|| { - let mut backend = MemoryBackend::new(&*VICINITY, Default::default()); - // max out the balance of the faucet - let faucet = backend.state_mut().entry(*FAUCET_ACCOUNT).or_insert_with(Default::default); - faucet.balance = U256::MAX; - backend - }); + pub fn test_executor() -> Executor { + ExecutorBuilder::new().with_cheatcodes(false).with_config((*EVM_OPTS).evm_env()).build() + } + + pub fn fuzz_executor<'a, DB: DatabaseRef>( + executor: &'a Executor, + ) -> FuzzedExecutor<'a, DB> { + let cfg = proptest::test_runner::Config { failure_persistence: None, ..Default::default() }; + + FuzzedExecutor::new(executor, proptest::test_runner::TestRunner::new(cfg), *CALLER) + } pub mod filter { use super::*; diff --git a/forge/src/multi_runner.rs b/forge/src/multi_runner.rs index 0e437590c941..691a067f88c0 100644 --- a/forge/src/multi_runner.rs +++ b/forge/src/multi_runner.rs @@ -1,22 +1,14 @@ -use crate::{runner::TestResult, ContractRunner, TestFilter}; -use evm_adapters::{ - evm_opts::{BackendKind, EvmOpts}, - sputnik::cheatcodes::{CONSOLE_ABI, HEVMCONSOLE_ABI, HEVM_ABI}, -}; -use foundry_utils::PostLinkInput; -use sputnik::{backend::Backend, Config}; - +use crate::{ContractRunner, TestFilter, TestResult}; use ethers::{ - abi::{Abi, Event, Function}, + abi::Abi, prelude::{artifacts::CompactContractBytecode, ArtifactId, ArtifactOutput}, - solc::Artifact, - types::{Address, H256, U256}, + solc::{Artifact, ProjectCompileOutput}, + types::{Address, Bytes, U256}, }; - -use proptest::test_runner::TestRunner; - -use ethers::solc::ProjectCompileOutput; use eyre::Result; +use foundry_evm::executor::{opts::EvmOpts, DatabaseRef, Executor, ExecutorBuilder, Fork, SpecId}; +use foundry_utils::PostLinkInput; +use proptest::test_runner::TestRunner; use rayon::prelude::*; use std::{collections::BTreeMap, marker::Sync, sync::mpsc::Sender}; @@ -30,12 +22,13 @@ pub struct MultiContractRunnerBuilder { pub sender: Option
, /// The initial balance for each one of the deployed smart contracts pub initial_balance: U256, - /// The EVM Configuration to use - pub evm_cfg: Option, + /// The EVM spec to use + pub evm_spec: Option, + /// The fork config + pub fork: Option, } -pub type DeployableContracts = - BTreeMap)>; +pub type DeployableContracts = BTreeMap)>; impl MultiContractRunnerBuilder { /// Given an EVM, proceeds to return a runner which is able to execute all tests @@ -94,7 +87,7 @@ impl MultiContractRunnerBuilder { }; let abi = contract.abi.expect("We should have an abi by now"); - // if it's a test, add it to deployable contracts + // if its a test, add it to deployable contracts if abi.constructor.as_ref().map(|c| c.inputs.is_empty()).unwrap_or(true) && abi.functions().any(|func| func.name.starts_with("test")) { @@ -115,22 +108,17 @@ impl MultiContractRunnerBuilder { }, )?; - // add forge+sputnik specific contracts - known_contracts.insert("VM".to_string(), (HEVM_ABI.clone(), Vec::new())); - known_contracts.insert("VM_CONSOLE".to_string(), (HEVMCONSOLE_ABI.clone(), Vec::new())); - known_contracts.insert("CONSOLE".to_string(), (CONSOLE_ABI.clone(), Vec::new())); - let execution_info = foundry_utils::flatten_known_contracts(&known_contracts); Ok(MultiContractRunner { contracts: deployable_contracts, known_contracts, - identified_contracts: Default::default(), evm_opts, - evm_cfg: self.evm_cfg.unwrap_or_else(Config::london), + evm_spec: self.evm_spec.unwrap_or(SpecId::LONDON), sender: self.sender, fuzzer: self.fuzzer, - execution_info, + errors: Some(execution_info.2), source_paths, + fork: self.fork, }) } @@ -153,8 +141,14 @@ impl MultiContractRunnerBuilder { } #[must_use] - pub fn evm_cfg(mut self, evm_cfg: Config) -> Self { - self.evm_cfg = Some(evm_cfg); + pub fn evm_spec(mut self, spec: SpecId) -> Self { + self.evm_spec = Some(spec); + self + } + + #[must_use] + pub fn with_fork(mut self, fork: Option) -> Self { + self.fork = fork; self } } @@ -167,53 +161,68 @@ pub struct MultiContractRunner { pub contracts: BTreeMap)>, /// Compiled contracts by name that have an Abi and runtime bytecode pub known_contracts: BTreeMap)>, - /// Identified contracts by test - pub identified_contracts: BTreeMap>, /// The EVM instance used in the test runner pub evm_opts: EvmOpts, - /// The EVM revision config - pub evm_cfg: Config, - /// All contract execution info, (functions, events, errors) - pub execution_info: (BTreeMap<[u8; 4], Function>, BTreeMap, Abi), + /// The EVM spec + pub evm_spec: SpecId, + /// All known errors, used for decoding reverts + pub errors: Option, /// The fuzzer which will be used to run parametric tests (w/ non-0 solidity args) fuzzer: Option, /// The address which will be used as the `from` field in all EVM calls sender: Option
, /// A map of contract names to absolute source file paths - source_paths: BTreeMap, + pub source_paths: BTreeMap, + /// The fork config + pub fork: Option, } impl MultiContractRunner { + pub fn count_filtered_tests(&self, filter: &(impl TestFilter + Send + Sync)) -> usize { + self.contracts + .iter() + .filter(|(name, _)| { + filter.matches_path(&self.source_paths.get(*name).unwrap()) && + filter.matches_contract(name) + }) + .flat_map(|(_, (abi, _, _))| { + abi.functions().filter(|func| filter.matches_test(&func.name)) + }) + .count() + } + pub fn test( &mut self, filter: &(impl TestFilter + Send + Sync), stream_result: Option)>>, ) -> Result>> { - let contracts = std::mem::take(&mut self.contracts); - let vicinity = self.evm_opts.vicinity()?; - let backend = self.evm_opts.backend(&vicinity)?; - let source_paths = self.source_paths.clone(); - - let results = contracts + let env = self.evm_opts.evm_env(); + let results = self + .contracts .par_iter() - .filter(|(name, _)| filter.matches_path(source_paths.get(*name).unwrap())) - .filter(|(name, _)| filter.matches_contract(name)) + .filter(|(name, _)| { + filter.matches_path(&self.source_paths.get(*name).unwrap()) && + filter.matches_contract(name) + }) + .filter(|(_, (abi, _, _))| abi.functions().any(|func| filter.matches_test(&func.name))) .map(|(name, (abi, deploy_code, libs))| { - // unavoidable duplication here? - let result = match backend { - BackendKind::Simple(ref backend) => { - self.run_tests(name, abi, backend, deploy_code.clone(), libs, filter)? - } - BackendKind::Shared(ref backend) => { - self.run_tests(name, abi, backend, deploy_code.clone(), libs, filter)? - } - }; + let mut builder = ExecutorBuilder::new() + .with_cheatcodes(self.evm_opts.ffi) + .with_config(env.clone()) + .with_spec(self.evm_spec) + .with_fork(self.fork.clone()); + + if self.evm_opts.verbosity >= 3 { + builder = builder.with_tracing(); + } + + let executor = builder.build(); + let result = + self.run_tests(name, abi, executor, deploy_code.clone(), libs, filter)?; Ok((name.clone(), result)) }) - .filter_map(|x: Result<_>| x.ok()) - .filter_map( - |(name, result)| if result.is_empty() { None } else { Some((name, result)) }, - ) + .filter_map(Result::<_>::ok) + .filter(|(_, results)| !results.is_empty()) .map_with(stream_result, |stream_result, (name, result)| { if let Some(stream_result) = stream_result.as_ref() { stream_result.send((name.clone(), result.clone())).unwrap(); @@ -222,7 +231,6 @@ impl MultiContractRunner { }) .collect::>(); - self.contracts = contracts; Ok(results) } @@ -233,147 +241,301 @@ impl MultiContractRunner { err, fields(name = %_name) )] - fn run_tests( + fn run_tests( &self, _name: &str, contract: &Abi, - backend: &B, - deploy_code: ethers::prelude::Bytes, - libs: &[ethers::prelude::Bytes], + executor: Executor, + deploy_code: Bytes, + libs: &[Bytes], filter: &impl TestFilter, ) -> Result> { - let runner = ContractRunner::new( - &self.evm_opts, - &self.evm_cfg, - backend, + let mut runner = ContractRunner::new( + executor, contract, deploy_code, + self.evm_opts.initial_balance, self.sender, - Some((&self.execution_info.0, &self.execution_info.1, &self.execution_info.2)), + self.errors.as_ref(), libs, ); - runner.run_tests(filter, self.fuzzer.clone(), Some(&self.known_contracts)) + runner.run_tests(filter, self.fuzzer.clone()) } } #[cfg(test)] mod tests { use super::*; - use crate::test_helpers::{filter::Filter, EVM_OPTS}; - use ethers::solc::{Project, ProjectPathsConfig}; - use std::path::PathBuf; - - fn project() -> Project { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata"); - - let paths = ProjectPathsConfig::builder().root(&root).sources(&root).build().unwrap(); - - Project::builder() - // need to explicitly allow a path outside the project - .allowed_path(root.join("../../evm-adapters/testdata")) - .paths(paths) - .ephemeral() - .no_artifacts() - .build() - .unwrap() + use crate::{ + decode::decode_console_logs, + test_helpers::{filter::Filter, COMPILED, EVM_OPTS}, + }; + use foundry_evm::trace::TraceKind; + + /// Builds a base runner + fn base_runner() -> MultiContractRunnerBuilder { + MultiContractRunnerBuilder::default().sender(EVM_OPTS.sender) } + /// Builds a non-tracing runner fn runner() -> MultiContractRunner { - MultiContractRunnerBuilder::default() - .build(project().compile().unwrap(), EVM_OPTS.clone()) - .unwrap() + base_runner().build((*COMPILED).clone(), EVM_OPTS.clone()).unwrap() } - fn test_multi_runner() { - let mut runner = runner(); - let results = runner.test(&Filter::matches_all(), None).unwrap(); - - // 10 contracts being built - assert_eq!(results.keys().len(), 10); - for (key, contract_tests) in results { - // for a bad setup, we dont want a successful test - if key == "SetupTest.json:SetupTest" { - assert!(contract_tests.iter().all(|(_, result)| !result.success)); - } else { - assert_ne!(contract_tests.keys().len(), 0); - assert!(contract_tests.iter().all(|(_, result)| result.success)); - } - } + /// Builds a tracing runner + fn tracing_runner() -> MultiContractRunner { + let mut opts = EVM_OPTS.clone(); + opts.verbosity = 5; + base_runner().build((*COMPILED).clone(), opts).unwrap() + } - // can also filter - let filter = Filter::new("testGm.*", ".*", ".*"); - let only_gm = runner.test(&filter, None).unwrap(); - assert_eq!(only_gm.len(), 1); + /// A helper to assert the outcome of multiple tests with helpful assert messages + fn assert_multiple( + actuals: &BTreeMap>, + expecteds: BTreeMap<&str, Vec<(&str, bool, Option, Option>)>>, + ) { + assert_eq!( + actuals.len(), + expecteds.len(), + "We did not run as many contracts as we expected" + ); + for (contract_name, tests) in &expecteds { + assert_eq!( + actuals[*contract_name].len(), + expecteds[contract_name].len(), + "We did not run as many test functions as we expected for {}", + contract_name + ); + for (test_name, should_pass, reason, expected_logs) in tests { + let logs = decode_console_logs(&actuals[*contract_name][*test_name].logs); + + if *should_pass { + assert!( + actuals[*contract_name][*test_name].success, + "Test {} did not pass as expected.\nReason: {:?}\nLogs:\n{}", + test_name, + actuals[*contract_name][*test_name].reason, + logs.join("\n") + ); + } else { + assert!( + !actuals[*contract_name][*test_name].success, + "Test {} did not fail as expected.\nLogs:\n{}", + test_name, + logs.join("\n") + ); + assert_eq!( + actuals[*contract_name][*test_name].reason, *reason, + "Failure reason for test {} did not match what we expected.", + test_name + ); + } - assert_eq!(only_gm["GmTest.json:GmTest"].len(), 1); - assert!(only_gm["GmTest.json:GmTest"]["testGm()"].success); + if let Some(expected_logs) = expected_logs { + assert!( + logs.iter().eq(expected_logs.iter()), + "Logs did not match for test {}.\nExpected:\n{}\n\nGot:\n{}", + test_name, + logs.join("\n"), + expected_logs.join("\n") + ); + } + } + } } - fn test_abstract_contract() { + #[test] + fn test_core() { let mut runner = runner(); - let results = runner.test(&Filter::matches_all(), None).unwrap(); - assert!(results.get("Tests.json:Tests").is_none()); - assert!(results.get("ATests.json:ATests").is_some()); - assert!(results.get("BTests.json:BTests").is_some()); + let results = runner.test(&Filter::new(".*", ".*", ".*core"), None).unwrap(); + + assert_multiple( + &results, + BTreeMap::from([ + ( + "FailingSetupTest.json:FailingSetupTest", + vec![( + "setUp()", + false, + Some("Setup failed: setup failed predictably".to_string()), + None, + )], + ), + ("RevertingTest.json:RevertingTest", vec![("testFailRevert()", true, None, None)]), + ( + "SetupConsistencyCheck.json:SetupConsistencyCheck", + vec![("testAdd()", true, None, None), ("testMultiply()", true, None, None)], + ), + ( + "DSStyleTest.json:DSStyleTest", + vec![ + ("testAddresses()", true, None, None), + ("testEnvironment()", true, None, None), + ], + ), + ( + "PaymentFailureTest.json:PaymentFailureTest", + vec![("testCantPay()", false, Some("Revert".to_string()), None)], + ), + ( + "LibraryLinkingTest.json:LibraryLinkingTest", + vec![("testDirect()", true, None, None), ("testNested()", true, None, None)], + ), + ("AbstractTest.json:AbstractTest", vec![("testSomething()", true, None, None)]), + ]), + ); } - mod sputnik { - use super::*; - use std::collections::HashMap; - - #[test] - fn test_sputnik_debug_logs() { - let mut runner = runner(); - let results = runner.test(&Filter::matches_all(), None).unwrap(); + #[test] + fn test_logs() { + let mut runner = runner(); + let results = runner.test(&Filter::new(".*", ".*", ".*logs"), None).unwrap(); + + assert_multiple( + &results, + BTreeMap::from([ + ( + "DebugLogsTest.json:DebugLogsTest", + vec![ + ("test1()", true, None, Some(vec!["0".into(), "1".into(), "2".into()])), + ("test2()", true, None, Some(vec!["0".into(), "1".into(), "3".into()])), + ( + "testFailWithRequire()", + true, + None, + Some(vec!["0".into(), "1".into(), "5".into()]), + ), + ( + "testFailWithRevert()", + true, + None, + Some(vec!["0".into(), "1".into(), "4".into(), "100".into()]), + ), + ], + ), + ( + "HardhatLogsTest.json:HardhatLogsTest", + vec![ + ( + "testInts()", + true, + None, + Some(vec![ + "constructor".into(), + "0".into(), + "1".into(), + "2".into(), + "3".into(), + ]), + ), + ( + "testMisc()", + true, + None, + Some(vec![ + "constructor".into(), + "testMisc, 0x0000000000000000000000000000000000000001".into(), + "testMisc, 42".into(), + ]), + ), + ( + "testStrings()", + true, + None, + Some(vec!["constructor".into(), "testStrings".into()]), + ), + ], + ), + ]), + ); + } - let reasons = results["DebugLogsTest.json:DebugLogsTest"] - .iter() - .map(|(name, res)| (name, res.logs.clone())) - .collect::>(); - assert_eq!( - reasons[&"test1()".to_owned()], - vec!["constructor".to_owned(), "setUp".to_owned(), "one".to_owned()] - ); - assert_eq!( - reasons[&"test2()".to_owned()], - vec!["constructor".to_owned(), "setUp".to_owned(), "two".to_owned()] - ); - assert_eq!( - reasons[&"testFailWithRevert()".to_owned()], - vec![ - "constructor".to_owned(), - "setUp".to_owned(), - "three".to_owned(), - "failure".to_owned() - ] - ); - assert_eq!( - reasons[&"testFailWithRequire()".to_owned()], - vec!["constructor".to_owned(), "setUp".to_owned(), "four".to_owned()] - ); + #[test] + fn test_cheats() { + let mut runner = runner(); + let results = runner.test(&Filter::new(".*", ".*", ".*cheats"), None).unwrap(); + + for (_, tests) in results { + for (test_name, result) in tests { + assert!( + result.success, + "Test {} did not pass as expected.\nReason: {:?}", + test_name, result.reason + ); + } } + } - #[test] - fn test_access_list_reset() { - let mut runner = runner(); - let results = runner.test(&Filter::matches_all(), None).unwrap(); - let results = &results["WhichTest.json:WhichTest"]; - assert!(results["testA()"].success); - assert_eq!(results["testA()"].gas_used, 65577); - assert!(results["testB()"].success); - assert_eq!(results["testB()"].gas_used, 68263); - assert!(results["testC()"].success); - assert_eq!(results["testC()"].gas_used, 63611); + #[test] + fn test_fuzz() { + let mut runner = runner(); + let results = runner.test(&Filter::new(".*", ".*", ".*fuzz"), None).unwrap(); + + for (_, tests) in results { + for (test_name, result) in tests { + match test_name.as_ref() { + "testPositive(uint256)" | "testSuccessfulFuzz(uint128,uint128)" => assert!( + result.success, + "Test {} did not pass as expected.\nReason: {:?}", + test_name, result.reason + ), + _ => assert!( + !result.success, + "Test {} did not fail as expected.\nReason: {:?}", + test_name, result.reason + ), + } + } } + } - #[test] - fn test_sputnik_multi_runner() { - test_multi_runner(); + #[test] + fn test_trace() { + let mut runner = tracing_runner(); + let results = runner.test(&Filter::new(".*", ".*", ".*trace"), None).unwrap(); + + // TODO: This trace test is very basic - it is probably a good candidate for snapshot + // testing. + for (_, tests) in results { + for (test_name, result) in tests { + let deployment_traces = result + .traces + .iter() + .filter(|(kind, _)| *kind == TraceKind::Deployment) + .collect::>(); + let setup_traces = result + .traces + .iter() + .filter(|(kind, _)| *kind == TraceKind::Setup) + .collect::>(); + let execution_traces = result + .traces + .iter() + .filter(|(kind, _)| *kind == TraceKind::Deployment) + .collect::>(); + + assert_eq!( + deployment_traces.len(), + 1, + "Test {} did not have exactly 1 deployment trace.", + test_name + ); + assert!(setup_traces.len() <= 1, "Test {} had more than 1 setup trace.", test_name); + assert_eq!( + execution_traces.len(), + 1, + "Test {} did not not have exactly 1 execution trace.", + test_name + ); + } } + } - #[test] - fn test_sputnik_abstract_contract() { - test_abstract_contract(); - } + #[test] + fn test_doesnt_run_abstract_contract() { + let mut runner = runner(); + let results = runner.test(&Filter::new(".*", ".*", ".*core/Abstract.t.sol"), None).unwrap(); + assert!(results.get("AbstractTestBase.json:AbstractTestBase").is_none()); + assert!(results.get("AbstractTest.json:AbstractTest").is_some()); } } diff --git a/forge/src/runner.rs b/forge/src/runner.rs index 83a6c05d01b8..669a7b924483 100644 --- a/forge/src/runner.rs +++ b/forge/src/runner.rs @@ -1,46 +1,19 @@ use crate::TestFilter; -use evm_adapters::{ - evm_opts::EvmOpts, - sputnik::{helpers::TestSputnikVM, Executor, SputnikExecutor, PRECOMPILES_MAP}, -}; -use rayon::iter::ParallelIterator; -use sputnik::{ - backend::Backend, - executor::stack::{StackState, StackSubstateMetadata}, - Config, -}; - use ethers::{ - abi::{Abi, Event, Function, Token}, - types::{Address, Bytes, H256}, -}; -use evm_adapters::{ - call_tracing::CallTraceArena, - fuzz::{FuzzTestResult, FuzzedCases, FuzzedExecutor}, - sputnik::cheatcodes::debugger::DebugArena, - Evm, EvmError, + abi::{Abi, Function, RawLog}, + types::{Address, Bytes, U256}, }; use eyre::Result; -use std::{collections::BTreeMap, fmt, time::Instant}; - -use proptest::test_runner::{TestError, TestRunner}; -use rayon::iter::IntoParallelRefIterator; +use foundry_evm::{ + executor::{CallResult, DatabaseRef, DeployResult, EvmError, Executor}, + fuzz::{CounterExample, FuzzedCases, FuzzedExecutor}, + trace::{CallTraceArena, TraceKind}, + CALLER, +}; +use proptest::test_runner::TestRunner; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CounterExample { - pub calldata: Bytes, - // Token does not implement Serde (lol), so we just serialize the calldata - #[serde(skip)] - pub args: Vec, -} - -impl fmt::Display for CounterExample { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let args = foundry_utils::format_tokens(&self.args).collect::>().join(", "); - write!(f, "calldata=0x{}, args=[{}]", hex::encode(&self.calldata), args) - } -} +use std::{collections::BTreeMap, fmt, time::Instant}; /// The result of an executed solidity test #[derive(Clone, Debug, Serialize, Deserialize)] @@ -54,31 +27,19 @@ pub struct TestResult { /// still be successful (i.e self.success == true) when it's expected to fail. pub reason: Option, - /// The gas used during execution. - /// - /// If this is the result of a fuzz test (`TestKind::Fuzz`), then this is the median of all - /// successful cases - pub gas_used: u64, - /// Minimal reproduction test case for failing fuzz tests pub counterexample: Option, /// Any captured & parsed as strings logs along the test's execution which should /// be printed to the user. - pub logs: Vec, + #[serde(skip)] + pub logs: Vec, /// What kind of test this was pub kind: TestKind, /// Traces - pub traces: Option>, - - /// Identified contracts - pub identified_contracts: Option>, - - /// Debug Steps - #[serde(skip)] - pub debug_calls: Option>, + pub traces: Vec<(TraceKind, CallTraceArena)>, /// Labeled addresses pub labeled_addresses: BTreeMap, @@ -116,7 +77,7 @@ impl TestKindGas { pub fn gas(&self) -> u64 { match self { TestKindGas::Standard(gas) => *gas, - // we use the median for comparisons + // We use the median for comparisons TestKindGas::Fuzz { median, .. } => *median, } } @@ -140,593 +101,311 @@ impl TestKind { TestKind::Standard(gas) => TestKindGas::Standard(*gas), TestKind::Fuzz(fuzzed) => TestKindGas::Fuzz { runs: fuzzed.cases().len(), - median: fuzzed.median_gas(), - mean: fuzzed.mean_gas(), + median: fuzzed.median_gas(false), + mean: fuzzed.mean_gas(false), }, } } } -/// Type complexity wrapper around execution info -type MaybeExecutionInfo<'a> = - Option<(&'a BTreeMap<[u8; 4], Function>, &'a BTreeMap, &'a Abi)>; - -pub struct ContractRunner<'a, B> { - // EVM Config Options - /// The options used to instantiate a new EVM. - pub evm_opts: &'a EvmOpts, - /// The backend used by the VM. - pub backend: &'a B, - /// The VM Configuration to use for the runner (London, Berlin , ...) - pub evm_cfg: &'a Config, - - // Contract deployment options - /// The deployed contract's ABI +#[derive(Clone, Debug, Default)] +pub struct TestSetup { + /// The address at which the test contract was deployed + pub address: Address, + /// The logs emitted during setup + pub logs: Vec, + /// Call traces of the setup + pub traces: Vec<(TraceKind, CallTraceArena)>, + /// Addresses labeled during setup + pub labeled_addresses: BTreeMap, + /// Whether the setup failed + pub setup_failed: bool, + /// The reason the setup failed + pub reason: Option, +} + +pub struct ContractRunner<'a, DB: DatabaseRef> { + /// The executor used by the runner. + pub executor: Executor, + + /// Library contracts to be deployed before the test contract + pub predeploy_libs: &'a [Bytes], + /// The deployed contract's code + pub code: Bytes, + /// The test contract's ABI pub contract: &'a Abi, - /// The deployed contract's address - // This is cheap to clone due to [`bytes::Bytes`], so OK to own - pub code: ethers::prelude::Bytes, + /// All known errors, used to decode reverts + pub errors: Option<&'a Abi>, + + /// The initial balance of the test contract + pub initial_balance: U256, /// The address which will be used as the `from` field in all EVM calls pub sender: Address, - - /// Contract execution info, (functions, events, errors) - pub execution_info: MaybeExecutionInfo<'a>, - /// library contracts to be deployed before this contract - pub predeploy_libs: &'a [ethers::prelude::Bytes], } -impl<'a, B: Backend> ContractRunner<'a, B> { +impl<'a, DB: DatabaseRef> ContractRunner<'a, DB> { #[allow(clippy::too_many_arguments)] pub fn new( - evm_opts: &'a EvmOpts, - evm_cfg: &'a Config, - backend: &'a B, + executor: Executor, contract: &'a Abi, - code: ethers::prelude::Bytes, + code: Bytes, + initial_balance: U256, sender: Option
, - execution_info: MaybeExecutionInfo<'a>, - predeploy_libs: &'a [ethers::prelude::Bytes], + errors: Option<&'a Abi>, + predeploy_libs: &'a [Bytes], ) -> Self { Self { - evm_opts, - evm_cfg, - backend, + executor, contract, code, + initial_balance, sender: sender.unwrap_or_default(), - execution_info, + errors, predeploy_libs, } } } -// Require that the backend is Cloneable. This allows us to use the `SharedBackend` from -// evm-adapters which is clone-able. -impl<'a, B: Backend + Clone + Send + Sync> ContractRunner<'a, B> { - /// Creates a new EVM and deploys the test contract inside the runner - /// from the sending account. - pub fn new_sputnik_evm(&'a self) -> eyre::Result<(Address, TestSputnikVM<'a, B>, Vec)> { - // create the EVM, clone the backend. - let mut executor = Executor::new_with_cheatcodes( - self.backend.clone(), - self.evm_opts.env.gas_limit, - self.evm_cfg, - &*PRECOMPILES_MAP, - self.evm_opts.ffi, - self.evm_opts.verbosity > 2, - self.evm_opts.debug, - ); +impl<'a, DB: DatabaseRef + Send + Sync> ContractRunner<'a, DB> { + /// Deploys the test contract inside the runner from the sending account, and optionally runs + /// the `setUp` function on the test contract. + pub fn setup(&mut self, setup: bool) -> Result { + // We max out their balance so that they can deploy and make calls. + self.executor.set_balance(self.sender, U256::MAX); + self.executor.set_balance(*CALLER, U256::MAX); + + // We set the nonce of the deployer accounts to 1 to get the same addresses as DappTools + self.executor.set_nonce(self.sender, 1); + + // Deploy libraries + let mut traces: Vec<(TraceKind, CallTraceArena)> = self + .predeploy_libs + .iter() + .filter_map(|code| { + let DeployResult { traces, .. } = self + .executor + .deploy(self.sender, code.0.clone(), 0u32.into()) + .expect("couldn't deploy library"); + + traces + }) + .map(|traces| (TraceKind::Deployment, traces)) + .collect(); + + // Deploy an instance of the contract + let DeployResult { address, mut logs, traces: constructor_traces, .. } = self + .executor + .deploy(self.sender, self.code.0.clone(), 0u32.into()) + .expect("couldn't deploy"); + traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces)).into_iter()); + self.executor.set_balance(address, self.initial_balance); + + // Optionally call the `setUp` function + Ok(if setup { + tracing::trace!("setting up"); + let (setup_failed, setup_logs, setup_traces, labeled_addresses, reason) = match self + .executor + .setup(address) + { + Ok(CallResult { traces, labels, logs, .. }) => (false, logs, traces, labels, None), + Err(EvmError::Execution { traces, labels, logs, reason, .. }) => { + (true, logs, traces, labels, Some(format!("Setup failed: {}", reason))) + } + Err(e) => ( + true, + Vec::new(), + None, + BTreeMap::new(), + Some(format!("Setup failed: {}", &e.to_string())), + ), + }; + traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)).into_iter()); + logs.extend_from_slice(&setup_logs); - self.predeploy_libs.iter().for_each(|code| { - executor - .deploy(self.sender, code.clone(), 0u32.into()) - .expect("couldn't deploy library"); - }); - - // deploy an instance of the contract inside the runner in the EVM - let (addr, _, _, logs) = - executor.deploy(self.sender, self.code.clone(), 0u32.into()).expect("couldn't deploy"); - executor.set_balance(addr, self.evm_opts.initial_balance); - Ok((addr, executor, logs)) + TestSetup { address, logs, traces, labeled_addresses, setup_failed, reason } + } else { + TestSetup { address, logs, traces, ..Default::default() } + }) } /// Runs all tests for a contract whose names match the provided regular expression pub fn run_tests( - &self, + &mut self, filter: &impl TestFilter, fuzzer: Option, - known_contracts: Option<&BTreeMap)>>, ) -> Result> { tracing::info!("starting tests"); let start = Instant::now(); let needs_setup = self.contract.functions().any(|func| func.name == "setUp"); - let test_fns = self + + let setup = self.setup(needs_setup)?; + if setup.setup_failed { + // The setup failed, so we return a single test result for `setUp` + return Ok([( + "setUp()".to_string(), + TestResult { + success: false, + reason: setup.reason, + counterexample: None, + logs: setup.logs, + kind: TestKind::Standard(0), + traces: setup.traces, + labeled_addresses: setup.labeled_addresses, + }, + )] + .into()) + } + + // Collect valid test functions + let tests: Vec<_> = self .contract .functions() .into_iter() - .filter(|func| func.name.starts_with("test")) - .filter(|func| filter.matches_test(&func.name)) - .collect::>(); + .filter(|func| func.name.starts_with("test") && filter.matches_test(&func.name)) + .map(|func| (func, func.name.starts_with("testFail"))) + .collect(); - // run all unit tests - let unit_tests = test_fns + let test_results = tests .par_iter() - .filter(|func| func.inputs.is_empty()) - .map(|func| { - let result = self.run_test(func, needs_setup, known_contracts)?; - Ok((func.signature(), result)) + .filter_map(|(func, should_fail)| { + let result = if func.inputs.is_empty() { + Some(self.run_test(func, *should_fail, setup.clone())) + } else { + fuzzer.as_ref().map(|fuzzer| { + self.run_fuzz_test(func, *should_fail, fuzzer.clone(), setup.clone()) + }) + }; + + result.map(|result| Ok((func.signature(), result?))) }) .collect::>>()?; - let map = if let Some(fuzzer) = fuzzer { - let fuzz_tests = test_fns - .par_iter() - .filter(|func| !func.inputs.is_empty()) - .map(|func| { - let result = - self.run_fuzz_test(func, needs_setup, fuzzer.clone(), known_contracts)?; - Ok((func.signature(), result)) - }) - .collect::>>()?; - - let mut map = unit_tests; - map.extend(fuzz_tests); - map - } else { - unit_tests - }; - - if !map.is_empty() { - let successful = map.iter().filter(|(_, tst)| tst.success).count(); - let duration = Instant::now().duration_since(start); - tracing::info!(?duration, "done. {}/{} successful", successful, map.len()); + if !test_results.is_empty() { + let successful = test_results.iter().filter(|(_, tst)| tst.success).count(); + tracing::info!( + duration = ?Instant::now().duration_since(start), + "done. {}/{} successful", + successful, + test_results.len() + ); } - Ok(map) + Ok(test_results) } - #[tracing::instrument(name = "test", skip_all, fields(name = %func.signature()))] + #[tracing::instrument(name = "test", skip_all, fields(name = %func.signature(), %should_fail))] pub fn run_test( &self, func: &Function, - setup: bool, - known_contracts: Option<&BTreeMap)>>, + should_fail: bool, + setup: TestSetup, ) -> Result { - let start = Instant::now(); - // the expected result depends on the function name - // DAppTools' ds-test will not revert inside its `assertEq`-like functions - // which allows to test multiple assertions in 1 test function while also - // preserving logs. - let should_fail = func.name.starts_with("testFail"); - tracing::debug!(func = ?func.signature(), should_fail, "unit-testing"); + let TestSetup { address, mut logs, mut traces, mut labeled_addresses, .. } = setup; - let (address, mut evm, init_logs) = self.new_sputnik_evm()?; - - let errors_abi = self.execution_info.as_ref().map(|(_, _, errors)| errors); - let errors_abi = if let Some(ref abi) = errors_abi { abi } else { self.contract }; - - let mut logs = init_logs; - - let mut traces: Option> = None; - let mut identified_contracts: Option> = None; - - // clear out the deployment trace - evm.reset_traces(); - - // call the setup function in each test to reset the test's state. - if setup { - tracing::trace!("setting up"); - let setup_logs = match evm.setup(address) { - Ok((_reason, setup_logs)) => setup_logs, - Err(e) => { - // if tracing is enabled, just return it as a failed test - // otherwise abort - if evm.tracing_enabled() { - self.update_traces( - &mut traces, - &mut identified_contracts, - known_contracts, - setup, - &mut evm, - ); - } - - return Ok(TestResult { - success: false, - reason: Some("Setup failed: ".to_string() + &e.to_string()), - gas_used: 0, - counterexample: None, - logs, - kind: TestKind::Standard(0), - traces, - identified_contracts, - debug_calls: if evm.state().debug_enabled { - Some(evm.debug_calls()) - } else { - None - }, - labeled_addresses: evm.state().labels.clone(), - }) - } - }; - logs.extend_from_slice(&setup_logs); - // this is dumb, but resetting metadata is the only way to reset access list, which - // affects setup -> call gas costs because setUp can make addresses and slots warm - // - // long live REVM. This is totally unnecessary once we switch. - let state = evm.executor.state_mut(); - let metadata = StackSubstateMetadata::new(self.evm_opts.env.gas_limit, self.evm_cfg); - let meta = state.metadata_mut(); - *meta = metadata; - } - - let (status, reason, gas_used, logs) = match evm.call::<(), _, _>( - self.sender, - address, - func.clone(), - (), - 0.into(), - Some(errors_abi), - ) { - Ok((_, status, gas_used, execution_logs)) => { + // Run unit test + let start = Instant::now(); + let (reverted, reason, gas, stipend, execution_traces, state_changeset) = match self + .executor + .call::<(), _, _>(self.sender, address, func.clone(), (), 0.into(), self.errors) + { + Ok(CallResult { + reverted, + gas, + stipend, + logs: execution_logs, + traces: execution_trace, + labels: new_labels, + state_changeset, + .. + }) => { + labeled_addresses.extend(new_labels); logs.extend(execution_logs); - (status, None, gas_used, logs) + (reverted, None, gas, stipend, execution_trace, state_changeset) + } + Err(EvmError::Execution { + reverted, + reason, + gas, + stipend, + logs: execution_logs, + traces: execution_trace, + labels: new_labels, + state_changeset, + .. + }) => { + labeled_addresses.extend(new_labels); + logs.extend(execution_logs); + (reverted, Some(reason), gas, stipend, execution_trace, state_changeset) + } + Err(err) => { + tracing::error!(?err); + return Err(err.into()) } - Err(err) => match err { - EvmError::Execution { reason, gas_used, logs: execution_logs } => { - logs.extend(execution_logs); - // add reverted logs - logs.extend(evm.all_logs()); - (revert(&evm), Some(reason), gas_used, logs) - } - err => { - tracing::error!(?err); - return Err(err.into()) - } - }, }; + traces.extend(execution_traces.map(|traces| (TraceKind::Execution, traces)).into_iter()); - self.update_traces( - &mut traces, - &mut identified_contracts, - known_contracts, - setup, - &mut evm, + let success = self.executor.is_success( + setup.address, + reverted, + state_changeset.expect("we should have a state changeset"), + should_fail, ); - let success = evm.check_success(address, &status, should_fail); - let duration = Instant::now().duration_since(start); - tracing::debug!(?duration, %success, %gas_used); + // Record test execution time + tracing::debug!( + duration = ?Instant::now().duration_since(start), + %success, + %gas + ); Ok(TestResult { success, reason, - gas_used, counterexample: None, logs, - kind: TestKind::Standard(gas_used), + kind: TestKind::Standard(gas.overflowing_sub(stipend).0), traces, - identified_contracts, - debug_calls: if evm.state().debug_enabled { Some(evm.debug_calls()) } else { None }, - labeled_addresses: evm.state().labels.clone(), + labeled_addresses, }) } - #[tracing::instrument(name = "fuzz-test", skip_all, fields(name = %func.signature()))] + #[tracing::instrument(name = "fuzz-test", skip_all, fields(name = %func.signature(), %should_fail))] pub fn run_fuzz_test( &self, func: &Function, - setup: bool, + should_fail: bool, runner: TestRunner, - known_contracts: Option<&BTreeMap)>>, + setup: TestSetup, ) -> Result { - // do not trace in fuzztests, as it's a big performance hit - let start = Instant::now(); - let should_fail = func.name.starts_with("testFail"); - tracing::debug!(func = ?func.signature(), should_fail, "fuzzing"); - - let (address, mut evm, init_logs) = self.new_sputnik_evm()?; - - let mut traces: Option> = None; - let mut identified_contracts: Option> = None; - - // clear out the deployment trace - evm.reset_traces(); - - // call the setup function in each test to reset the test's state. - if setup { - tracing::trace!("setting up"); - match evm.setup(address) { - Ok((_reason, _setup_logs)) => {} - Err(e) => { - // if tracing is enabled, just return it as a failed test - // otherwise abort - if evm.tracing_enabled() { - self.update_traces( - &mut traces, - &mut identified_contracts, - known_contracts, - setup, - &mut evm, - ); - } - return Ok(TestResult { - success: false, - reason: Some("Setup failed: ".to_string() + &e.to_string()), - gas_used: 0, - counterexample: None, - logs: vec![], - kind: TestKind::Fuzz(FuzzedCases::new(vec![])), - traces, - identified_contracts, - debug_calls: if evm.state().debug_enabled { - Some(evm.debug_calls()) - } else { - None - }, - labeled_addresses: evm.state().labels.clone(), - }) - } - } - } - - let mut logs = init_logs; + let TestSetup { address, mut logs, mut traces, mut labeled_addresses, .. } = setup; - let prev = evm.set_tracing_enabled(false); - - // instantiate the fuzzed evm in line - let evm = FuzzedExecutor::new(&mut evm, runner, self.sender); - let FuzzTestResult { cases, test_error } = - evm.fuzz(func, address, should_fail, Some(self.contract)); - - let evm = evm.into_inner(); - if let Some(ref error) = test_error { - // we want traces for a failed fuzz - if let TestError::Fail(_reason, bytes) = &error.test_error { - if prev { - let _ = evm.set_tracing_enabled(true); - } - let (_retdata, status, _gas, execution_logs) = - evm.call_raw(self.sender, address, bytes.clone(), 0.into(), false)?; - if is_fail(evm, status) { - logs.extend(execution_logs); - // add reverted logs - logs.extend(evm.all_logs()); - } else { - logs.extend(execution_logs); - } - self.update_traces( - &mut traces, - &mut identified_contracts, - known_contracts, - setup, - evm, - ); - } - } + // Run fuzz test + let start = Instant::now(); + let mut result = FuzzedExecutor::new(&self.executor, runner, self.sender).fuzz( + func, + address, + should_fail, + self.errors, + ); - let success = test_error.is_none(); - let mut counterexample = None; - let mut reason = None; - if let Some(err) = test_error { - match err.test_error { - TestError::Abort(r) if r == "Too many global rejects".into() => { - reason = Some(r.message().to_string()); - } - TestError::Fail(_, value) => { - // skip the function selector when decoding - let args = func.decode_input(&value.as_ref()[4..])?; - let counter = CounterExample { calldata: value.clone(), args }; - counterexample = Some(counter); - tracing::info!("Found minimal failing case: {}", hex::encode(&value)); - } - result => panic!("Unexpected test result: {:?}", result), - } - if !err.revert_reason.is_empty() { - reason = Some(err.revert_reason); - } - } + // Record logs, labels and traces + logs.append(&mut result.logs); + labeled_addresses.append(&mut result.labeled_addresses); + traces.extend(result.traces.map(|traces| (TraceKind::Execution, traces)).into_iter()); - let duration = Instant::now().duration_since(start); - tracing::debug!(?duration, %success); + // Record test execution time + tracing::debug!( + duration = ?Instant::now().duration_since(start), + success = %result.success + ); - // from that call? Ok(TestResult { - success, - reason, - gas_used: cases.median_gas(), - counterexample, + success: result.success, + reason: result.reason, + counterexample: result.counterexample, logs, - kind: TestKind::Fuzz(cases), + kind: TestKind::Fuzz(result.cases), traces, - identified_contracts, - debug_calls: if evm.state().debug_enabled { Some(evm.debug_calls()) } else { None }, - labeled_addresses: evm.state().labels.clone(), + labeled_addresses, }) } - - fn update_traces>( - &self, - traces: &mut Option>, - identified_contracts: &mut Option>, - known_contracts: Option<&BTreeMap)>>, - setup: bool, - evm: &mut E, - ) { - let evm_traces = evm.traces(); - if !evm_traces.is_empty() && evm.tracing_enabled() { - let mut ident = BTreeMap::new(); - // create an iter over the traces - let mut trace_iter = evm_traces.into_iter(); - let mut temp_traces = Vec::new(); - if setup { - // grab the setup trace if it exists - let setup = trace_iter.next().expect("no setup trace"); - setup.update_identified( - 0, - known_contracts.expect("traces enabled but no identified_contracts"), - &mut ident, - evm, - ); - temp_traces.push(setup); - } - // grab the test trace - if let Some(test_trace) = trace_iter.next() { - test_trace.update_identified( - 0, - known_contracts.expect("traces enabled but no identified_contracts"), - &mut ident, - evm, - ); - temp_traces.push(test_trace); - } - - // pass back the identified contracts and traces - *identified_contracts = Some(ident); - *traces = Some(temp_traces); - } - evm.reset_traces(); - } -} - -// Helper functions for getting the revert status for a `ReturnReason` without having -// to specify the full EVM signature -fn is_fail + evm_adapters::Evm, T>( - _evm: &mut E, - status: T, -) -> bool { - >::is_fail(&status) -} - -fn revert + evm_adapters::Evm, T>(_evm: &E) -> T { - >::revert() -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_helpers::{filter::Filter, BACKEND, COMPILED, EVM_OPTS}; - use ethers::solc::artifacts::CompactContractRef; - - mod sputnik { - use ::sputnik::backend::MemoryBackend; - use evm_adapters::sputnik::helpers::CFG_NO_LMT; - use foundry_utils::get_func; - use proptest::test_runner::Config as FuzzConfig; - - use super::*; - - pub fn runner<'a>( - abi: &'a Abi, - code: ethers::prelude::Bytes, - libs: &'a mut Vec, - ) -> ContractRunner<'a, MemoryBackend<'a>> { - ContractRunner::new(&*EVM_OPTS, &*CFG_NO_LMT, &*BACKEND, abi, code, None, None, libs) - } - - #[test] - fn test_runner() { - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - super::test_runner(compiled); - } - - #[test] - fn test_function_overriding() { - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - - let (_, code, _) = compiled.into_parts_or_default(); - let mut libs = vec![]; - let runner = runner(compiled.abi.as_ref().unwrap(), code, &mut libs); - - let mut cfg = FuzzConfig::default(); - cfg.failure_persistence = None; - let fuzzer = TestRunner::new(cfg); - let filter = Filter::new("testGreeting", ".*", ".*"); - let results = runner.run_tests(&filter, Some(fuzzer), None).unwrap(); - assert!(results["testGreeting()"].success); - assert!(results["testGreeting(string)"].success); - assert!(results["testGreeting(string,string)"].success); - } - - #[test] - fn test_fuzzing_counterexamples() { - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - let (_, code, _) = compiled.into_parts_or_default(); - let mut libs = vec![]; - let runner = runner(compiled.abi.as_ref().unwrap(), code, &mut libs); - - let mut cfg = FuzzConfig::default(); - cfg.failure_persistence = None; - let fuzzer = TestRunner::new(cfg); - let filter = Filter::new("testFuzz.*", ".*", ".*"); - let results = runner.run_tests(&filter, Some(fuzzer), None).unwrap(); - for (_, res) in results { - assert!(!res.success); - assert!(res.counterexample.is_some()); - } - } - - #[test] - fn test_fuzzing_ok() { - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - let (_, code, _) = compiled.into_parts_or_default(); - let mut libs = vec![]; - let runner = runner(compiled.abi.as_ref().unwrap(), code, &mut libs); - - let mut cfg = FuzzConfig::default(); - cfg.failure_persistence = None; - let fuzzer = TestRunner::new(cfg); - let func = get_func("testStringFuzz(string)").unwrap(); - let res = runner.run_fuzz_test(&func, true, fuzzer, None).unwrap(); - assert!(res.success); - assert!(res.counterexample.is_none()); - } - - #[test] - fn test_fuzz_shrinking() { - let compiled = COMPILED.find("GreeterTest").expect("could not find contract"); - let (_, code, _) = compiled.into_parts_or_default(); - let mut libs = vec![]; - let runner = runner(compiled.abi.as_ref().unwrap(), code, &mut libs); - - let mut cfg = FuzzConfig::default(); - cfg.failure_persistence = None; - let fuzzer = TestRunner::new(cfg); - let func = get_func("function testShrinking(uint256 x, uint256 y) public").unwrap(); - let res = runner.run_fuzz_test(&func, true, fuzzer, None).unwrap(); - assert!(!res.success); - - // get the counterexample with shrinking enabled by default - let counterexample = res.counterexample.unwrap(); - let product_with_shrinking: u64 = - // casting to u64 here is safe because the shrunk result is always gonna be small - // enough to fit in a u64, whereas as seen below, that's not possible without - // shrinking - counterexample.args.into_iter().map(|x| x.into_uint().unwrap().as_u64()).product(); - - let mut cfg = FuzzConfig::default(); - cfg.failure_persistence = None; - // we reduce the shrinking iters and observe a larger result - cfg.max_shrink_iters = 5; - let fuzzer = TestRunner::new(cfg); - let res = runner.run_fuzz_test(&func, true, fuzzer, None).unwrap(); - assert!(!res.success); - - // get the non-shrunk result - let counterexample = res.counterexample.unwrap(); - let args = - counterexample.args.into_iter().map(|x| x.into_uint().unwrap()).collect::>(); - let product_without_shrinking = args[0].saturating_mul(args[1]); - assert!(product_without_shrinking > product_with_shrinking.into()); - } - } - - pub fn test_runner(compiled: CompactContractRef) { - let (_, code, _) = compiled.into_parts_or_default(); - let mut libs = vec![]; - let runner = sputnik::runner(compiled.abi.as_ref().unwrap(), code, &mut libs); - - let res = runner.run_tests(&Filter::matches_all(), None, None).unwrap(); - assert!(!res.is_empty()); - assert!(res.iter().all(|(_, result)| result.success)); - } } diff --git a/forge/testdata/Abstract.sol b/forge/testdata/Abstract.sol deleted file mode 100644 index af359060f899..000000000000 --- a/forge/testdata/Abstract.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity 0.8.10; - -interface IContract { function foo() external; } - -// your 2 implementations -contract A is IContract { function foo() public { } } -contract B is IContract { function foo() public { } } - -// the shared test suite -abstract contract Tests { - IContract myContract; - // this function is part of any contract that inherits `Tests` - function testFoo() public { myContract.foo(); } -} - -contract ATests is Tests { - function setUp() public { - myContract = IContract(address(new A())); - } -} - -contract BTests is Tests { - function setUp() public { - myContract = IContract(address(new B())); - } -} diff --git a/forge/testdata/BadSetup.sol b/forge/testdata/BadSetup.sol deleted file mode 100644 index 99c8ed11ceee..000000000000 --- a/forge/testdata/BadSetup.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.8.1; - -contract DsTestMini { - bool public failed; - - function fail() private { - failed = true; - } - - function assertEq(uint a, uint b) internal { - if (a != b) { - fail(); - } - } -} - -contract SetupTest is DsTestMini { - function setUp() public { - T t = new T(10); - } - - function testSetupBad() public { - } - - function testSetupBad2() public { - } -} - - -contract T { - constructor(uint256 a) { - uint256 b = a - 100; - } -} \ No newline at end of file diff --git a/forge/testdata/FooTest.sol b/forge/testdata/FooTest.sol deleted file mode 100644 index a826c8636019..000000000000 --- a/forge/testdata/FooTest.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.8.1; - -contract DsTestMini { - bool public failed; - - function fail() private { - failed = true; - } - - function assertEq(uint a, uint b) internal { - if (a != b) { - fail(); - } - } -} - -contract FooTest is DsTestMini { - uint256 x; - - function setUp() public { - x = 1; - } - - function testX() public { - require(x == 1, "x is not one"); - } - - function testFailX() public { - assertEq(x, 2); - } -} diff --git a/forge/testdata/FooTest2.sol b/forge/testdata/FooTest2.sol deleted file mode 100644 index bdc17a53a2d7..000000000000 --- a/forge/testdata/FooTest2.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.8.1; - -contract FooBar { - uint256 x; - - function setUp() public { - x = 1; - } - - function testX() public { - require(x == 1, "x is not one"); - } -} diff --git a/forge/testdata/GreetTest.sol b/forge/testdata/GreetTest.sol deleted file mode 100644 index d1d10548f4fa..000000000000 --- a/forge/testdata/GreetTest.sol +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma abicoder v2; -pragma solidity =0.7.6; - -contract Greeter { - string public greeting; - - function greet(string memory _greeting) public { - greeting = _greeting; - } - - function gm() public { - greeting = "gm"; - } -} - -contract GreeterTestSetup { - Greeter greeter; - - function greeting() public view returns (string memory) { - return greeter.greeting(); - } - - function setUp() public { - greeter = new Greeter(); - } -} - -contract GreeterTest is GreeterTestSetup { - function greet(string memory _greeting) public { - greeter.greet(_greeting); - } - - function testShrinking(uint256 x, uint256 y) public { - require(x * y <= 100, "product greater than 100"); - } - - - function testStringFuzz(string memory myGreeting) public { - greeter.greet(myGreeting); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked(myGreeting)), "not equal"); - } - - function testFuzzFixedArray(uint256[2] memory x) public { - // filter out x[1] == 0 since it'll drain all our gas in the - // division by zero from all future tests - if (x[1] == 0) return; - require(x[1] / x[1] == 0); - } - - function testFuzzVariableArray(uint256[] memory x) public { - require(x[0] == x[1]); - } - - function testFuzzBytes1(bytes1 x) public { - require(x == 0); - } - - function testFuzzBytes14(bytes14 x) public { - require(x == 0); - } - - function testFuzzBytes32(bytes32 x) public { - require(x == 0); - } - - function testFuzzI256(int256 x) public { - require(x >= 0); - } - - struct Foo { - Bar bar; - } - - struct Bar { - uint256 baz; - } - - function testFuzzAbiCoderV2(Foo memory foo) public { - require(foo.bar.baz < 5); - } - - // check the positive case - function testGreeting() public { - greeter.greet("yo"); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked("yo")), "not equal"); - } - function testGreeting(string memory message) public { - greeter.greet(message); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked(message)), "not equal"); - } - function testGreeting(string memory message, string memory _message) public { - greeter.greet(message); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked(message)), "not equal"); - } - - - // check the unhappy case - function testFailGreeting() public { - greeter.greet("yo"); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked("hi")), "not equal to `hi`"); - } - - function testIsolation() public { - require(bytes(greeter.greeting()).length == 0); - } -} - -contract GmTest is GreeterTestSetup { - function testGm() public { - greeter.gm(); - require(keccak256(abi.encodePacked(greeter.greeting())) == keccak256(abi.encodePacked("gm")), "not equal"); - } -} diff --git a/forge/testdata/LibLinking.sol b/forge/testdata/LibLinking.sol deleted file mode 100644 index 53a59b1921fa..000000000000 --- a/forge/testdata/LibLinking.sol +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.11; - -// a library that needs to be linked with another library -library LibTestNested { - enum TestEnum2 { - A, - B, - C - } - - function foobar(TestEnum2 test) public view returns (uint256) { - return LibTest.foobar(101); - } -} - -// a library -library LibTest { - function foobar(uint256 a) public view returns (uint256) { - return a * 100; - } -} - - -// a contract that uses 2 linked libraries -contract Main { - function foo() public returns (uint256) { - return LibTest.foobar(1); - } - - function bar() public returns (uint256) { - return LibTestNested.foobar(LibTestNested.TestEnum2(0)); - } -} - -contract DsTestMini { - bool public failed; - - function fail() private { - failed = true; - } - - function assertEq(uint a, uint b) internal { - if (a != b) { - fail(); - } - } -} - - -contract LibLinkingTest is DsTestMini { - Main main; - function setUp() public { - main = new Main(); - } - - function testCall() public { - assertEq(100, main.foo()); - } - - function testCall2() public { - assertEq(10100, main.bar()); - } -} diff --git a/forge/testdata/WarmColdTest.sol b/forge/testdata/WarmColdTest.sol deleted file mode 100644 index 89c9782708e3..000000000000 --- a/forge/testdata/WarmColdTest.sol +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.7; - -contract DsTestMini { - bool public failed; - - function fail() private { - failed = true; - } - - function assertEq(uint a, uint b) internal { - if (a != b) { - fail(); - } - } -} - -contract Which { - uint256[] public s_playerFunds; - uint256 public s_totalFunds; - - constructor() { - s_playerFunds = [ - 1, - 15, - 22, - 199, - 234, - 5, - 234, - 5, - 2345, - 234, - 555, - 23423, - 55 - ]; - } - - function a() public { - uint256 totalFunds; - for (uint256 i = 0; i < s_playerFunds.length; i++) { - totalFunds = totalFunds + s_playerFunds[i]; - } - s_totalFunds = totalFunds; - } - - function b() external { - for (uint256 i = 0; i < s_playerFunds.length; i++) { - s_totalFunds += s_playerFunds[i]; - } - } - - function c() public { - uint256 totalFunds; - uint256[] memory playerFunds = s_playerFunds; - for (uint256 i = 0; i < playerFunds.length; i++) { - totalFunds = totalFunds + playerFunds[i]; - } - s_totalFunds = totalFunds; - } -} - -contract WhichTest is DsTestMini { - Which internal which; - - function setUp() public { - which = new Which(); - } - - function testA() public { - which.a(); - } - - function testB() public { - which.b(); - } - - function testC() public { - which.c(); - } -} diff --git a/forge/testdata/dapp-artifact.json b/forge/testdata/dapp-artifact.json deleted file mode 100644 index d8e604920654..000000000000 --- a/forge/testdata/dapp-artifact.json +++ /dev/null @@ -1 +0,0 @@ -{"contracts":{"lib/ds-test/src/test.sol":{"DSTest":{"abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"}],"name":"log","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"log_address","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"}],"name":"log_bytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"","type":"bytes32"}],"name":"log_bytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"","type":"int256"}],"name":"log_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"address","name":"val","type":"address"}],"name":"log_named_address","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"bytes","name":"val","type":"bytes"}],"name":"log_named_bytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"bytes32","name":"val","type":"bytes32"}],"name":"log_named_bytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"int256","name":"val","type":"int256"},{"indexed":false,"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"log_named_decimal_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"uint256","name":"val","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"log_named_decimal_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"int256","name":"val","type":"int256"}],"name":"log_named_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"val","type":"string"}],"name":"log_named_string","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"uint256","name":"val","type":"uint256"}],"name":"log_named_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"}],"name":"log_string","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"log_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"}],"name":"logs","type":"event"},{"inputs":[],"name":"IS_TEST","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"failed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"60806040526000805460ff19166001179055348015601c57600080fd5b50609e8061002b6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c8063ba414fa6146037578063fa7626d414605c575b600080fd5b600054604890610100900460ff1681565b604051901515815260200160405180910390f35b60005460489060ff168156fea2646970667358221220db9381fef6a0d3f3da8dbc7fd712ee2dcdf595f08471ca7b88ef34f103ce393d64736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 SLOAD PUSH1 0xFF NOT AND PUSH1 0x1 OR SWAP1 SSTORE CALLVALUE DUP1 ISZERO PUSH1 0x1C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x9E DUP1 PUSH2 0x2B PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xBA414FA6 EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0xFA7626D4 EQ PUSH1 0x5C JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x48 SWAP1 PUSH2 0x100 SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x48 SWAP1 PUSH1 0xFF AND DUP2 JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xDB SWAP4 DUP2 INVALID 0xF6 LOG0 0xD3 RETURN 0xDA DUP14 0xBC PUSH32 0xD712EE2DCDF595F08471CA7B88EF34F103CE393D64736F6C6343000807003300 ","sourceMap":"716:14223:0:-:0;;;1573:26;;;-1:-1:-1;;1573:26:0;1595:4;1573:26;;;716:14223;;;;;;;;;;;;;;;;"},"deployedBytecode":{"functionDebugData":{"@IS_TEST_532":{"entryPoint":null,"id":532,"parameterSlots":0,"returnSlots":0},"@failed_534":{"entryPoint":null,"id":534,"parameterSlots":0,"returnSlots":0},"abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1}},"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:203:7","statements":[{"nodeType":"YulBlock","src":"6:3:7","statements":[]},{"body":{"nodeType":"YulBlock","src":"109:92:7","statements":[{"nodeType":"YulAssignment","src":"119:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"131:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"142:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"127:3:7"},"nodeType":"YulFunctionCall","src":"127:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"119:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"161:9:7"},{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"186:6:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"179:6:7"},"nodeType":"YulFunctionCall","src":"179:14:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"172:6:7"},"nodeType":"YulFunctionCall","src":"172:22:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"154:6:7"},"nodeType":"YulFunctionCall","src":"154:41:7"},"nodeType":"YulExpressionStatement","src":"154:41:7"}]},"name":"abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"78:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"89:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"100:4:7","type":""}],"src":"14:187:7"}]},"contents":"{\n { }\n function abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, iszero(iszero(value0)))\n }\n}","id":7,"language":"Yul","name":"#utility.yul"}],"immutableReferences":{},"linkReferences":{},"object":"6080604052348015600f57600080fd5b506004361060325760003560e01c8063ba414fa6146037578063fa7626d414605c575b600080fd5b600054604890610100900460ff1681565b604051901515815260200160405180910390f35b60005460489060ff168156fea2646970667358221220db9381fef6a0d3f3da8dbc7fd712ee2dcdf595f08471ca7b88ef34f103ce393d64736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xBA414FA6 EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0xFA7626D4 EQ PUSH1 0x5C JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x48 SWAP1 PUSH2 0x100 SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x48 SWAP1 PUSH1 0xFF AND DUP2 JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xDB SWAP4 DUP2 INVALID 0xF6 LOG0 0xD3 RETURN 0xDA DUP14 0xBC PUSH32 0xD712EE2DCDF595F08471CA7B88EF34F103CE393D64736F6C6343000807003300 ","sourceMap":"716:14223:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1605:18;;;;;;;;;;;;;;;179:14:7;;172:22;154:41;;142:2;127:18;1605::0;;;;;;;1573:26;;;;;;;;"}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log_address\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"log_bytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"log_bytes32\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"name\":\"log_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"val\",\"type\":\"address\"}],\"name\":\"log_named_address\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"val\",\"type\":\"bytes\"}],\"name\":\"log_named_bytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"val\",\"type\":\"bytes32\"}],\"name\":\"log_named_bytes32\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"}],\"name\":\"log_named_decimal_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"}],\"name\":\"log_named_decimal_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"}],\"name\":\"log_named_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"val\",\"type\":\"string\"}],\"name\":\"log_named_string\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"log_named_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log_string\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"logs\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"IS_TEST\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"failed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/ds-test/src/test.sol\":\"DSTest\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/ds-test/src/test.sol\":{\"keccak256\":\"0x529f30c5939d75689f6a982f7f96b8898bed30bd90ec5b385b57cab681e12b00\",\"license\":\"GPL-3.0-or-later\",\"urls\":[\"bzz-raw://89075d5a96e87acef1d00cf556b409d1836728ec2e92f5629ceb5cae3d1e4354\",\"dweb:/ipfs/QmPAViJrxffEDns9GEMVSAzmr3soAzfrEg1CVuovwmNfnt\"]}},\"version\":1}","storageLayout":{"storage":[{"astId":532,"contract":"lib/ds-test/src/test.sol:DSTest","label":"IS_TEST","offset":0,"slot":"0","type":"t_bool"},{"astId":534,"contract":"lib/ds-test/src/test.sol:DSTest","label":"failed","offset":1,"slot":"0","type":"t_bool"}],"types":{"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"}}}}},"lib/openzeppelin-contracts/contracts/access/Ownable.sol":{"Ownable":{"abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"immutableReferences":{},"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module which provides a basic access control mechanism, where there is an account (an owner) that can be granted exclusive access to specific functions. By default, the owner account will be the one that deploys the contract. This can later be changed with {transferOwnership}. This module is used through inheritance. It will make available the modifier `onlyOwner`, which can be applied to your functions to restrict their use to the owner.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"details\":\"Initializes the contract setting the deployer as the initial owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":\"Ownable\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x6bb804a310218875e89d12c053e94a13a4607cdf7cc2052f3e52bd32a0dc50a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2ebbbe6d0011175bd9e7268b83de3f9c2f9d8d4cbfbaef12aff977d7d727163\",\"dweb:/ipfs/Qmd5c7Vxtis9wzkDNhxwc6A2QT5H9xn9kfjhx7qx44vpro\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x90565a39ae45c80f0468dc96c7b20d0afc3055f344c8203a0c9258239f350b9f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e8b38a7ac8e7b4463af00cf7fff1bf48ae9875765bf4f7751e100124d0bc8c\",\"dweb:/ipfs/QmWcsmkVr24xmmjfnBQZoemFniXjj3vwT78Cz6uqZW1Hux\"]}},\"version\":1}","storageLayout":{"storage":[{"astId":347,"contract":"lib/openzeppelin-contracts/contracts/access/Ownable.sol:Ownable","label":"_owner","offset":0,"slot":"0","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"}}}}},"lib/openzeppelin-contracts/contracts/utils/Context.sol":{"Context":{"abi":[],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"immutableReferences":{},"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":\"Context\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x90565a39ae45c80f0468dc96c7b20d0afc3055f344c8203a0c9258239f350b9f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e8b38a7ac8e7b4463af00cf7fff1bf48ae9875765bf4f7751e100124d0bc8c\",\"dweb:/ipfs/QmWcsmkVr24xmmjfnBQZoemFniXjj3vwT78Cz6uqZW1Hux\"]}},\"version\":1}","storageLayout":{"storage":[],"types":null}}},"src/Greeter.sol":{"Errors":{"abi":[],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220812e1e92ff3d0e2002622bd23d60d100337dd3d2c6e6a9371846f9b751f56a3864736f6c63430008070033","opcodes":"PUSH1 0x56 PUSH1 0x37 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH1 0x0 BYTE PUSH1 0x73 EQ PUSH1 0x2A JUMPI PUSH4 0x4E487B71 PUSH1 0xE0 SHL PUSH1 0x0 MSTORE PUSH1 0x0 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST ADDRESS PUSH1 0x0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 DUP2 0x2E 0x1E SWAP3 SELFDESTRUCT RETURNDATASIZE 0xE KECCAK256 MUL PUSH3 0x2BD23D PUSH1 0xD1 STOP CALLER PUSH30 0xD3D2C6E6A9371846F9B751F56A3864736F6C634300080700330000000000 ","sourceMap":"117:151:3:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;117:151:3;;;;;;;;;;;;;;;;;"},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"immutableReferences":{},"linkReferences":{},"object":"73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220812e1e92ff3d0e2002622bd23d60d100337dd3d2c6e6a9371846f9b751f56a3864736f6c63430008070033","opcodes":"PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 DUP2 0x2E 0x1E SWAP3 SELFDESTRUCT RETURNDATASIZE 0xE KECCAK256 MUL PUSH3 0x2BD23D PUSH1 0xD1 STOP CALLER PUSH30 0xD3D2C6E6A9371846F9B751F56A3864736F6C634300080700330000000000 ","sourceMap":"117:151:3:-:0;;;;;;;;"}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/Greeter.sol\":\"Errors\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x6bb804a310218875e89d12c053e94a13a4607cdf7cc2052f3e52bd32a0dc50a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2ebbbe6d0011175bd9e7268b83de3f9c2f9d8d4cbfbaef12aff977d7d727163\",\"dweb:/ipfs/Qmd5c7Vxtis9wzkDNhxwc6A2QT5H9xn9kfjhx7qx44vpro\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x90565a39ae45c80f0468dc96c7b20d0afc3055f344c8203a0c9258239f350b9f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e8b38a7ac8e7b4463af00cf7fff1bf48ae9875765bf4f7751e100124d0bc8c\",\"dweb:/ipfs/QmWcsmkVr24xmmjfnBQZoemFniXjj3vwT78Cz6uqZW1Hux\"]},\"src/Greeter.sol\":{\"keccak256\":\"0xc34bd8409a4fa4a474f29c6cb7d076cf9379c9c79e257c5cda7e5d114023f0f6\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://9db4f0c61754c54fd3b3ae58dfaf72865f8134e96959f7fc295b1a8e3b7511d7\",\"dweb:/ipfs/QmPuGbtNJ9rRaC7kFWqy76A9sfcGGcYAps6yPRrW28v4xd\"]}},\"version\":1}","storageLayout":{"storage":[],"types":null}},"Greeter":{"abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"gm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"name":"greet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"greeting","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{"@_363":{"entryPoint":null,"id":363,"parameterSlots":0,"returnSlots":0},"@_msgSender_2136":{"entryPoint":null,"id":2136,"parameterSlots":0,"returnSlots":1},"@_setOwner_442":{"entryPoint":31,"id":442,"parameterSlots":1,"returnSlots":0}},"generatedSources":[],"linkReferences":{},"object":"608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6108fe8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ead710c411610050578063ead710c4146100b6578063ef690cc0146100c9578063f2fde38b146100de57600080fd5b8063715018a6146100775780638da5cb5b14610081578063c0129d43146100ae575b600080fd5b61007f6100f1565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007f610183565b61007f6100c436600461067d565b6102ab565b6100d161037b565b6040516100a59190610768565b61007f6100ec366004610640565b610409565b60005473ffffffffffffffffffffffffffffffffffffffff163314610177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6101816000610532565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b61020f600a4361083d565b6000146040518060600160405280602181526020016108a86021913990610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b506040805180820190915260028082527f676d00000000000000000000000000000000000000000000000000000000000060209092019182526102a8916001916105a7565b50565b7f71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270816040516020016102dd919061074c565b6040516020818303038152906040528051906020012014156040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d00000000000000000000000081525090610363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b5080516103779060019060208401906105a7565b5050565b60018054610388906107e9565b80601f01602080910402602001604051908101604052809291908181526020018280546103b4906107e9565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff16331461048a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b73ffffffffffffffffffffffffffffffffffffffff811661052d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161016e565b6102a8815b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546105b3906107e9565b90600052602060002090601f0160209004810192826105d5576000855561061b565b82601f106105ee57805160ff191683800117855561061b565b8280016001018555821561061b579182015b8281111561061b578251825591602001919060010190610600565b5061062792915061062b565b5090565b5b80821115610627576000815560010161062c565b60006020828403121561065257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461067657600080fd5b9392505050565b60006020828403121561068f57600080fd5b813567ffffffffffffffff808211156106a757600080fd5b818401915084601f8301126106bb57600080fd5b8135818111156106cd576106cd610878565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071357610713610878565b8160405282815287602084870101111561072c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825161075e8184602087016107b9565b9190910192915050565b60208152600082518060208401526107878160408501602087016107b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b838110156107d45781810151838201526020016107bc565b838111156107e3576000848401525b50505050565b600181811c908216806107fd57607f821691505b60208210811415610837577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082610873577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a264697066735822122005045f3a3e5209d1d8290892555e955496efc239f089d2b9b89ba31daba73e9564736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1A CALLER PUSH2 0x1F JUMP JUMPDEST PUSH2 0x6F JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 DUP2 AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH2 0x8FE DUP1 PUSH2 0x7E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xEAD710C4 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0xEF690CC0 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0xDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0x715018A6 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0xC0129D43 EQ PUSH2 0xAE JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xF1 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x183 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x67D JUMP JUMPDEST PUSH2 0x2AB JUMP JUMPDEST PUSH2 0xD1 PUSH2 0x37B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xA5 SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xEC CALLDATASIZE PUSH1 0x4 PUSH2 0x640 JUMP JUMPDEST PUSH2 0x409 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x177 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x181 PUSH1 0x0 PUSH2 0x532 JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x204 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x20F PUSH1 0xA NUMBER PUSH2 0x83D JUMP JUMPDEST PUSH1 0x0 EQ PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x8A8 PUSH1 0x21 SWAP2 CODECOPY SWAP1 PUSH2 0x263 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x2 DUP1 DUP3 MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 SWAP1 SWAP3 ADD SWAP2 DUP3 MSTORE PUSH2 0x2A8 SWAP2 PUSH1 0x1 SWAP2 PUSH2 0x5A7 JUMP JUMPDEST POP JUMP JUMPDEST PUSH32 0x71B78290913AF2ADDD8FCBE5766DE306AF2C8AFBC466CA891E207F73638C7270 DUP2 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2DD SWAP2 SWAP1 PUSH2 0x74C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ ISZERO PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP SWAP1 PUSH2 0x363 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP DUP1 MLOAD PUSH2 0x377 SWAP1 PUSH1 0x1 SWAP1 PUSH1 0x20 DUP5 ADD SWAP1 PUSH2 0x5A7 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH2 0x388 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x3B4 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x401 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x3D6 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x401 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x3E4 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x48A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND PUSH2 0x52D JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x26 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A206E6577206F776E657220697320746865207A65726F2061 PUSH1 0x44 DUP3 ADD MSTORE PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000 PUSH1 0x64 DUP3 ADD MSTORE PUSH1 0x84 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x2A8 DUP2 JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x5B3 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x5D5 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0x5EE JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH2 0x61B JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x61B JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x600 JUMP JUMPDEST POP PUSH2 0x627 SWAP3 SWAP2 POP PUSH2 0x62B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x627 JUMPI PUSH1 0x0 DUP2 SSTORE PUSH1 0x1 ADD PUSH2 0x62C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x652 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x676 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x68F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x6A7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x6CD JUMPI PUSH2 0x6CD PUSH2 0x878 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x713 JUMPI PUSH2 0x713 PUSH2 0x878 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x72C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x75E DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 DUP3 MLOAD DUP1 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x787 DUP2 PUSH1 0x40 DUP6 ADD PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP2 SWAP1 SWAP2 ADD PUSH1 0x40 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x7D4 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x7BC JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x7E3 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SHR SWAP1 DUP3 AND DUP1 PUSH2 0x7FD JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 EQ ISZERO PUSH2 0x837 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH2 0x873 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x12 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP MOD SWAP1 JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID PUSH10 0x6E76616C696420626C6F PUSH4 0x6B206E75 PUSH14 0x6265722C20706C65617365207761 PUSH10 0x74A26469706673582212 KECCAK256 SDIV DIV 0x5F GASPRICE RETURNDATACOPY MSTORE MULMOD 0xD1 0xD8 0x29 ADDMOD SWAP3 SSTORE 0x5E SWAP6 SLOAD SWAP7 0xEF 0xC2 CODECOPY CREATE DUP10 0xD2 0xB9 0xB8 SWAP12 LOG3 SAR 0xAB 0xA7 RETURNDATACOPY SWAP6 PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER ","sourceMap":"270:379:3:-:0;;;;;;;;;;;;-1:-1:-1;867:23:1;666:10:2;867:9:1;:23::i;:::-;270:379:3;;2041:169:1;2096:16;2115:6;;-1:-1:-1;2131:17:1;;-1:-1:-1;2131:17:1;;;;;;;;2163:40;;2115:6;;;2131:17;;2115:6;;2163:40;;;2086:124;2041:169;:::o;270:379:3:-;;;;;;;"},"deployedBytecode":{"functionDebugData":{"@_msgSender_2136":{"entryPoint":null,"id":2136,"parameterSlots":0,"returnSlots":1},"@_setOwner_442":{"entryPoint":1330,"id":442,"parameterSlots":1,"returnSlots":0},"@gm_34":{"entryPoint":387,"id":34,"parameterSlots":0,"returnSlots":0},"@greet_59":{"entryPoint":683,"id":59,"parameterSlots":1,"returnSlots":0},"@greeting_13":{"entryPoint":891,"id":13,"parameterSlots":0,"returnSlots":0},"@owner_372":{"entryPoint":null,"id":372,"parameterSlots":0,"returnSlots":1},"@renounceOwnership_400":{"entryPoint":241,"id":400,"parameterSlots":0,"returnSlots":0},"@transferOwnership_423":{"entryPoint":1033,"id":423,"parameterSlots":1,"returnSlots":0},"abi_decode_tuple_t_address":{"entryPoint":1600,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_tuple_t_string_memory_ptr":{"entryPoint":1661,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed":{"entryPoint":1868,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_address__to_t_address__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":1896,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_stringliteral_245f15ff17f551913a7a18385165551503906a406f905ac1c2437281a7cd0cfe__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":1,"returnSlots":1},"abi_encode_tuple_t_stringliteral_9924ebdf1add33d25d4ef888e16131f0a5687b0580a36c21b5c301a6c462effe__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":1,"returnSlots":1},"copy_memory_to_memory":{"entryPoint":1977,"id":null,"parameterSlots":3,"returnSlots":0},"extract_byte_array_length":{"entryPoint":2025,"id":null,"parameterSlots":1,"returnSlots":1},"mod_t_uint256":{"entryPoint":2109,"id":null,"parameterSlots":2,"returnSlots":1},"panic_error_0x41":{"entryPoint":2168,"id":null,"parameterSlots":0,"returnSlots":0}},"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:4203:7","statements":[{"nodeType":"YulBlock","src":"6:3:7","statements":[]},{"body":{"nodeType":"YulBlock","src":"84:239:7","statements":[{"body":{"nodeType":"YulBlock","src":"130:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"139:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"142:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"132:6:7"},"nodeType":"YulFunctionCall","src":"132:12:7"},"nodeType":"YulExpressionStatement","src":"132:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"105:7:7"},{"name":"headStart","nodeType":"YulIdentifier","src":"114:9:7"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"101:3:7"},"nodeType":"YulFunctionCall","src":"101:23:7"},{"kind":"number","nodeType":"YulLiteral","src":"126:2:7","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"97:3:7"},"nodeType":"YulFunctionCall","src":"97:32:7"},"nodeType":"YulIf","src":"94:52:7"},{"nodeType":"YulVariableDeclaration","src":"155:36:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"181:9:7"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"168:12:7"},"nodeType":"YulFunctionCall","src":"168:23:7"},"variables":[{"name":"value","nodeType":"YulTypedName","src":"159:5:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"277:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"286:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"289:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"279:6:7"},"nodeType":"YulFunctionCall","src":"279:12:7"},"nodeType":"YulExpressionStatement","src":"279:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"213:5:7"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"224:5:7"},{"kind":"number","nodeType":"YulLiteral","src":"231:42:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffff"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"220:3:7"},"nodeType":"YulFunctionCall","src":"220:54:7"}],"functionName":{"name":"eq","nodeType":"YulIdentifier","src":"210:2:7"},"nodeType":"YulFunctionCall","src":"210:65:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"203:6:7"},"nodeType":"YulFunctionCall","src":"203:73:7"},"nodeType":"YulIf","src":"200:93:7"},{"nodeType":"YulAssignment","src":"302:15:7","value":{"name":"value","nodeType":"YulIdentifier","src":"312:5:7"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"302:6:7"}]}]},"name":"abi_decode_tuple_t_address","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"50:9:7","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"61:7:7","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"73:6:7","type":""}],"src":"14:309:7"},{"body":{"nodeType":"YulBlock","src":"408:901:7","statements":[{"body":{"nodeType":"YulBlock","src":"454:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"463:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"466:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"456:6:7"},"nodeType":"YulFunctionCall","src":"456:12:7"},"nodeType":"YulExpressionStatement","src":"456:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"429:7:7"},{"name":"headStart","nodeType":"YulIdentifier","src":"438:9:7"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"425:3:7"},"nodeType":"YulFunctionCall","src":"425:23:7"},{"kind":"number","nodeType":"YulLiteral","src":"450:2:7","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"421:3:7"},"nodeType":"YulFunctionCall","src":"421:32:7"},"nodeType":"YulIf","src":"418:52:7"},{"nodeType":"YulVariableDeclaration","src":"479:37:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"506:9:7"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"493:12:7"},"nodeType":"YulFunctionCall","src":"493:23:7"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"483:6:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"525:28:7","value":{"kind":"number","nodeType":"YulLiteral","src":"535:18:7","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"529:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"580:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"589:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"592:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"582:6:7"},"nodeType":"YulFunctionCall","src":"582:12:7"},"nodeType":"YulExpressionStatement","src":"582:12:7"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"568:6:7"},{"name":"_1","nodeType":"YulIdentifier","src":"576:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"565:2:7"},"nodeType":"YulFunctionCall","src":"565:14:7"},"nodeType":"YulIf","src":"562:34:7"},{"nodeType":"YulVariableDeclaration","src":"605:32:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"619:9:7"},{"name":"offset","nodeType":"YulIdentifier","src":"630:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"615:3:7"},"nodeType":"YulFunctionCall","src":"615:22:7"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"609:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"685:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"694:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"697:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"687:6:7"},"nodeType":"YulFunctionCall","src":"687:12:7"},"nodeType":"YulExpressionStatement","src":"687:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"664:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"668:4:7","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"660:3:7"},"nodeType":"YulFunctionCall","src":"660:13:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"675:7:7"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"656:3:7"},"nodeType":"YulFunctionCall","src":"656:27:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"649:6:7"},"nodeType":"YulFunctionCall","src":"649:35:7"},"nodeType":"YulIf","src":"646:55:7"},{"nodeType":"YulVariableDeclaration","src":"710:26:7","value":{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"733:2:7"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"720:12:7"},"nodeType":"YulFunctionCall","src":"720:16:7"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"714:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"759:22:7","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"761:16:7"},"nodeType":"YulFunctionCall","src":"761:18:7"},"nodeType":"YulExpressionStatement","src":"761:18:7"}]},"condition":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"751:2:7"},{"name":"_1","nodeType":"YulIdentifier","src":"755:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"748:2:7"},"nodeType":"YulFunctionCall","src":"748:10:7"},"nodeType":"YulIf","src":"745:36:7"},{"nodeType":"YulVariableDeclaration","src":"790:76:7","value":{"kind":"number","nodeType":"YulLiteral","src":"800:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"},"variables":[{"name":"_4","nodeType":"YulTypedName","src":"794:2:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"875:23:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"895:2:7","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"889:5:7"},"nodeType":"YulFunctionCall","src":"889:9:7"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"879:6:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"907:71:7","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"929:6:7"},{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"953:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"957:4:7","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"949:3:7"},"nodeType":"YulFunctionCall","src":"949:13:7"},{"name":"_4","nodeType":"YulIdentifier","src":"964:2:7"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"945:3:7"},"nodeType":"YulFunctionCall","src":"945:22:7"},{"kind":"number","nodeType":"YulLiteral","src":"969:2:7","type":"","value":"63"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"941:3:7"},"nodeType":"YulFunctionCall","src":"941:31:7"},{"name":"_4","nodeType":"YulIdentifier","src":"974:2:7"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"937:3:7"},"nodeType":"YulFunctionCall","src":"937:40:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"925:3:7"},"nodeType":"YulFunctionCall","src":"925:53:7"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"911:10:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"1037:22:7","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"1039:16:7"},"nodeType":"YulFunctionCall","src":"1039:18:7"},"nodeType":"YulExpressionStatement","src":"1039:18:7"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"996:10:7"},{"name":"_1","nodeType":"YulIdentifier","src":"1008:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"993:2:7"},"nodeType":"YulFunctionCall","src":"993:18:7"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1016:10:7"},{"name":"memPtr","nodeType":"YulIdentifier","src":"1028:6:7"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"1013:2:7"},"nodeType":"YulFunctionCall","src":"1013:22:7"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"990:2:7"},"nodeType":"YulFunctionCall","src":"990:46:7"},"nodeType":"YulIf","src":"987:72:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1075:2:7","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1079:10:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1068:6:7"},"nodeType":"YulFunctionCall","src":"1068:22:7"},"nodeType":"YulExpressionStatement","src":"1068:22:7"},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1106:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"1114:2:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1099:6:7"},"nodeType":"YulFunctionCall","src":"1099:18:7"},"nodeType":"YulExpressionStatement","src":"1099:18:7"},{"body":{"nodeType":"YulBlock","src":"1163:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1172:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1175:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1165:6:7"},"nodeType":"YulFunctionCall","src":"1165:12:7"},"nodeType":"YulExpressionStatement","src":"1165:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"1140:2:7"},{"name":"_3","nodeType":"YulIdentifier","src":"1144:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1136:3:7"},"nodeType":"YulFunctionCall","src":"1136:11:7"},{"kind":"number","nodeType":"YulLiteral","src":"1149:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1132:3:7"},"nodeType":"YulFunctionCall","src":"1132:20:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"1154:7:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1129:2:7"},"nodeType":"YulFunctionCall","src":"1129:33:7"},"nodeType":"YulIf","src":"1126:53:7"},{"expression":{"arguments":[{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1205:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1213:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1201:3:7"},"nodeType":"YulFunctionCall","src":"1201:15:7"},{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"1222:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"1226:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1218:3:7"},"nodeType":"YulFunctionCall","src":"1218:11:7"},{"name":"_3","nodeType":"YulIdentifier","src":"1231:2:7"}],"functionName":{"name":"calldatacopy","nodeType":"YulIdentifier","src":"1188:12:7"},"nodeType":"YulFunctionCall","src":"1188:46:7"},"nodeType":"YulExpressionStatement","src":"1188:46:7"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1258:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"1266:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1254:3:7"},"nodeType":"YulFunctionCall","src":"1254:15:7"},{"kind":"number","nodeType":"YulLiteral","src":"1271:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1250:3:7"},"nodeType":"YulFunctionCall","src":"1250:24:7"},{"kind":"number","nodeType":"YulLiteral","src":"1276:1:7","type":"","value":"0"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1243:6:7"},"nodeType":"YulFunctionCall","src":"1243:35:7"},"nodeType":"YulExpressionStatement","src":"1243:35:7"},{"nodeType":"YulAssignment","src":"1287:16:7","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"1297:6:7"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1287:6:7"}]}]},"name":"abi_decode_tuple_t_string_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"374:9:7","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"385:7:7","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"397:6:7","type":""}],"src":"328:981:7"},{"body":{"nodeType":"YulBlock","src":"1453:137:7","statements":[{"nodeType":"YulVariableDeclaration","src":"1463:27:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1483:6:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1477:5:7"},"nodeType":"YulFunctionCall","src":"1477:13:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"1467:6:7","type":""}]},{"expression":{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1525:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1533:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1521:3:7"},"nodeType":"YulFunctionCall","src":"1521:17:7"},{"name":"pos","nodeType":"YulIdentifier","src":"1540:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"1545:6:7"}],"functionName":{"name":"copy_memory_to_memory","nodeType":"YulIdentifier","src":"1499:21:7"},"nodeType":"YulFunctionCall","src":"1499:53:7"},"nodeType":"YulExpressionStatement","src":"1499:53:7"},{"nodeType":"YulAssignment","src":"1561:23:7","value":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"1572:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"1577:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1568:3:7"},"nodeType":"YulFunctionCall","src":"1568:16:7"},"variableNames":[{"name":"end","nodeType":"YulIdentifier","src":"1561:3:7"}]}]},"name":"abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"pos","nodeType":"YulTypedName","src":"1429:3:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1434:6:7","type":""}],"returnVariables":[{"name":"end","nodeType":"YulTypedName","src":"1445:3:7","type":""}],"src":"1314:276:7"},{"body":{"nodeType":"YulBlock","src":"1696:125:7","statements":[{"nodeType":"YulAssignment","src":"1706:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1718:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"1729:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1714:3:7"},"nodeType":"YulFunctionCall","src":"1714:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1706:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1748:9:7"},{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1763:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1771:42:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffff"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"1759:3:7"},"nodeType":"YulFunctionCall","src":"1759:55:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1741:6:7"},"nodeType":"YulFunctionCall","src":"1741:74:7"},"nodeType":"YulExpressionStatement","src":"1741:74:7"}]},"name":"abi_encode_tuple_t_address__to_t_address__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1665:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1676:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1687:4:7","type":""}],"src":"1595:226:7"},{"body":{"nodeType":"YulBlock","src":"1947:321:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1964:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"1975:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1957:6:7"},"nodeType":"YulFunctionCall","src":"1957:21:7"},"nodeType":"YulExpressionStatement","src":"1957:21:7"},{"nodeType":"YulVariableDeclaration","src":"1987:27:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"2007:6:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"2001:5:7"},"nodeType":"YulFunctionCall","src":"2001:13:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"1991:6:7","type":""}]},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2034:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2045:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2030:3:7"},"nodeType":"YulFunctionCall","src":"2030:18:7"},{"name":"length","nodeType":"YulIdentifier","src":"2050:6:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2023:6:7"},"nodeType":"YulFunctionCall","src":"2023:34:7"},"nodeType":"YulExpressionStatement","src":"2023:34:7"},{"expression":{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"2092:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"2100:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2088:3:7"},"nodeType":"YulFunctionCall","src":"2088:15:7"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2109:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2120:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2105:3:7"},"nodeType":"YulFunctionCall","src":"2105:18:7"},{"name":"length","nodeType":"YulIdentifier","src":"2125:6:7"}],"functionName":{"name":"copy_memory_to_memory","nodeType":"YulIdentifier","src":"2066:21:7"},"nodeType":"YulFunctionCall","src":"2066:66:7"},"nodeType":"YulExpressionStatement","src":"2066:66:7"},{"nodeType":"YulAssignment","src":"2141:121:7","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2157:9:7"},{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2176:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"2184:2:7","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2172:3:7"},"nodeType":"YulFunctionCall","src":"2172:15:7"},{"kind":"number","nodeType":"YulLiteral","src":"2189:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"2168:3:7"},"nodeType":"YulFunctionCall","src":"2168:88:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2153:3:7"},"nodeType":"YulFunctionCall","src":"2153:104:7"},{"kind":"number","nodeType":"YulLiteral","src":"2259:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2149:3:7"},"nodeType":"YulFunctionCall","src":"2149:113:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"2141:4:7"}]}]},"name":"abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1916:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1927:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1938:4:7","type":""}],"src":"1826:442:7"},{"body":{"nodeType":"YulBlock","src":"2447:228:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2464:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2475:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2457:6:7"},"nodeType":"YulFunctionCall","src":"2457:21:7"},"nodeType":"YulExpressionStatement","src":"2457:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2498:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2509:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2494:3:7"},"nodeType":"YulFunctionCall","src":"2494:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"2514:2:7","type":"","value":"38"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2487:6:7"},"nodeType":"YulFunctionCall","src":"2487:30:7"},"nodeType":"YulExpressionStatement","src":"2487:30:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2537:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2548:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2533:3:7"},"nodeType":"YulFunctionCall","src":"2533:18:7"},{"hexValue":"4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061","kind":"string","nodeType":"YulLiteral","src":"2553:34:7","type":"","value":"Ownable: new owner is the zero a"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2526:6:7"},"nodeType":"YulFunctionCall","src":"2526:62:7"},"nodeType":"YulExpressionStatement","src":"2526:62:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2608:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2619:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2604:3:7"},"nodeType":"YulFunctionCall","src":"2604:18:7"},{"hexValue":"646472657373","kind":"string","nodeType":"YulLiteral","src":"2624:8:7","type":"","value":"ddress"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2597:6:7"},"nodeType":"YulFunctionCall","src":"2597:36:7"},"nodeType":"YulExpressionStatement","src":"2597:36:7"},{"nodeType":"YulAssignment","src":"2642:27:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2654:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2665:3:7","type":"","value":"128"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2650:3:7"},"nodeType":"YulFunctionCall","src":"2650:19:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"2642:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_245f15ff17f551913a7a18385165551503906a406f905ac1c2437281a7cd0cfe__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2424:9:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2438:4:7","type":""}],"src":"2273:402:7"},{"body":{"nodeType":"YulBlock","src":"2854:182:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2871:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2882:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2864:6:7"},"nodeType":"YulFunctionCall","src":"2864:21:7"},"nodeType":"YulExpressionStatement","src":"2864:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2905:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2916:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2901:3:7"},"nodeType":"YulFunctionCall","src":"2901:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"2921:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2894:6:7"},"nodeType":"YulFunctionCall","src":"2894:30:7"},"nodeType":"YulExpressionStatement","src":"2894:30:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2944:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2955:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2940:3:7"},"nodeType":"YulFunctionCall","src":"2940:18:7"},{"hexValue":"4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572","kind":"string","nodeType":"YulLiteral","src":"2960:34:7","type":"","value":"Ownable: caller is not the owner"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2933:6:7"},"nodeType":"YulFunctionCall","src":"2933:62:7"},"nodeType":"YulExpressionStatement","src":"2933:62:7"},{"nodeType":"YulAssignment","src":"3004:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3016:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3027:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3012:3:7"},"nodeType":"YulFunctionCall","src":"3012:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3004:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_9924ebdf1add33d25d4ef888e16131f0a5687b0580a36c21b5c301a6c462effe__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2831:9:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2845:4:7","type":""}],"src":"2680:356:7"},{"body":{"nodeType":"YulBlock","src":"3094:205:7","statements":[{"nodeType":"YulVariableDeclaration","src":"3104:10:7","value":{"kind":"number","nodeType":"YulLiteral","src":"3113:1:7","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"3108:1:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"3173:63:7","statements":[{"expression":{"arguments":[{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"3198:3:7"},{"name":"i","nodeType":"YulIdentifier","src":"3203:1:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3194:3:7"},"nodeType":"YulFunctionCall","src":"3194:11:7"},{"arguments":[{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"3217:3:7"},{"name":"i","nodeType":"YulIdentifier","src":"3222:1:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3213:3:7"},"nodeType":"YulFunctionCall","src":"3213:11:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"3207:5:7"},"nodeType":"YulFunctionCall","src":"3207:18:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3187:6:7"},"nodeType":"YulFunctionCall","src":"3187:39:7"},"nodeType":"YulExpressionStatement","src":"3187:39:7"}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"3134:1:7"},{"name":"length","nodeType":"YulIdentifier","src":"3137:6:7"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"3131:2:7"},"nodeType":"YulFunctionCall","src":"3131:13:7"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"3145:19:7","statements":[{"nodeType":"YulAssignment","src":"3147:15:7","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"3156:1:7"},{"kind":"number","nodeType":"YulLiteral","src":"3159:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3152:3:7"},"nodeType":"YulFunctionCall","src":"3152:10:7"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"3147:1:7"}]}]},"pre":{"nodeType":"YulBlock","src":"3127:3:7","statements":[]},"src":"3123:113:7"},{"body":{"nodeType":"YulBlock","src":"3262:31:7","statements":[{"expression":{"arguments":[{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"3275:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"3280:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3271:3:7"},"nodeType":"YulFunctionCall","src":"3271:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"3289:1:7","type":"","value":"0"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3264:6:7"},"nodeType":"YulFunctionCall","src":"3264:27:7"},"nodeType":"YulExpressionStatement","src":"3264:27:7"}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"3251:1:7"},{"name":"length","nodeType":"YulIdentifier","src":"3254:6:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"3248:2:7"},"nodeType":"YulFunctionCall","src":"3248:13:7"},"nodeType":"YulIf","src":"3245:48:7"}]},"name":"copy_memory_to_memory","nodeType":"YulFunctionDefinition","parameters":[{"name":"src","nodeType":"YulTypedName","src":"3072:3:7","type":""},{"name":"dst","nodeType":"YulTypedName","src":"3077:3:7","type":""},{"name":"length","nodeType":"YulTypedName","src":"3082:6:7","type":""}],"src":"3041:258:7"},{"body":{"nodeType":"YulBlock","src":"3359:382:7","statements":[{"nodeType":"YulAssignment","src":"3369:22:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3383:1:7","type":"","value":"1"},{"name":"data","nodeType":"YulIdentifier","src":"3386:4:7"}],"functionName":{"name":"shr","nodeType":"YulIdentifier","src":"3379:3:7"},"nodeType":"YulFunctionCall","src":"3379:12:7"},"variableNames":[{"name":"length","nodeType":"YulIdentifier","src":"3369:6:7"}]},{"nodeType":"YulVariableDeclaration","src":"3400:38:7","value":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"3430:4:7"},{"kind":"number","nodeType":"YulLiteral","src":"3436:1:7","type":"","value":"1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"3426:3:7"},"nodeType":"YulFunctionCall","src":"3426:12:7"},"variables":[{"name":"outOfPlaceEncoding","nodeType":"YulTypedName","src":"3404:18:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"3477:31:7","statements":[{"nodeType":"YulAssignment","src":"3479:27:7","value":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"3493:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"3501:4:7","type":"","value":"0x7f"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"3489:3:7"},"nodeType":"YulFunctionCall","src":"3489:17:7"},"variableNames":[{"name":"length","nodeType":"YulIdentifier","src":"3479:6:7"}]}]},"condition":{"arguments":[{"name":"outOfPlaceEncoding","nodeType":"YulIdentifier","src":"3457:18:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"3450:6:7"},"nodeType":"YulFunctionCall","src":"3450:26:7"},"nodeType":"YulIf","src":"3447:61:7"},{"body":{"nodeType":"YulBlock","src":"3567:168:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3588:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3591:77:7","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3581:6:7"},"nodeType":"YulFunctionCall","src":"3581:88:7"},"nodeType":"YulExpressionStatement","src":"3581:88:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3689:1:7","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"3692:4:7","type":"","value":"0x22"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3682:6:7"},"nodeType":"YulFunctionCall","src":"3682:15:7"},"nodeType":"YulExpressionStatement","src":"3682:15:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3717:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3720:4:7","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"3710:6:7"},"nodeType":"YulFunctionCall","src":"3710:15:7"},"nodeType":"YulExpressionStatement","src":"3710:15:7"}]},"condition":{"arguments":[{"name":"outOfPlaceEncoding","nodeType":"YulIdentifier","src":"3523:18:7"},{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"3546:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"3554:2:7","type":"","value":"32"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"3543:2:7"},"nodeType":"YulFunctionCall","src":"3543:14:7"}],"functionName":{"name":"eq","nodeType":"YulIdentifier","src":"3520:2:7"},"nodeType":"YulFunctionCall","src":"3520:38:7"},"nodeType":"YulIf","src":"3517:218:7"}]},"name":"extract_byte_array_length","nodeType":"YulFunctionDefinition","parameters":[{"name":"data","nodeType":"YulTypedName","src":"3339:4:7","type":""}],"returnVariables":[{"name":"length","nodeType":"YulTypedName","src":"3348:6:7","type":""}],"src":"3304:437:7"},{"body":{"nodeType":"YulBlock","src":"3784:228:7","statements":[{"body":{"nodeType":"YulBlock","src":"3815:168:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3836:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3839:77:7","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3829:6:7"},"nodeType":"YulFunctionCall","src":"3829:88:7"},"nodeType":"YulExpressionStatement","src":"3829:88:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3937:1:7","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"3940:4:7","type":"","value":"0x12"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3930:6:7"},"nodeType":"YulFunctionCall","src":"3930:15:7"},"nodeType":"YulExpressionStatement","src":"3930:15:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3965:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3968:4:7","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"3958:6:7"},"nodeType":"YulFunctionCall","src":"3958:15:7"},"nodeType":"YulExpressionStatement","src":"3958:15:7"}]},"condition":{"arguments":[{"name":"y","nodeType":"YulIdentifier","src":"3804:1:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"3797:6:7"},"nodeType":"YulFunctionCall","src":"3797:9:7"},"nodeType":"YulIf","src":"3794:189:7"},{"nodeType":"YulAssignment","src":"3992:14:7","value":{"arguments":[{"name":"x","nodeType":"YulIdentifier","src":"4001:1:7"},{"name":"y","nodeType":"YulIdentifier","src":"4004:1:7"}],"functionName":{"name":"mod","nodeType":"YulIdentifier","src":"3997:3:7"},"nodeType":"YulFunctionCall","src":"3997:9:7"},"variableNames":[{"name":"r","nodeType":"YulIdentifier","src":"3992:1:7"}]}]},"name":"mod_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"x","nodeType":"YulTypedName","src":"3769:1:7","type":""},{"name":"y","nodeType":"YulTypedName","src":"3772:1:7","type":""}],"returnVariables":[{"name":"r","nodeType":"YulTypedName","src":"3778:1:7","type":""}],"src":"3746:266:7"},{"body":{"nodeType":"YulBlock","src":"4049:152:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4066:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"4069:77:7","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4059:6:7"},"nodeType":"YulFunctionCall","src":"4059:88:7"},"nodeType":"YulExpressionStatement","src":"4059:88:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4163:1:7","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"4166:4:7","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4156:6:7"},"nodeType":"YulFunctionCall","src":"4156:15:7"},"nodeType":"YulExpressionStatement","src":"4156:15:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4187:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"4190:4:7","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"4180:6:7"},"nodeType":"YulFunctionCall","src":"4180:15:7"},"nodeType":"YulExpressionStatement","src":"4180:15:7"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"4017:184:7"}]},"contents":"{\n { }\n function abi_decode_tuple_t_address(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n let value := calldataload(headStart)\n if iszero(eq(value, and(value, 0xffffffffffffffffffffffffffffffffffffffff))) { revert(0, 0) }\n value0 := value\n }\n function abi_decode_tuple_t_string_memory_ptr(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n let offset := calldataload(headStart)\n let _1 := 0xffffffffffffffff\n if gt(offset, _1) { revert(0, 0) }\n let _2 := add(headStart, offset)\n if iszero(slt(add(_2, 0x1f), dataEnd)) { revert(0, 0) }\n let _3 := calldataload(_2)\n if gt(_3, _1) { panic_error_0x41() }\n let _4 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0\n let memPtr := mload(64)\n let newFreePtr := add(memPtr, and(add(and(add(_3, 0x1f), _4), 63), _4))\n if or(gt(newFreePtr, _1), lt(newFreePtr, memPtr)) { panic_error_0x41() }\n mstore(64, newFreePtr)\n mstore(memPtr, _3)\n if gt(add(add(_2, _3), 32), dataEnd) { revert(0, 0) }\n calldatacopy(add(memPtr, 32), add(_2, 32), _3)\n mstore(add(add(memPtr, _3), 32), 0)\n value0 := memPtr\n }\n function abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed(pos, value0) -> end\n {\n let length := mload(value0)\n copy_memory_to_memory(add(value0, 0x20), pos, length)\n end := add(pos, length)\n }\n function abi_encode_tuple_t_address__to_t_address__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, and(value0, 0xffffffffffffffffffffffffffffffffffffffff))\n }\n function abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed(headStart, value0) -> tail\n {\n mstore(headStart, 32)\n let length := mload(value0)\n mstore(add(headStart, 32), length)\n copy_memory_to_memory(add(value0, 32), add(headStart, 64), length)\n tail := add(add(headStart, and(add(length, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)), 64)\n }\n function abi_encode_tuple_t_stringliteral_245f15ff17f551913a7a18385165551503906a406f905ac1c2437281a7cd0cfe__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 38)\n mstore(add(headStart, 64), \"Ownable: new owner is the zero a\")\n mstore(add(headStart, 96), \"ddress\")\n tail := add(headStart, 128)\n }\n function abi_encode_tuple_t_stringliteral_9924ebdf1add33d25d4ef888e16131f0a5687b0580a36c21b5c301a6c462effe__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 32)\n mstore(add(headStart, 64), \"Ownable: caller is not the owner\")\n tail := add(headStart, 96)\n }\n function copy_memory_to_memory(src, dst, length)\n {\n let i := 0\n for { } lt(i, length) { i := add(i, 32) }\n {\n mstore(add(dst, i), mload(add(src, i)))\n }\n if gt(i, length) { mstore(add(dst, length), 0) }\n }\n function extract_byte_array_length(data) -> length\n {\n length := shr(1, data)\n let outOfPlaceEncoding := and(data, 1)\n if iszero(outOfPlaceEncoding) { length := and(length, 0x7f) }\n if eq(outOfPlaceEncoding, lt(length, 32))\n {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x22)\n revert(0, 0x24)\n }\n }\n function mod_t_uint256(x, y) -> r\n {\n if iszero(y)\n {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x12)\n revert(0, 0x24)\n }\n r := mod(x, y)\n }\n function panic_error_0x41()\n {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x41)\n revert(0, 0x24)\n }\n}","id":7,"language":"Yul","name":"#utility.yul"}],"immutableReferences":{},"linkReferences":{},"object":"608060405234801561001057600080fd5b50600436106100725760003560e01c8063ead710c411610050578063ead710c4146100b6578063ef690cc0146100c9578063f2fde38b146100de57600080fd5b8063715018a6146100775780638da5cb5b14610081578063c0129d43146100ae575b600080fd5b61007f6100f1565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007f610183565b61007f6100c436600461067d565b6102ab565b6100d161037b565b6040516100a59190610768565b61007f6100ec366004610640565b610409565b60005473ffffffffffffffffffffffffffffffffffffffff163314610177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6101816000610532565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b61020f600a4361083d565b6000146040518060600160405280602181526020016108a86021913990610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b506040805180820190915260028082527f676d00000000000000000000000000000000000000000000000000000000000060209092019182526102a8916001916105a7565b50565b7f71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270816040516020016102dd919061074c565b6040516020818303038152906040528051906020012014156040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d00000000000000000000000081525090610363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b5080516103779060019060208401906105a7565b5050565b60018054610388906107e9565b80601f01602080910402602001604051908101604052809291908181526020018280546103b4906107e9565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff16331461048a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b73ffffffffffffffffffffffffffffffffffffffff811661052d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161016e565b6102a8815b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546105b3906107e9565b90600052602060002090601f0160209004810192826105d5576000855561061b565b82601f106105ee57805160ff191683800117855561061b565b8280016001018555821561061b579182015b8281111561061b578251825591602001919060010190610600565b5061062792915061062b565b5090565b5b80821115610627576000815560010161062c565b60006020828403121561065257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461067657600080fd5b9392505050565b60006020828403121561068f57600080fd5b813567ffffffffffffffff808211156106a757600080fd5b818401915084601f8301126106bb57600080fd5b8135818111156106cd576106cd610878565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071357610713610878565b8160405282815287602084870101111561072c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825161075e8184602087016107b9565b9190910192915050565b60208152600082518060208401526107878160408501602087016107b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b838110156107d45781810151838201526020016107bc565b838111156107e3576000848401525b50505050565b600181811c908216806107fd57607f821691505b60208210811415610837577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082610873577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a264697066735822122005045f3a3e5209d1d8290892555e955496efc239f089d2b9b89ba31daba73e9564736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xEAD710C4 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0xEF690CC0 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0xDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0x715018A6 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0xC0129D43 EQ PUSH2 0xAE JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xF1 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x183 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x67D JUMP JUMPDEST PUSH2 0x2AB JUMP JUMPDEST PUSH2 0xD1 PUSH2 0x37B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xA5 SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xEC CALLDATASIZE PUSH1 0x4 PUSH2 0x640 JUMP JUMPDEST PUSH2 0x409 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x177 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x181 PUSH1 0x0 PUSH2 0x532 JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x204 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x20F PUSH1 0xA NUMBER PUSH2 0x83D JUMP JUMPDEST PUSH1 0x0 EQ PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x8A8 PUSH1 0x21 SWAP2 CODECOPY SWAP1 PUSH2 0x263 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x2 DUP1 DUP3 MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 SWAP1 SWAP3 ADD SWAP2 DUP3 MSTORE PUSH2 0x2A8 SWAP2 PUSH1 0x1 SWAP2 PUSH2 0x5A7 JUMP JUMPDEST POP JUMP JUMPDEST PUSH32 0x71B78290913AF2ADDD8FCBE5766DE306AF2C8AFBC466CA891E207F73638C7270 DUP2 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2DD SWAP2 SWAP1 PUSH2 0x74C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ ISZERO PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP SWAP1 PUSH2 0x363 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP DUP1 MLOAD PUSH2 0x377 SWAP1 PUSH1 0x1 SWAP1 PUSH1 0x20 DUP5 ADD SWAP1 PUSH2 0x5A7 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH2 0x388 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x3B4 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x401 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x3D6 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x401 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x3E4 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x48A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND PUSH2 0x52D JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x26 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A206E6577206F776E657220697320746865207A65726F2061 PUSH1 0x44 DUP3 ADD MSTORE PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000 PUSH1 0x64 DUP3 ADD MSTORE PUSH1 0x84 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x2A8 DUP2 JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x5B3 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x5D5 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0x5EE JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH2 0x61B JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x61B JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x600 JUMP JUMPDEST POP PUSH2 0x627 SWAP3 SWAP2 POP PUSH2 0x62B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x627 JUMPI PUSH1 0x0 DUP2 SSTORE PUSH1 0x1 ADD PUSH2 0x62C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x652 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x676 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x68F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x6A7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x6CD JUMPI PUSH2 0x6CD PUSH2 0x878 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x713 JUMPI PUSH2 0x713 PUSH2 0x878 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x72C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x75E DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 DUP3 MLOAD DUP1 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x787 DUP2 PUSH1 0x40 DUP6 ADD PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP2 SWAP1 SWAP2 ADD PUSH1 0x40 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x7D4 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x7BC JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x7E3 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SHR SWAP1 DUP3 AND DUP1 PUSH2 0x7FD JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 EQ ISZERO PUSH2 0x837 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH2 0x873 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x12 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP MOD SWAP1 JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID PUSH10 0x6E76616C696420626C6F PUSH4 0x6B206E75 PUSH14 0x6265722C20706C65617365207761 PUSH10 0x74A26469706673582212 KECCAK256 SDIV DIV 0x5F GASPRICE RETURNDATACOPY MSTORE MULMOD 0xD1 0xD8 0x29 ADDMOD SWAP3 SSTORE 0x5E SWAP6 SLOAD SWAP7 0xEF 0xC2 CODECOPY CREATE DUP10 0xD2 0xB9 0xB8 SWAP12 LOG3 SAR 0xAB 0xA7 RETURNDATACOPY SWAP6 PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER ","sourceMap":"270:379:3:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1605:92:1;;;:::i;:::-;;973:85;1019:7;1045:6;973:85;;1045:6;;;;1741:74:7;;1729:2;1714:18;973:85:1;;;;;;;;333:131:3;;;:::i;470:177::-;;;;;;:::i;:::-;;:::i;304:22::-;;;:::i;:::-;;;;;;;:::i;1846:189:1:-;;;;;;:::i;:::-;;:::i;1605:92::-;1019:7;1045:6;1185:23;1045:6;666:10:2;1185:23:1;1177:68;;;;;;;2882:2:7;1177:68:1;;;2864:21:7;;;2901:18;;;2894:30;2960:34;2940:18;;;2933:62;3012:18;;1177:68:1;;;;;;;;;1669:21:::1;1687:1;1669:9;:21::i;:::-;1605:92::o:0;333:131:3:-;1019:7:1;1045:6;1185:23;1045:6;666:10:2;1185:23:1;1177:68;;;;;;;2882:2:7;1177:68:1;;;2864:21:7;;;2901:18;;;2894:30;2960:34;2940:18;;;2933:62;3012:18;;1177:68:1;2680:356:7;1177:68:1;382:17:3::1;397:2;382:12;:17;:::i;:::-;403:1;382:22;406:25;;;;;;;;;;;;;;;;;374:58;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;442:15:3::1;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;;::::0;;::::1;::::0;;;::::1;::::0;:8:::1;::::0;:15:::1;:::i;:::-;;333:131::o:0;470:177::-;577:15;562:9;545:27;;;;;;;;:::i;:::-;;;;;;;;;;;;;535:38;;;;;;:57;;594:15;;;;;;;;;;;;;;;;;527:83;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;620:20:3;;;;:8;;:20;;;;;:::i;:::-;;470:177;:::o;304:22::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1846:189:1:-;1019:7;1045:6;1185:23;1045:6;666:10:2;1185:23:1;1177:68;;;;;;;2882:2:7;1177:68:1;;;2864:21:7;;;2901:18;;;2894:30;2960:34;2940:18;;;2933:62;3012:18;;1177:68:1;2680:356:7;1177:68:1;1934:22:::1;::::0;::::1;1926:73;;;::::0;::::1;::::0;;2475:2:7;1926:73:1::1;::::0;::::1;2457:21:7::0;2514:2;2494:18;;;2487:30;2553:34;2533:18;;;2526:62;2624:8;2604:18;;;2597:36;2650:19;;1926:73:1::1;2273:402:7::0;1926:73:1::1;2009:19;2019:8;2041:169:::0;2096:16;2115:6;;;2131:17;;;;;;;;;;2163:40;;2115:6;;;;;;;2163:40;;2096:16;2163:40;2086:124;2041:169;:::o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:309:7;73:6;126:2;114:9;105:7;101:23;97:32;94:52;;;142:1;139;132:12;94:52;181:9;168:23;231:42;224:5;220:54;213:5;210:65;200:93;;289:1;286;279:12;200:93;312:5;14:309;-1:-1:-1;;;14:309:7:o;328:981::-;397:6;450:2;438:9;429:7;425:23;421:32;418:52;;;466:1;463;456:12;418:52;506:9;493:23;535:18;576:2;568:6;565:14;562:34;;;592:1;589;582:12;562:34;630:6;619:9;615:22;605:32;;675:7;668:4;664:2;660:13;656:27;646:55;;697:1;694;687:12;646:55;733:2;720:16;755:2;751;748:10;745:36;;;761:18;;:::i;:::-;895:2;889:9;957:4;949:13;;800:66;945:22;;;969:2;941:31;937:40;925:53;;;993:18;;;1013:22;;;990:46;987:72;;;1039:18;;:::i;:::-;1079:10;1075:2;1068:22;1114:2;1106:6;1099:18;1154:7;1149:2;1144;1140;1136:11;1132:20;1129:33;1126:53;;;1175:1;1172;1165:12;1126:53;1231:2;1226;1222;1218:11;1213:2;1205:6;1201:15;1188:46;1276:1;1254:15;;;1271:2;1250:24;1243:35;;;;-1:-1:-1;1258:6:7;328:981;-1:-1:-1;;;;;328:981:7:o;1314:276::-;1445:3;1483:6;1477:13;1499:53;1545:6;1540:3;1533:4;1525:6;1521:17;1499:53;:::i;:::-;1568:16;;;;;1314:276;-1:-1:-1;;1314:276:7:o;1826:442::-;1975:2;1964:9;1957:21;1938:4;2007:6;2001:13;2050:6;2045:2;2034:9;2030:18;2023:34;2066:66;2125:6;2120:2;2109:9;2105:18;2100:2;2092:6;2088:15;2066:66;:::i;:::-;2184:2;2172:15;2189:66;2168:88;2153:104;;;;2259:2;2149:113;;1826:442;-1:-1:-1;;1826:442:7:o;3041:258::-;3113:1;3123:113;3137:6;3134:1;3131:13;3123:113;;;3213:11;;;3207:18;3194:11;;;3187:39;3159:2;3152:10;3123:113;;;3254:6;3251:1;3248:13;3245:48;;;3289:1;3280:6;3275:3;3271:16;3264:27;3245:48;;3041:258;;;:::o;3304:437::-;3383:1;3379:12;;;;3426;;;3447:61;;3501:4;3493:6;3489:17;3479:27;;3447:61;3554:2;3546:6;3543:14;3523:18;3520:38;3517:218;;;3591:77;3588:1;3581:88;3692:4;3689:1;3682:15;3720:4;3717:1;3710:15;3517:218;;3304:437;;;:::o;3746:266::-;3778:1;3804;3794:189;;3839:77;3836:1;3829:88;3940:4;3937:1;3930:15;3968:4;3965:1;3958:15;3794:189;-1:-1:-1;3997:9:7;;3746:266::o;4017:184::-;4069:77;4066:1;4059:88;4166:4;4163:1;4156:15;4190:4;4187:1;4180:15"}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"gm\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_greeting\",\"type\":\"string\"}],\"name\":\"greet\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"greeting\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/Greeter.sol\":\"Greeter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x6bb804a310218875e89d12c053e94a13a4607cdf7cc2052f3e52bd32a0dc50a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2ebbbe6d0011175bd9e7268b83de3f9c2f9d8d4cbfbaef12aff977d7d727163\",\"dweb:/ipfs/Qmd5c7Vxtis9wzkDNhxwc6A2QT5H9xn9kfjhx7qx44vpro\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x90565a39ae45c80f0468dc96c7b20d0afc3055f344c8203a0c9258239f350b9f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e8b38a7ac8e7b4463af00cf7fff1bf48ae9875765bf4f7751e100124d0bc8c\",\"dweb:/ipfs/QmWcsmkVr24xmmjfnBQZoemFniXjj3vwT78Cz6uqZW1Hux\"]},\"src/Greeter.sol\":{\"keccak256\":\"0xc34bd8409a4fa4a474f29c6cb7d076cf9379c9c79e257c5cda7e5d114023f0f6\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://9db4f0c61754c54fd3b3ae58dfaf72865f8134e96959f7fc295b1a8e3b7511d7\",\"dweb:/ipfs/QmPuGbtNJ9rRaC7kFWqy76A9sfcGGcYAps6yPRrW28v4xd\"]}},\"version\":1}","storageLayout":{"storage":[{"astId":347,"contract":"src/Greeter.sol:Greeter","label":"_owner","offset":0,"slot":"0","type":"t_address"},{"astId":13,"contract":"src/Greeter.sol:Greeter","label":"greeting","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}},"src/test/Greeter.t.sol":{"Gm":{"abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"}],"name":"log","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"log_address","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"}],"name":"log_bytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"","type":"bytes32"}],"name":"log_bytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"","type":"int256"}],"name":"log_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"address","name":"val","type":"address"}],"name":"log_named_address","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"bytes","name":"val","type":"bytes"}],"name":"log_named_bytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"bytes32","name":"val","type":"bytes32"}],"name":"log_named_bytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"int256","name":"val","type":"int256"},{"indexed":false,"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"log_named_decimal_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"uint256","name":"val","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"log_named_decimal_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"int256","name":"val","type":"int256"}],"name":"log_named_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"val","type":"string"}],"name":"log_named_string","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"uint256","name":"val","type":"uint256"}],"name":"log_named_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"}],"name":"log_string","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"log_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"}],"name":"logs","type":"event"},{"inputs":[],"name":"IS_TEST","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"failed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"setUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testNonOwnerCannotGm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testOwnerCanGmOnGoodBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testOwnerCannotGmOnBadBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"60806040526000805460ff1916600117905534801561001d57600080fd5b506119738061002d6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063a474cdb011610050578063a474cdb014610091578063ba414fa614610099578063fa7626d4146100bf57600080fd5b80630a9254e4146100775780632a11c35d146100815780638dc5d38014610089575b600080fd5b61007f6100cc565b005b61007f6102df565b61007f6104e1565b61007f610607565b6000546100ab90610100900460ff1681565b604051901515815260200160405180910390f35b6000546100ab9060ff1681565b6040516100d8906108cd565b604051809103906000f0801580156100f4573d6000803e3d6000fd5b50600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff93841681029190911791829055604051910490911690610153906108da565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f08015801561018c573d6000803e3d6000fd5b50600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92831617905560005460405162010000909104909116906101e8906108da565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f080158015610221573d6000803e3d6000fd5b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283161790556000546001546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081529083166004820152620100009091049091169063f2fde38b90602401600060405180830381600087803b1580156102c557600080fd5b505af11580156102d9573d6000803e3d6000fd5b50505050565b6040517f1f7b4f30000000000000000000000000000000000000000000000000000000008152600a6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90631f7b4f3090602401600060405180830381600087803b15801561034557600080fd5b505af1158015610359573d6000803e3d6000fd5b50505050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c0129d436040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103c757600080fd5b505af11580156103db573d6000803e3d6000fd5b505050506104df600060029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ef690cc06040518163ffffffff1660e01b815260040160006040518083038186803b15801561044a57600080fd5b505afa15801561045e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104a491908101906108e7565b6040518060400160405280600281526020017f676d00000000000000000000000000000000000000000000000000000000000081525061074a565b565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c0129d436040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561054b57600080fd5b505af192505050801561055c575060015b6105d657610568610b3e565b806308c379a014156105ca575061057d610b5a565b8061058857506105cc565b6105c7816040518060400160405280602081526020017f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525061074a565b50565b505b3d6000803e3d6000fd5b6104df600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b6040517f1f7b4f30000000000000000000000000000000000000000000000000000000008152600b6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90631f7b4f3090602401600060405180830381600087803b15801561066d57600080fd5b505af1158015610681573d6000803e3d6000fd5b50505050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c0129d436040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156106ef57600080fd5b505af1925050508015610700575060015b6105d65761070c610b3e565b806308c379a014156105ca5750610721610b5a565b8061072c57506105cc565b6105c78160405180606001604052806021815260200161191d602191395b8060405160200161075b91906109e7565b604051602081830303815290604052805190602001208260405160200161078291906109e7565b60405160208183030381529060405280519060200120146108c9577f41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f506040516108229060208082526024908201527f4572726f723a2061203d3d2062206e6f7420736174697366696564205b73747260408201527f696e675d00000000000000000000000000000000000000000000000000000000606082015260800190565b60405180910390a17f280f4446b28a1372417dda658d30b95b2992b12ac9c7f378535f29a97acf3583826040516108599190610a03565b60405180910390a17f280f4446b28a1372417dda658d30b95b2992b12ac9c7f378535f29a97acf3583816040516108909190610a51565b60405180910390a16108c9600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b5050565b61097c80610c0383390190565b61039e8061157f83390190565b6000602082840312156108f957600080fd5b815167ffffffffffffffff8082111561091157600080fd5b818401915084601f83011261092557600080fd5b81518181111561093757610937610b0f565b604051915061096e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160183610ac4565b80825285602082850101111561098357600080fd5b610994816020840160208601610a98565b50949350505050565b600081518084526109b5816020860160208601610a98565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082516109f9818460208701610a98565b9190910192915050565b60408152600960408201527f202056616c7565206100000000000000000000000000000000000000000000006060820152608060208201526000610a4a608083018461099d565b9392505050565b60408152600960408201527f202056616c7565206200000000000000000000000000000000000000000000006060820152608060208201526000610a4a608083018461099d565b60005b83811015610ab3578181015183820152602001610a9b565b838111156102d95750506000910152565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715610b0857610b08610b0f565b6040525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d1115610b575760046000803e5060005160e01c5b90565b600060443d1015610b685790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610bb657505050505090565b8285019150815181811115610bce5750505050505090565b843d8701016020828501011115610be85750505050505090565b610bf760208286010187610ac4565b50909594505050505056fe608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6108fe8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ead710c411610050578063ead710c4146100b6578063ef690cc0146100c9578063f2fde38b146100de57600080fd5b8063715018a6146100775780638da5cb5b14610081578063c0129d43146100ae575b600080fd5b61007f6100f1565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007f610183565b61007f6100c436600461067d565b6102ab565b6100d161037b565b6040516100a59190610768565b61007f6100ec366004610640565b610409565b60005473ffffffffffffffffffffffffffffffffffffffff163314610177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6101816000610532565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b61020f600a4361083d565b6000146040518060600160405280602181526020016108a86021913990610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b506040805180820190915260028082527f676d00000000000000000000000000000000000000000000000000000000000060209092019182526102a8916001916105a7565b50565b7f71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270816040516020016102dd919061074c565b6040516020818303038152906040528051906020012014156040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d00000000000000000000000081525090610363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b5080516103779060019060208401906105a7565b5050565b60018054610388906107e9565b80601f01602080910402602001604051908101604052809291908181526020018280546103b4906107e9565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff16331461048a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b73ffffffffffffffffffffffffffffffffffffffff811661052d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161016e565b6102a8815b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546105b3906107e9565b90600052602060002090601f0160209004810192826105d5576000855561061b565b82601f106105ee57805160ff191683800117855561061b565b8280016001018555821561061b579182015b8281111561061b578251825591602001919060010190610600565b5061062792915061062b565b5090565b5b80821115610627576000815560010161062c565b60006020828403121561065257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461067657600080fd5b9392505050565b60006020828403121561068f57600080fd5b813567ffffffffffffffff808211156106a757600080fd5b818401915084601f8301126106bb57600080fd5b8135818111156106cd576106cd610878565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071357610713610878565b8160405282815287602084870101111561072c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825161075e8184602087016107b9565b9190910192915050565b60208152600082518060208401526107878160408501602087016107b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b838110156107d45781810151838201526020016107bc565b838111156107e3576000848401525b50505050565b600181811c908216806107fd57607f821691505b60208210811415610837577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082610873577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a264697066735822122005045f3a3e5209d1d8290892555e955496efc239f089d2b9b89ba31daba73e9564736f6c63430008070033608060405234801561001057600080fd5b5060405161039e38038061039e83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61030b806100936000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c0129d431461003b578063ead710c414610045575b600080fd5b610043610058565b005b610043610053366004610164565b6100d9565b60008054604080517fc0129d43000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169263c0129d439260048084019382900301818387803b1580156100bf57600080fd5b505af11580156100d3573d6000803e3d6000fd5b50505050565b6000546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c49061012f908490600401610233565b600060405180830381600087803b15801561014957600080fd5b505af115801561015d573d6000803e3d6000fd5b5050505050565b60006020828403121561017657600080fd5b813567ffffffffffffffff8082111561018e57600080fd5b818401915084601f8301126101a257600080fd5b8135818111156101b4576101b46102a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101fa576101fa6102a6565b8160405282815287602084870101111561021357600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561026057858101830151858201604001528201610244565b81811115610272576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220bfa72ed9ea0d57905e92811e328260534806dbdb8ad58675306b2582254f247564736f6c63430008070033696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a26469706673582212207e86e36fa543460096d0ce1f27b7239468336340c4a0df5e85d3096f5c47f21e64736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 SLOAD PUSH1 0xFF NOT AND PUSH1 0x1 OR SWAP1 SSTORE CALLVALUE DUP1 ISZERO PUSH2 0x1D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1973 DUP1 PUSH2 0x2D PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xA474CDB0 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xA474CDB0 EQ PUSH2 0x91 JUMPI DUP1 PUSH4 0xBA414FA6 EQ PUSH2 0x99 JUMPI DUP1 PUSH4 0xFA7626D4 EQ PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0xA9254E4 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x2A11C35D EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0x8DC5D380 EQ PUSH2 0x89 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xCC JUMP JUMPDEST STOP JUMPDEST PUSH2 0x7F PUSH2 0x2DF JUMP JUMPDEST PUSH2 0x7F PUSH2 0x4E1 JUMP JUMPDEST PUSH2 0x7F PUSH2 0x607 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0xAB SWAP1 PUSH2 0x100 SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 SLOAD PUSH2 0xAB SWAP1 PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xD8 SWAP1 PUSH2 0x8CD JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0xF4 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000FFFF AND PUSH3 0x10000 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP4 DUP5 AND DUP2 MUL SWAP2 SWAP1 SWAP2 OR SWAP2 DUP3 SWAP1 SSTORE PUSH1 0x40 MLOAD SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x153 SWAP1 PUSH2 0x8DA JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x18C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x1 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x1E8 SWAP1 PUSH2 0x8DA JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x221 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x2 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xF2FDE38B00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 DUP4 AND PUSH1 0x4 DUP3 ADD MSTORE PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH4 0xF2FDE38B SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2C5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x2D9 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1F7B4F3000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0xA PUSH1 0x4 DUP3 ADD MSTORE PUSH20 0x7109709ECFA91A80626FF3989D68F67F5B1DD12D SWAP1 PUSH4 0x1F7B4F30 SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x345 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x359 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x1 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xC0129D43 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3C7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x3DB JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH2 0x4DF PUSH1 0x0 PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xEF690CC0 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x44A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x45E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x0 DUP3 RETURNDATACOPY PUSH1 0x1F RETURNDATASIZE SWAP1 DUP2 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND DUP3 ADD PUSH1 0x40 MSTORE PUSH2 0x4A4 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x8E7 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x2 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP PUSH2 0x74A JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x2 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xC0129D43 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x54B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL SWAP3 POP POP POP DUP1 ISZERO PUSH2 0x55C JUMPI POP PUSH1 0x1 JUMPDEST PUSH2 0x5D6 JUMPI PUSH2 0x568 PUSH2 0xB3E JUMP JUMPDEST DUP1 PUSH4 0x8C379A0 EQ ISZERO PUSH2 0x5CA JUMPI POP PUSH2 0x57D PUSH2 0xB5A JUMP JUMPDEST DUP1 PUSH2 0x588 JUMPI POP PUSH2 0x5CC JUMP JUMPDEST PUSH2 0x5C7 DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x20 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 DUP2 MSTORE POP PUSH2 0x74A JUMP JUMPDEST POP JUMP JUMPDEST POP JUMPDEST RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST PUSH2 0x4DF PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF AND PUSH2 0x100 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1F7B4F3000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0xB PUSH1 0x4 DUP3 ADD MSTORE PUSH20 0x7109709ECFA91A80626FF3989D68F67F5B1DD12D SWAP1 PUSH4 0x1F7B4F30 SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x66D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x681 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x1 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xC0129D43 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x6EF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL SWAP3 POP POP POP DUP1 ISZERO PUSH2 0x700 JUMPI POP PUSH1 0x1 JUMPDEST PUSH2 0x5D6 JUMPI PUSH2 0x70C PUSH2 0xB3E JUMP JUMPDEST DUP1 PUSH4 0x8C379A0 EQ ISZERO PUSH2 0x5CA JUMPI POP PUSH2 0x721 PUSH2 0xB5A JUMP JUMPDEST DUP1 PUSH2 0x72C JUMPI POP PUSH2 0x5CC JUMP JUMPDEST PUSH2 0x5C7 DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x191D PUSH1 0x21 SWAP2 CODECOPY JUMPDEST DUP1 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x75B SWAP2 SWAP1 PUSH2 0x9E7 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP3 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x782 SWAP2 SWAP1 PUSH2 0x9E7 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ PUSH2 0x8C9 JUMPI PUSH32 0x41304FACD9323D75B11BCDD609CB38EFFFFDB05710F7CAF0E9B16C6D9D709F50 PUSH1 0x40 MLOAD PUSH2 0x822 SWAP1 PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x24 SWAP1 DUP3 ADD MSTORE PUSH32 0x4572726F723A2061203D3D2062206E6F7420736174697366696564205B737472 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x696E675D00000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH32 0x280F4446B28A1372417DDA658D30B95B2992B12AC9C7F378535F29A97ACF3583 DUP3 PUSH1 0x40 MLOAD PUSH2 0x859 SWAP2 SWAP1 PUSH2 0xA03 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH32 0x280F4446B28A1372417DDA658D30B95B2992B12AC9C7F378535F29A97ACF3583 DUP2 PUSH1 0x40 MLOAD PUSH2 0x890 SWAP2 SWAP1 PUSH2 0xA51 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH2 0x8C9 PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF AND PUSH2 0x100 OR SWAP1 SSTORE JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH2 0x97C DUP1 PUSH2 0xC03 DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH2 0x39E DUP1 PUSH2 0x157F DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x8F9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x911 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x925 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD DUP2 DUP2 GT ISZERO PUSH2 0x937 JUMPI PUSH2 0x937 PUSH2 0xB0F JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP2 POP PUSH2 0x96E PUSH1 0x20 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP5 ADD AND ADD DUP4 PUSH2 0xAC4 JUMP JUMPDEST DUP1 DUP3 MSTORE DUP6 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x983 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x994 DUP2 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP7 ADD PUSH2 0xA98 JUMP JUMPDEST POP SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x9B5 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0xA98 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x9F9 DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0xA98 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x40 DUP2 MSTORE PUSH1 0x9 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x202056616C756520610000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x0 PUSH2 0xA4A PUSH1 0x80 DUP4 ADD DUP5 PUSH2 0x99D JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP2 MSTORE PUSH1 0x9 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x202056616C756520620000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x0 PUSH2 0xA4A PUSH1 0x80 DUP4 ADD DUP5 PUSH2 0x99D JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xAB3 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xA9B JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x2D9 JUMPI POP POP PUSH1 0x0 SWAP2 ADD MSTORE JUMP JUMPDEST PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP4 ADD AND DUP2 ADD DUP2 DUP2 LT PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT OR ISZERO PUSH2 0xB08 JUMPI PUSH2 0xB08 PUSH2 0xB0F JUMP JUMPDEST PUSH1 0x40 MSTORE POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST PUSH1 0x0 PUSH1 0x3 RETURNDATASIZE GT ISZERO PUSH2 0xB57 JUMPI PUSH1 0x4 PUSH1 0x0 DUP1 RETURNDATACOPY POP PUSH1 0x0 MLOAD PUSH1 0xE0 SHR JUMPDEST SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x44 RETURNDATASIZE LT ISZERO PUSH2 0xB68 JUMPI SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC DUP1 RETURNDATASIZE ADD PUSH1 0x4 DUP4 RETURNDATACOPY DUP2 MLOAD RETURNDATASIZE PUSH8 0xFFFFFFFFFFFFFFFF DUP2 PUSH1 0x24 DUP5 ADD GT DUP2 DUP5 GT OR ISZERO PUSH2 0xBB6 JUMPI POP POP POP POP POP SWAP1 JUMP JUMPDEST DUP3 DUP6 ADD SWAP2 POP DUP2 MLOAD DUP2 DUP2 GT ISZERO PUSH2 0xBCE JUMPI POP POP POP POP POP POP SWAP1 JUMP JUMPDEST DUP5 RETURNDATASIZE DUP8 ADD ADD PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0xBE8 JUMPI POP POP POP POP POP POP SWAP1 JUMP JUMPDEST PUSH2 0xBF7 PUSH1 0x20 DUP3 DUP7 ADD ADD DUP8 PUSH2 0xAC4 JUMP JUMPDEST POP SWAP1 SWAP6 SWAP5 POP POP POP POP POP JUMP INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1A CALLER PUSH2 0x1F JUMP JUMPDEST PUSH2 0x6F JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 DUP2 AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH2 0x8FE DUP1 PUSH2 0x7E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xEAD710C4 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0xEF690CC0 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0xDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0x715018A6 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0xC0129D43 EQ PUSH2 0xAE JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xF1 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x183 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x67D JUMP JUMPDEST PUSH2 0x2AB JUMP JUMPDEST PUSH2 0xD1 PUSH2 0x37B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xA5 SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xEC CALLDATASIZE PUSH1 0x4 PUSH2 0x640 JUMP JUMPDEST PUSH2 0x409 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x177 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x181 PUSH1 0x0 PUSH2 0x532 JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x204 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x20F PUSH1 0xA NUMBER PUSH2 0x83D JUMP JUMPDEST PUSH1 0x0 EQ PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x8A8 PUSH1 0x21 SWAP2 CODECOPY SWAP1 PUSH2 0x263 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x2 DUP1 DUP3 MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 SWAP1 SWAP3 ADD SWAP2 DUP3 MSTORE PUSH2 0x2A8 SWAP2 PUSH1 0x1 SWAP2 PUSH2 0x5A7 JUMP JUMPDEST POP JUMP JUMPDEST PUSH32 0x71B78290913AF2ADDD8FCBE5766DE306AF2C8AFBC466CA891E207F73638C7270 DUP2 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2DD SWAP2 SWAP1 PUSH2 0x74C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ ISZERO PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP SWAP1 PUSH2 0x363 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP DUP1 MLOAD PUSH2 0x377 SWAP1 PUSH1 0x1 SWAP1 PUSH1 0x20 DUP5 ADD SWAP1 PUSH2 0x5A7 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH2 0x388 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x3B4 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x401 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x3D6 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x401 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x3E4 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x48A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND PUSH2 0x52D JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x26 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A206E6577206F776E657220697320746865207A65726F2061 PUSH1 0x44 DUP3 ADD MSTORE PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000 PUSH1 0x64 DUP3 ADD MSTORE PUSH1 0x84 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x2A8 DUP2 JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x5B3 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x5D5 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0x5EE JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH2 0x61B JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x61B JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x600 JUMP JUMPDEST POP PUSH2 0x627 SWAP3 SWAP2 POP PUSH2 0x62B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x627 JUMPI PUSH1 0x0 DUP2 SSTORE PUSH1 0x1 ADD PUSH2 0x62C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x652 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x676 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x68F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x6A7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x6CD JUMPI PUSH2 0x6CD PUSH2 0x878 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x713 JUMPI PUSH2 0x713 PUSH2 0x878 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x72C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x75E DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 DUP3 MLOAD DUP1 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x787 DUP2 PUSH1 0x40 DUP6 ADD PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP2 SWAP1 SWAP2 ADD PUSH1 0x40 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x7D4 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x7BC JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x7E3 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SHR SWAP1 DUP3 AND DUP1 PUSH2 0x7FD JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 EQ ISZERO PUSH2 0x837 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH2 0x873 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x12 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP MOD SWAP1 JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID PUSH10 0x6E76616C696420626C6F PUSH4 0x6B206E75 PUSH14 0x6265722C20706C65617365207761 PUSH10 0x74A26469706673582212 KECCAK256 SDIV DIV 0x5F GASPRICE RETURNDATACOPY MSTORE MULMOD 0xD1 0xD8 0x29 ADDMOD SWAP3 SSTORE 0x5E SWAP6 SLOAD SWAP7 0xEF 0xC2 CODECOPY CREATE DUP10 0xD2 0xB9 0xB8 SWAP12 LOG3 SAR 0xAB 0xA7 RETURNDATACOPY SWAP6 PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x39E CODESIZE SUB DUP1 PUSH2 0x39E DUP4 CODECOPY DUP2 ADD PUSH1 0x40 DUP2 SWAP1 MSTORE PUSH2 0x2F SWAP2 PUSH2 0x54 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x84 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x66 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH2 0x7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH2 0x30B DUP1 PUSH2 0x93 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC0129D43 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x58 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x43 PUSH2 0x53 CALLDATASIZE PUSH1 0x4 PUSH2 0x164 JUMP JUMPDEST PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0xC0129D4300000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP3 PUSH4 0xC0129D43 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xD3 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x12F SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0x233 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x149 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x15D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x176 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x18E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x1A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1B4 JUMPI PUSH2 0x1B4 PUSH2 0x2A6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x1FA JUMPI PUSH2 0x1FA PUSH2 0x2A6 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x213 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 MSTORE DUP4 MLOAD DUP1 DUP3 DUP6 ADD MSTORE PUSH1 0x0 JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x260 JUMPI DUP6 DUP2 ADD DUP4 ADD MLOAD DUP6 DUP3 ADD PUSH1 0x40 ADD MSTORE DUP3 ADD PUSH2 0x244 JUMP JUMPDEST DUP2 DUP2 GT ISZERO PUSH2 0x272 JUMPI PUSH1 0x0 PUSH1 0x40 DUP4 DUP8 ADD ADD MSTORE JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x40 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xBF 0xA7 0x2E 0xD9 0xEA 0xD JUMPI SWAP1 0x5E SWAP3 DUP2 0x1E ORIGIN DUP3 PUSH1 0x53 BASEFEE MOD 0xDB 0xDB DUP11 0xD5 DUP7 PUSH22 0x306B2582254F247564736F6C63430008070033696E76 PUSH2 0x6C69 PUSH5 0x20626C6F63 PUSH12 0x206E756D6265722C20706C65 PUSH2 0x7365 KECCAK256 PUSH24 0x616974A26469706673582212207E86E36FA543460096D0CE 0x1F 0x27 0xB7 0x23 SWAP5 PUSH9 0x336340C4A0DF5E85D3 MULMOD PUSH16 0x5C47F21E64736F6C6343000807003300 ","sourceMap":"629:588:4:-:0;;;1573:26:0;;;-1:-1:-1;;1573:26:0;1595:4;1573:26;;;629:588:4;;;;;;;;;;;;;;;;"},"deployedBytecode":{"functionDebugData":{"@IS_TEST_532":{"entryPoint":null,"id":532,"parameterSlots":0,"returnSlots":0},"@assertEq_1977":{"entryPoint":1866,"id":1977,"parameterSlots":2,"returnSlots":0},"@fail_569":{"entryPoint":null,"id":569,"parameterSlots":0,"returnSlots":0},"@failed_534":{"entryPoint":null,"id":534,"parameterSlots":0,"returnSlots":0},"@setUp_308":{"entryPoint":204,"id":308,"parameterSlots":0,"returnSlots":0},"@testNonOwnerCannotGm_206":{"entryPoint":1249,"id":206,"parameterSlots":0,"returnSlots":0},"@testOwnerCanGmOnGoodBlocks_153":{"entryPoint":735,"id":153,"parameterSlots":0,"returnSlots":0},"@testOwnerCannotGmOnBadBlocks_183":{"entryPoint":1543,"id":183,"parameterSlots":0,"returnSlots":0},"abi_decode_tuple_t_string_memory_ptr_fromMemory":{"entryPoint":2279,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_string":{"entryPoint":2461,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed":{"entryPoint":2535,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_address__to_t_address__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_rational_10_by_1__to_t_uint256__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_rational_11_by_1__to_t_uint256__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_stringliteral_58e3ca0e65e73c038df3db6a7cab1bf7de300d13038b802ce0f4435889c48e5e__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":1,"returnSlots":1},"abi_encode_tuple_t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed":{"entryPoint":2563,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed":{"entryPoint":2641,"id":null,"parameterSlots":2,"returnSlots":1},"copy_memory_to_memory":{"entryPoint":2712,"id":null,"parameterSlots":3,"returnSlots":0},"finalize_allocation":{"entryPoint":2756,"id":null,"parameterSlots":2,"returnSlots":0},"panic_error_0x41":{"entryPoint":2831,"id":null,"parameterSlots":0,"returnSlots":0},"return_data_selector":{"entryPoint":2878,"id":null,"parameterSlots":0,"returnSlots":1},"try_decode_error_message":{"entryPoint":2906,"id":null,"parameterSlots":0,"returnSlots":1}},"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:5223:7","statements":[{"nodeType":"YulBlock","src":"6:3:7","statements":[]},{"body":{"nodeType":"YulBlock","src":"105:708:7","statements":[{"body":{"nodeType":"YulBlock","src":"151:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"160:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"163:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"153:6:7"},"nodeType":"YulFunctionCall","src":"153:12:7"},"nodeType":"YulExpressionStatement","src":"153:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"126:7:7"},{"name":"headStart","nodeType":"YulIdentifier","src":"135:9:7"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"122:3:7"},"nodeType":"YulFunctionCall","src":"122:23:7"},{"kind":"number","nodeType":"YulLiteral","src":"147:2:7","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"118:3:7"},"nodeType":"YulFunctionCall","src":"118:32:7"},"nodeType":"YulIf","src":"115:52:7"},{"nodeType":"YulVariableDeclaration","src":"176:30:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"196:9:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"190:5:7"},"nodeType":"YulFunctionCall","src":"190:16:7"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"180:6:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"215:28:7","value":{"kind":"number","nodeType":"YulLiteral","src":"225:18:7","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"219:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"270:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"279:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"282:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"272:6:7"},"nodeType":"YulFunctionCall","src":"272:12:7"},"nodeType":"YulExpressionStatement","src":"272:12:7"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"258:6:7"},{"name":"_1","nodeType":"YulIdentifier","src":"266:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"255:2:7"},"nodeType":"YulFunctionCall","src":"255:14:7"},"nodeType":"YulIf","src":"252:34:7"},{"nodeType":"YulVariableDeclaration","src":"295:32:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"309:9:7"},{"name":"offset","nodeType":"YulIdentifier","src":"320:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"305:3:7"},"nodeType":"YulFunctionCall","src":"305:22:7"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"299:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"375:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"384:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"387:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"377:6:7"},"nodeType":"YulFunctionCall","src":"377:12:7"},"nodeType":"YulExpressionStatement","src":"377:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"354:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"358:4:7","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"350:3:7"},"nodeType":"YulFunctionCall","src":"350:13:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"365:7:7"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"346:3:7"},"nodeType":"YulFunctionCall","src":"346:27:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"339:6:7"},"nodeType":"YulFunctionCall","src":"339:35:7"},"nodeType":"YulIf","src":"336:55:7"},{"nodeType":"YulVariableDeclaration","src":"400:19:7","value":{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"416:2:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"410:5:7"},"nodeType":"YulFunctionCall","src":"410:9:7"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"404:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"442:22:7","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"444:16:7"},"nodeType":"YulFunctionCall","src":"444:18:7"},"nodeType":"YulExpressionStatement","src":"444:18:7"}]},"condition":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"434:2:7"},{"name":"_1","nodeType":"YulIdentifier","src":"438:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"431:2:7"},"nodeType":"YulFunctionCall","src":"431:10:7"},"nodeType":"YulIf","src":"428:36:7"},{"nodeType":"YulVariableDeclaration","src":"473:23:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"493:2:7","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"487:5:7"},"nodeType":"YulFunctionCall","src":"487:9:7"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"477:6:7","type":""}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"525:6:7"},{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"545:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"549:4:7","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"541:3:7"},"nodeType":"YulFunctionCall","src":"541:13:7"},{"kind":"number","nodeType":"YulLiteral","src":"556:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"537:3:7"},"nodeType":"YulFunctionCall","src":"537:86:7"},{"kind":"number","nodeType":"YulLiteral","src":"625:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"533:3:7"},"nodeType":"YulFunctionCall","src":"533:95:7"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"505:19:7"},"nodeType":"YulFunctionCall","src":"505:124:7"},"nodeType":"YulExpressionStatement","src":"505:124:7"},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"645:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"653:2:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"638:6:7"},"nodeType":"YulFunctionCall","src":"638:18:7"},"nodeType":"YulExpressionStatement","src":"638:18:7"},{"body":{"nodeType":"YulBlock","src":"702:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"711:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"714:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"704:6:7"},"nodeType":"YulFunctionCall","src":"704:12:7"},"nodeType":"YulExpressionStatement","src":"704:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"679:2:7"},{"name":"_3","nodeType":"YulIdentifier","src":"683:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"675:3:7"},"nodeType":"YulFunctionCall","src":"675:11:7"},{"kind":"number","nodeType":"YulLiteral","src":"688:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"671:3:7"},"nodeType":"YulFunctionCall","src":"671:20:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"693:7:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"668:2:7"},"nodeType":"YulFunctionCall","src":"668:33:7"},"nodeType":"YulIf","src":"665:53:7"},{"expression":{"arguments":[{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"753:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"757:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"749:3:7"},"nodeType":"YulFunctionCall","src":"749:11:7"},{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"766:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"774:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"762:3:7"},"nodeType":"YulFunctionCall","src":"762:15:7"},{"name":"_3","nodeType":"YulIdentifier","src":"779:2:7"}],"functionName":{"name":"copy_memory_to_memory","nodeType":"YulIdentifier","src":"727:21:7"},"nodeType":"YulFunctionCall","src":"727:55:7"},"nodeType":"YulExpressionStatement","src":"727:55:7"},{"nodeType":"YulAssignment","src":"791:16:7","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"801:6:7"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"791:6:7"}]}]},"name":"abi_decode_tuple_t_string_memory_ptr_fromMemory","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"71:9:7","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"82:7:7","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"94:6:7","type":""}],"src":"14:799:7"},{"body":{"nodeType":"YulBlock","src":"868:267:7","statements":[{"nodeType":"YulVariableDeclaration","src":"878:26:7","value":{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"898:5:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"892:5:7"},"nodeType":"YulFunctionCall","src":"892:12:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"882:6:7","type":""}]},{"expression":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"920:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"925:6:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"913:6:7"},"nodeType":"YulFunctionCall","src":"913:19:7"},"nodeType":"YulExpressionStatement","src":"913:19:7"},{"expression":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"967:5:7"},{"kind":"number","nodeType":"YulLiteral","src":"974:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"963:3:7"},"nodeType":"YulFunctionCall","src":"963:16:7"},{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"985:3:7"},{"kind":"number","nodeType":"YulLiteral","src":"990:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"981:3:7"},"nodeType":"YulFunctionCall","src":"981:14:7"},{"name":"length","nodeType":"YulIdentifier","src":"997:6:7"}],"functionName":{"name":"copy_memory_to_memory","nodeType":"YulIdentifier","src":"941:21:7"},"nodeType":"YulFunctionCall","src":"941:63:7"},"nodeType":"YulExpressionStatement","src":"941:63:7"},{"nodeType":"YulAssignment","src":"1013:116:7","value":{"arguments":[{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"1028:3:7"},{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1041:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1049:2:7","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1037:3:7"},"nodeType":"YulFunctionCall","src":"1037:15:7"},{"kind":"number","nodeType":"YulLiteral","src":"1054:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"1033:3:7"},"nodeType":"YulFunctionCall","src":"1033:88:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1024:3:7"},"nodeType":"YulFunctionCall","src":"1024:98:7"},{"kind":"number","nodeType":"YulLiteral","src":"1124:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1020:3:7"},"nodeType":"YulFunctionCall","src":"1020:109:7"},"variableNames":[{"name":"end","nodeType":"YulIdentifier","src":"1013:3:7"}]}]},"name":"abi_encode_string","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"845:5:7","type":""},{"name":"pos","nodeType":"YulTypedName","src":"852:3:7","type":""}],"returnVariables":[{"name":"end","nodeType":"YulTypedName","src":"860:3:7","type":""}],"src":"818:317:7"},{"body":{"nodeType":"YulBlock","src":"1279:137:7","statements":[{"nodeType":"YulVariableDeclaration","src":"1289:27:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1309:6:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1303:5:7"},"nodeType":"YulFunctionCall","src":"1303:13:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"1293:6:7","type":""}]},{"expression":{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1351:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1359:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1347:3:7"},"nodeType":"YulFunctionCall","src":"1347:17:7"},{"name":"pos","nodeType":"YulIdentifier","src":"1366:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"1371:6:7"}],"functionName":{"name":"copy_memory_to_memory","nodeType":"YulIdentifier","src":"1325:21:7"},"nodeType":"YulFunctionCall","src":"1325:53:7"},"nodeType":"YulExpressionStatement","src":"1325:53:7"},{"nodeType":"YulAssignment","src":"1387:23:7","value":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"1398:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"1403:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1394:3:7"},"nodeType":"YulFunctionCall","src":"1394:16:7"},"variableNames":[{"name":"end","nodeType":"YulIdentifier","src":"1387:3:7"}]}]},"name":"abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"pos","nodeType":"YulTypedName","src":"1255:3:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1260:6:7","type":""}],"returnVariables":[{"name":"end","nodeType":"YulTypedName","src":"1271:3:7","type":""}],"src":"1140:276:7"},{"body":{"nodeType":"YulBlock","src":"1522:125:7","statements":[{"nodeType":"YulAssignment","src":"1532:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1544:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"1555:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1540:3:7"},"nodeType":"YulFunctionCall","src":"1540:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1532:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1574:9:7"},{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1589:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1597:42:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffff"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"1585:3:7"},"nodeType":"YulFunctionCall","src":"1585:55:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1567:6:7"},"nodeType":"YulFunctionCall","src":"1567:74:7"},"nodeType":"YulExpressionStatement","src":"1567:74:7"}]},"name":"abi_encode_tuple_t_address__to_t_address__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1491:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1502:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1513:4:7","type":""}],"src":"1421:226:7"},{"body":{"nodeType":"YulBlock","src":"1747:92:7","statements":[{"nodeType":"YulAssignment","src":"1757:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1769:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"1780:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1765:3:7"},"nodeType":"YulFunctionCall","src":"1765:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1757:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1799:9:7"},{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1824:6:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"1817:6:7"},"nodeType":"YulFunctionCall","src":"1817:14:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"1810:6:7"},"nodeType":"YulFunctionCall","src":"1810:22:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1792:6:7"},"nodeType":"YulFunctionCall","src":"1792:41:7"},"nodeType":"YulExpressionStatement","src":"1792:41:7"}]},"name":"abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1716:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1727:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1738:4:7","type":""}],"src":"1652:187:7"},{"body":{"nodeType":"YulBlock","src":"1954:76:7","statements":[{"nodeType":"YulAssignment","src":"1964:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1976:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"1987:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1972:3:7"},"nodeType":"YulFunctionCall","src":"1972:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1964:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2006:9:7"},{"name":"value0","nodeType":"YulIdentifier","src":"2017:6:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1999:6:7"},"nodeType":"YulFunctionCall","src":"1999:25:7"},"nodeType":"YulExpressionStatement","src":"1999:25:7"}]},"name":"abi_encode_tuple_t_rational_10_by_1__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1923:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1934:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1945:4:7","type":""}],"src":"1844:186:7"},{"body":{"nodeType":"YulBlock","src":"2145:76:7","statements":[{"nodeType":"YulAssignment","src":"2155:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2167:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2178:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2163:3:7"},"nodeType":"YulFunctionCall","src":"2163:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"2155:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2197:9:7"},{"name":"value0","nodeType":"YulIdentifier","src":"2208:6:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2190:6:7"},"nodeType":"YulFunctionCall","src":"2190:25:7"},"nodeType":"YulExpressionStatement","src":"2190:25:7"}]},"name":"abi_encode_tuple_t_rational_11_by_1__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2114:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"2125:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2136:4:7","type":""}],"src":"2035:186:7"},{"body":{"nodeType":"YulBlock","src":"2400:226:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2417:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2428:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2410:6:7"},"nodeType":"YulFunctionCall","src":"2410:21:7"},"nodeType":"YulExpressionStatement","src":"2410:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2451:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2462:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2447:3:7"},"nodeType":"YulFunctionCall","src":"2447:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"2467:2:7","type":"","value":"36"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2440:6:7"},"nodeType":"YulFunctionCall","src":"2440:30:7"},"nodeType":"YulExpressionStatement","src":"2440:30:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2490:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2501:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2486:3:7"},"nodeType":"YulFunctionCall","src":"2486:18:7"},{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b737472","kind":"string","nodeType":"YulLiteral","src":"2506:34:7","type":"","value":"Error: a == b not satisfied [str"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2479:6:7"},"nodeType":"YulFunctionCall","src":"2479:62:7"},"nodeType":"YulExpressionStatement","src":"2479:62:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2561:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2572:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2557:3:7"},"nodeType":"YulFunctionCall","src":"2557:18:7"},{"hexValue":"696e675d","kind":"string","nodeType":"YulLiteral","src":"2577:6:7","type":"","value":"ing]"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2550:6:7"},"nodeType":"YulFunctionCall","src":"2550:34:7"},"nodeType":"YulExpressionStatement","src":"2550:34:7"},{"nodeType":"YulAssignment","src":"2593:27:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2605:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2616:3:7","type":"","value":"128"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2601:3:7"},"nodeType":"YulFunctionCall","src":"2601:19:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"2593:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_58e3ca0e65e73c038df3db6a7cab1bf7de300d13038b802ce0f4435889c48e5e__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2377:9:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2391:4:7","type":""}],"src":"2226:400:7"},{"body":{"nodeType":"YulBlock","src":"2853:228:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2870:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2881:2:7","type":"","value":"64"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2863:6:7"},"nodeType":"YulFunctionCall","src":"2863:21:7"},"nodeType":"YulExpressionStatement","src":"2863:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2904:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2915:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2900:3:7"},"nodeType":"YulFunctionCall","src":"2900:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"2920:1:7","type":"","value":"9"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2893:6:7"},"nodeType":"YulFunctionCall","src":"2893:29:7"},"nodeType":"YulExpressionStatement","src":"2893:29:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2942:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2953:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2938:3:7"},"nodeType":"YulFunctionCall","src":"2938:18:7"},{"hexValue":"202056616c75652061","kind":"string","nodeType":"YulLiteral","src":"2958:11:7","type":"","value":" Value a"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2931:6:7"},"nodeType":"YulFunctionCall","src":"2931:39:7"},"nodeType":"YulExpressionStatement","src":"2931:39:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2990:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3001:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2986:3:7"},"nodeType":"YulFunctionCall","src":"2986:20:7"},{"kind":"number","nodeType":"YulLiteral","src":"3008:3:7","type":"","value":"128"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2979:6:7"},"nodeType":"YulFunctionCall","src":"2979:33:7"},"nodeType":"YulExpressionStatement","src":"2979:33:7"},{"nodeType":"YulAssignment","src":"3021:54:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"3047:6:7"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3059:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3070:3:7","type":"","value":"128"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3055:3:7"},"nodeType":"YulFunctionCall","src":"3055:19:7"}],"functionName":{"name":"abi_encode_string","nodeType":"YulIdentifier","src":"3029:17:7"},"nodeType":"YulFunctionCall","src":"3029:46:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3021:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2822:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"2833:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2844:4:7","type":""}],"src":"2631:450:7"},{"body":{"nodeType":"YulBlock","src":"3308:228:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3325:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3336:2:7","type":"","value":"64"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3318:6:7"},"nodeType":"YulFunctionCall","src":"3318:21:7"},"nodeType":"YulExpressionStatement","src":"3318:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3359:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3370:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3355:3:7"},"nodeType":"YulFunctionCall","src":"3355:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"3375:1:7","type":"","value":"9"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3348:6:7"},"nodeType":"YulFunctionCall","src":"3348:29:7"},"nodeType":"YulExpressionStatement","src":"3348:29:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3397:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3408:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3393:3:7"},"nodeType":"YulFunctionCall","src":"3393:18:7"},{"hexValue":"202056616c75652062","kind":"string","nodeType":"YulLiteral","src":"3413:11:7","type":"","value":" Value b"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3386:6:7"},"nodeType":"YulFunctionCall","src":"3386:39:7"},"nodeType":"YulExpressionStatement","src":"3386:39:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3445:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3456:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3441:3:7"},"nodeType":"YulFunctionCall","src":"3441:20:7"},{"kind":"number","nodeType":"YulLiteral","src":"3463:3:7","type":"","value":"128"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3434:6:7"},"nodeType":"YulFunctionCall","src":"3434:33:7"},"nodeType":"YulExpressionStatement","src":"3434:33:7"},{"nodeType":"YulAssignment","src":"3476:54:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"3502:6:7"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3514:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3525:3:7","type":"","value":"128"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3510:3:7"},"nodeType":"YulFunctionCall","src":"3510:19:7"}],"functionName":{"name":"abi_encode_string","nodeType":"YulIdentifier","src":"3484:17:7"},"nodeType":"YulFunctionCall","src":"3484:46:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3476:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3277:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"3288:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"3299:4:7","type":""}],"src":"3086:450:7"},{"body":{"nodeType":"YulBlock","src":"3594:205:7","statements":[{"nodeType":"YulVariableDeclaration","src":"3604:10:7","value":{"kind":"number","nodeType":"YulLiteral","src":"3613:1:7","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"3608:1:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"3673:63:7","statements":[{"expression":{"arguments":[{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"3698:3:7"},{"name":"i","nodeType":"YulIdentifier","src":"3703:1:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3694:3:7"},"nodeType":"YulFunctionCall","src":"3694:11:7"},{"arguments":[{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"3717:3:7"},{"name":"i","nodeType":"YulIdentifier","src":"3722:1:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3713:3:7"},"nodeType":"YulFunctionCall","src":"3713:11:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"3707:5:7"},"nodeType":"YulFunctionCall","src":"3707:18:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3687:6:7"},"nodeType":"YulFunctionCall","src":"3687:39:7"},"nodeType":"YulExpressionStatement","src":"3687:39:7"}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"3634:1:7"},{"name":"length","nodeType":"YulIdentifier","src":"3637:6:7"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"3631:2:7"},"nodeType":"YulFunctionCall","src":"3631:13:7"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"3645:19:7","statements":[{"nodeType":"YulAssignment","src":"3647:15:7","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"3656:1:7"},{"kind":"number","nodeType":"YulLiteral","src":"3659:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3652:3:7"},"nodeType":"YulFunctionCall","src":"3652:10:7"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"3647:1:7"}]}]},"pre":{"nodeType":"YulBlock","src":"3627:3:7","statements":[]},"src":"3623:113:7"},{"body":{"nodeType":"YulBlock","src":"3762:31:7","statements":[{"expression":{"arguments":[{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"3775:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"3780:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3771:3:7"},"nodeType":"YulFunctionCall","src":"3771:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"3789:1:7","type":"","value":"0"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3764:6:7"},"nodeType":"YulFunctionCall","src":"3764:27:7"},"nodeType":"YulExpressionStatement","src":"3764:27:7"}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"3751:1:7"},{"name":"length","nodeType":"YulIdentifier","src":"3754:6:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"3748:2:7"},"nodeType":"YulFunctionCall","src":"3748:13:7"},"nodeType":"YulIf","src":"3745:48:7"}]},"name":"copy_memory_to_memory","nodeType":"YulFunctionDefinition","parameters":[{"name":"src","nodeType":"YulTypedName","src":"3572:3:7","type":""},{"name":"dst","nodeType":"YulTypedName","src":"3577:3:7","type":""},{"name":"length","nodeType":"YulTypedName","src":"3582:6:7","type":""}],"src":"3541:258:7"},{"body":{"nodeType":"YulBlock","src":"3851:261:7","statements":[{"nodeType":"YulVariableDeclaration","src":"3861:117:7","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"3883:6:7"},{"arguments":[{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"3899:4:7"},{"kind":"number","nodeType":"YulLiteral","src":"3905:2:7","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3895:3:7"},"nodeType":"YulFunctionCall","src":"3895:13:7"},{"kind":"number","nodeType":"YulLiteral","src":"3910:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"3891:3:7"},"nodeType":"YulFunctionCall","src":"3891:86:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3879:3:7"},"nodeType":"YulFunctionCall","src":"3879:99:7"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"3865:10:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"4053:22:7","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"4055:16:7"},"nodeType":"YulFunctionCall","src":"4055:18:7"},"nodeType":"YulExpressionStatement","src":"4055:18:7"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"3996:10:7"},{"kind":"number","nodeType":"YulLiteral","src":"4008:18:7","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"3993:2:7"},"nodeType":"YulFunctionCall","src":"3993:34:7"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"4032:10:7"},{"name":"memPtr","nodeType":"YulIdentifier","src":"4044:6:7"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"4029:2:7"},"nodeType":"YulFunctionCall","src":"4029:22:7"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"3990:2:7"},"nodeType":"YulFunctionCall","src":"3990:62:7"},"nodeType":"YulIf","src":"3987:88:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4091:2:7","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"4095:10:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4084:6:7"},"nodeType":"YulFunctionCall","src":"4084:22:7"},"nodeType":"YulExpressionStatement","src":"4084:22:7"}]},"name":"finalize_allocation","nodeType":"YulFunctionDefinition","parameters":[{"name":"memPtr","nodeType":"YulTypedName","src":"3833:6:7","type":""},{"name":"size","nodeType":"YulTypedName","src":"3841:4:7","type":""}],"src":"3804:308:7"},{"body":{"nodeType":"YulBlock","src":"4149:152:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4166:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"4169:77:7","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4159:6:7"},"nodeType":"YulFunctionCall","src":"4159:88:7"},"nodeType":"YulExpressionStatement","src":"4159:88:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4263:1:7","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"4266:4:7","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4256:6:7"},"nodeType":"YulFunctionCall","src":"4256:15:7"},"nodeType":"YulExpressionStatement","src":"4256:15:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4287:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"4290:4:7","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"4280:6:7"},"nodeType":"YulFunctionCall","src":"4280:15:7"},"nodeType":"YulExpressionStatement","src":"4280:15:7"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"4117:184:7"},{"body":{"nodeType":"YulBlock","src":"4349:136:7","statements":[{"body":{"nodeType":"YulBlock","src":"4394:85:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4423:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"4426:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"4429:1:7","type":"","value":"4"}],"functionName":{"name":"returndatacopy","nodeType":"YulIdentifier","src":"4408:14:7"},"nodeType":"YulFunctionCall","src":"4408:23:7"},"nodeType":"YulExpressionStatement","src":"4408:23:7"},{"nodeType":"YulAssignment","src":"4444:25:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4455:3:7","type":"","value":"224"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4466:1:7","type":"","value":"0"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"4460:5:7"},"nodeType":"YulFunctionCall","src":"4460:8:7"}],"functionName":{"name":"shr","nodeType":"YulIdentifier","src":"4451:3:7"},"nodeType":"YulFunctionCall","src":"4451:18:7"},"variableNames":[{"name":"sig","nodeType":"YulIdentifier","src":"4444:3:7"}]}]},"condition":{"arguments":[{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"4365:14:7"},"nodeType":"YulFunctionCall","src":"4365:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"4383:1:7","type":"","value":"3"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"4362:2:7"},"nodeType":"YulFunctionCall","src":"4362:23:7"},"nodeType":"YulIf","src":"4359:120:7"}]},"name":"return_data_selector","nodeType":"YulFunctionDefinition","returnVariables":[{"name":"sig","nodeType":"YulTypedName","src":"4341:3:7","type":""}],"src":"4306:179:7"},{"body":{"nodeType":"YulBlock","src":"4537:684:7","statements":[{"body":{"nodeType":"YulBlock","src":"4577:9:7","statements":[{"nodeType":"YulLeave","src":"4579:5:7"}]},"condition":{"arguments":[{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"4553:14:7"},"nodeType":"YulFunctionCall","src":"4553:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"4571:4:7","type":"","value":"0x44"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"4550:2:7"},"nodeType":"YulFunctionCall","src":"4550:26:7"},"nodeType":"YulIf","src":"4547:39:7"},{"nodeType":"YulVariableDeclaration","src":"4595:21:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"4613:2:7","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"4607:5:7"},"nodeType":"YulFunctionCall","src":"4607:9:7"},"variables":[{"name":"data","nodeType":"YulTypedName","src":"4599:4:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"4625:76:7","value":{"kind":"number","nodeType":"YulLiteral","src":"4635:66:7","type":"","value":"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"4629:2:7","type":""}]},{"expression":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"4725:4:7"},{"kind":"number","nodeType":"YulLiteral","src":"4731:1:7","type":"","value":"4"},{"arguments":[{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"4738:14:7"},"nodeType":"YulFunctionCall","src":"4738:16:7"},{"name":"_1","nodeType":"YulIdentifier","src":"4756:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4734:3:7"},"nodeType":"YulFunctionCall","src":"4734:25:7"}],"functionName":{"name":"returndatacopy","nodeType":"YulIdentifier","src":"4710:14:7"},"nodeType":"YulFunctionCall","src":"4710:50:7"},"nodeType":"YulExpressionStatement","src":"4710:50:7"},{"nodeType":"YulVariableDeclaration","src":"4769:25:7","value":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"4789:4:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"4783:5:7"},"nodeType":"YulFunctionCall","src":"4783:11:7"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"4773:6:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"4803:26:7","value":{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"4813:14:7"},"nodeType":"YulFunctionCall","src":"4813:16:7"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"4807:2:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"4838:28:7","value":{"kind":"number","nodeType":"YulLiteral","src":"4848:18:7","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"4842:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"4924:9:7","statements":[{"nodeType":"YulLeave","src":"4926:5:7"}]},"condition":{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"4884:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"4892:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"4881:2:7"},"nodeType":"YulFunctionCall","src":"4881:14:7"},{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"4904:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"4912:4:7","type":"","value":"0x24"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4900:3:7"},"nodeType":"YulFunctionCall","src":"4900:17:7"},{"name":"_2","nodeType":"YulIdentifier","src":"4919:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"4897:2:7"},"nodeType":"YulFunctionCall","src":"4897:25:7"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"4878:2:7"},"nodeType":"YulFunctionCall","src":"4878:45:7"},"nodeType":"YulIf","src":"4875:58:7"},{"nodeType":"YulVariableDeclaration","src":"4942:28:7","value":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"4957:4:7"},{"name":"offset","nodeType":"YulIdentifier","src":"4963:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4953:3:7"},"nodeType":"YulFunctionCall","src":"4953:17:7"},"variables":[{"name":"msg","nodeType":"YulTypedName","src":"4946:3:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"4979:24:7","value":{"arguments":[{"name":"msg","nodeType":"YulIdentifier","src":"4999:3:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"4993:5:7"},"nodeType":"YulFunctionCall","src":"4993:10:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"4983:6:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"5030:9:7","statements":[{"nodeType":"YulLeave","src":"5032:5:7"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"5018:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"5026:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"5015:2:7"},"nodeType":"YulFunctionCall","src":"5015:14:7"},"nodeType":"YulIf","src":"5012:27:7"},{"body":{"nodeType":"YulBlock","src":"5121:9:7","statements":[{"nodeType":"YulLeave","src":"5123:5:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"msg","nodeType":"YulIdentifier","src":"5062:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"5067:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5058:3:7"},"nodeType":"YulFunctionCall","src":"5058:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"5076:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5054:3:7"},"nodeType":"YulFunctionCall","src":"5054:27:7"},{"arguments":[{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"5091:4:7"},{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"5097:14:7"},"nodeType":"YulFunctionCall","src":"5097:16:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5087:3:7"},"nodeType":"YulFunctionCall","src":"5087:27:7"},{"name":"_1","nodeType":"YulIdentifier","src":"5116:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5083:3:7"},"nodeType":"YulFunctionCall","src":"5083:36:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"5051:2:7"},"nodeType":"YulFunctionCall","src":"5051:69:7"},"nodeType":"YulIf","src":"5048:82:7"},{"expression":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"5159:4:7"},{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"5173:6:7"},{"name":"length","nodeType":"YulIdentifier","src":"5181:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5169:3:7"},"nodeType":"YulFunctionCall","src":"5169:19:7"},{"kind":"number","nodeType":"YulLiteral","src":"5190:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5165:3:7"},"nodeType":"YulFunctionCall","src":"5165:30:7"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"5139:19:7"},"nodeType":"YulFunctionCall","src":"5139:57:7"},"nodeType":"YulExpressionStatement","src":"5139:57:7"},{"nodeType":"YulAssignment","src":"5205:10:7","value":{"name":"msg","nodeType":"YulIdentifier","src":"5212:3:7"},"variableNames":[{"name":"ret","nodeType":"YulIdentifier","src":"5205:3:7"}]}]},"name":"try_decode_error_message","nodeType":"YulFunctionDefinition","returnVariables":[{"name":"ret","nodeType":"YulTypedName","src":"4529:3:7","type":""}],"src":"4490:731:7"}]},"contents":"{\n { }\n function abi_decode_tuple_t_string_memory_ptr_fromMemory(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n let offset := mload(headStart)\n let _1 := 0xffffffffffffffff\n if gt(offset, _1) { revert(0, 0) }\n let _2 := add(headStart, offset)\n if iszero(slt(add(_2, 0x1f), dataEnd)) { revert(0, 0) }\n let _3 := mload(_2)\n if gt(_3, _1) { panic_error_0x41() }\n let memPtr := mload(64)\n finalize_allocation(memPtr, add(and(add(_3, 0x1f), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0), 32))\n mstore(memPtr, _3)\n if gt(add(add(_2, _3), 32), dataEnd) { revert(0, 0) }\n copy_memory_to_memory(add(_2, 32), add(memPtr, 32), _3)\n value0 := memPtr\n }\n function abi_encode_string(value, pos) -> end\n {\n let length := mload(value)\n mstore(pos, length)\n copy_memory_to_memory(add(value, 0x20), add(pos, 0x20), length)\n end := add(add(pos, and(add(length, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)), 0x20)\n }\n function abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed(pos, value0) -> end\n {\n let length := mload(value0)\n copy_memory_to_memory(add(value0, 0x20), pos, length)\n end := add(pos, length)\n }\n function abi_encode_tuple_t_address__to_t_address__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, and(value0, 0xffffffffffffffffffffffffffffffffffffffff))\n }\n function abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, iszero(iszero(value0)))\n }\n function abi_encode_tuple_t_rational_10_by_1__to_t_uint256__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, value0)\n }\n function abi_encode_tuple_t_rational_11_by_1__to_t_uint256__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, value0)\n }\n function abi_encode_tuple_t_stringliteral_58e3ca0e65e73c038df3db6a7cab1bf7de300d13038b802ce0f4435889c48e5e__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 36)\n mstore(add(headStart, 64), \"Error: a == b not satisfied [str\")\n mstore(add(headStart, 96), \"ing]\")\n tail := add(headStart, 128)\n }\n function abi_encode_tuple_t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed(headStart, value0) -> tail\n {\n mstore(headStart, 64)\n mstore(add(headStart, 64), 9)\n mstore(add(headStart, 96), \" Value a\")\n mstore(add(headStart, 0x20), 128)\n tail := abi_encode_string(value0, add(headStart, 128))\n }\n function abi_encode_tuple_t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed(headStart, value0) -> tail\n {\n mstore(headStart, 64)\n mstore(add(headStart, 64), 9)\n mstore(add(headStart, 96), \" Value b\")\n mstore(add(headStart, 0x20), 128)\n tail := abi_encode_string(value0, add(headStart, 128))\n }\n function copy_memory_to_memory(src, dst, length)\n {\n let i := 0\n for { } lt(i, length) { i := add(i, 32) }\n {\n mstore(add(dst, i), mload(add(src, i)))\n }\n if gt(i, length) { mstore(add(dst, length), 0) }\n }\n function finalize_allocation(memPtr, size)\n {\n let newFreePtr := add(memPtr, and(add(size, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0))\n if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }\n mstore(64, newFreePtr)\n }\n function panic_error_0x41()\n {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x41)\n revert(0, 0x24)\n }\n function return_data_selector() -> sig\n {\n if gt(returndatasize(), 3)\n {\n returndatacopy(0, 0, 4)\n sig := shr(224, mload(0))\n }\n }\n function try_decode_error_message() -> ret\n {\n if lt(returndatasize(), 0x44) { leave }\n let data := mload(64)\n let _1 := 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc\n returndatacopy(data, 4, add(returndatasize(), _1))\n let offset := mload(data)\n let _2 := returndatasize()\n let _3 := 0xffffffffffffffff\n if or(gt(offset, _3), gt(add(offset, 0x24), _2)) { leave }\n let msg := add(data, offset)\n let length := mload(msg)\n if gt(length, _3) { leave }\n if gt(add(add(msg, length), 0x20), add(add(data, returndatasize()), _1)) { leave }\n finalize_allocation(data, add(add(offset, length), 0x20))\n ret := msg\n }\n}","id":7,"language":"Yul","name":"#utility.yul"}],"immutableReferences":{},"linkReferences":{},"object":"608060405234801561001057600080fd5b50600436106100725760003560e01c8063a474cdb011610050578063a474cdb014610091578063ba414fa614610099578063fa7626d4146100bf57600080fd5b80630a9254e4146100775780632a11c35d146100815780638dc5d38014610089575b600080fd5b61007f6100cc565b005b61007f6102df565b61007f6104e1565b61007f610607565b6000546100ab90610100900460ff1681565b604051901515815260200160405180910390f35b6000546100ab9060ff1681565b6040516100d8906108cd565b604051809103906000f0801580156100f4573d6000803e3d6000fd5b50600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff93841681029190911791829055604051910490911690610153906108da565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f08015801561018c573d6000803e3d6000fd5b50600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92831617905560005460405162010000909104909116906101e8906108da565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f080158015610221573d6000803e3d6000fd5b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283161790556000546001546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081529083166004820152620100009091049091169063f2fde38b90602401600060405180830381600087803b1580156102c557600080fd5b505af11580156102d9573d6000803e3d6000fd5b50505050565b6040517f1f7b4f30000000000000000000000000000000000000000000000000000000008152600a6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90631f7b4f3090602401600060405180830381600087803b15801561034557600080fd5b505af1158015610359573d6000803e3d6000fd5b50505050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c0129d436040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103c757600080fd5b505af11580156103db573d6000803e3d6000fd5b505050506104df600060029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ef690cc06040518163ffffffff1660e01b815260040160006040518083038186803b15801561044a57600080fd5b505afa15801561045e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104a491908101906108e7565b6040518060400160405280600281526020017f676d00000000000000000000000000000000000000000000000000000000000081525061074a565b565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c0129d436040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561054b57600080fd5b505af192505050801561055c575060015b6105d657610568610b3e565b806308c379a014156105ca575061057d610b5a565b8061058857506105cc565b6105c7816040518060400160405280602081526020017f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525061074a565b50565b505b3d6000803e3d6000fd5b6104df600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b6040517f1f7b4f30000000000000000000000000000000000000000000000000000000008152600b6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90631f7b4f3090602401600060405180830381600087803b15801561066d57600080fd5b505af1158015610681573d6000803e3d6000fd5b50505050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c0129d436040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156106ef57600080fd5b505af1925050508015610700575060015b6105d65761070c610b3e565b806308c379a014156105ca5750610721610b5a565b8061072c57506105cc565b6105c78160405180606001604052806021815260200161191d602191395b8060405160200161075b91906109e7565b604051602081830303815290604052805190602001208260405160200161078291906109e7565b60405160208183030381529060405280519060200120146108c9577f41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f506040516108229060208082526024908201527f4572726f723a2061203d3d2062206e6f7420736174697366696564205b73747260408201527f696e675d00000000000000000000000000000000000000000000000000000000606082015260800190565b60405180910390a17f280f4446b28a1372417dda658d30b95b2992b12ac9c7f378535f29a97acf3583826040516108599190610a03565b60405180910390a17f280f4446b28a1372417dda658d30b95b2992b12ac9c7f378535f29a97acf3583816040516108909190610a51565b60405180910390a16108c9600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b5050565b61097c80610c0383390190565b61039e8061157f83390190565b6000602082840312156108f957600080fd5b815167ffffffffffffffff8082111561091157600080fd5b818401915084601f83011261092557600080fd5b81518181111561093757610937610b0f565b604051915061096e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160183610ac4565b80825285602082850101111561098357600080fd5b610994816020840160208601610a98565b50949350505050565b600081518084526109b5816020860160208601610a98565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082516109f9818460208701610a98565b9190910192915050565b60408152600960408201527f202056616c7565206100000000000000000000000000000000000000000000006060820152608060208201526000610a4a608083018461099d565b9392505050565b60408152600960408201527f202056616c7565206200000000000000000000000000000000000000000000006060820152608060208201526000610a4a608083018461099d565b60005b83811015610ab3578181015183820152602001610a9b565b838111156102d95750506000910152565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715610b0857610b08610b0f565b6040525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d1115610b575760046000803e5060005160e01c5b90565b600060443d1015610b685790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610bb657505050505090565b8285019150815181811115610bce5750505050505090565b843d8701016020828501011115610be85750505050505090565b610bf760208286010187610ac4565b50909594505050505056fe608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6108fe8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ead710c411610050578063ead710c4146100b6578063ef690cc0146100c9578063f2fde38b146100de57600080fd5b8063715018a6146100775780638da5cb5b14610081578063c0129d43146100ae575b600080fd5b61007f6100f1565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007f610183565b61007f6100c436600461067d565b6102ab565b6100d161037b565b6040516100a59190610768565b61007f6100ec366004610640565b610409565b60005473ffffffffffffffffffffffffffffffffffffffff163314610177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6101816000610532565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b61020f600a4361083d565b6000146040518060600160405280602181526020016108a86021913990610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b506040805180820190915260028082527f676d00000000000000000000000000000000000000000000000000000000000060209092019182526102a8916001916105a7565b50565b7f71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270816040516020016102dd919061074c565b6040516020818303038152906040528051906020012014156040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d00000000000000000000000081525090610363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b5080516103779060019060208401906105a7565b5050565b60018054610388906107e9565b80601f01602080910402602001604051908101604052809291908181526020018280546103b4906107e9565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff16331461048a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b73ffffffffffffffffffffffffffffffffffffffff811661052d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161016e565b6102a8815b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546105b3906107e9565b90600052602060002090601f0160209004810192826105d5576000855561061b565b82601f106105ee57805160ff191683800117855561061b565b8280016001018555821561061b579182015b8281111561061b578251825591602001919060010190610600565b5061062792915061062b565b5090565b5b80821115610627576000815560010161062c565b60006020828403121561065257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461067657600080fd5b9392505050565b60006020828403121561068f57600080fd5b813567ffffffffffffffff808211156106a757600080fd5b818401915084601f8301126106bb57600080fd5b8135818111156106cd576106cd610878565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071357610713610878565b8160405282815287602084870101111561072c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825161075e8184602087016107b9565b9190910192915050565b60208152600082518060208401526107878160408501602087016107b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b838110156107d45781810151838201526020016107bc565b838111156107e3576000848401525b50505050565b600181811c908216806107fd57607f821691505b60208210811415610837577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082610873577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a264697066735822122005045f3a3e5209d1d8290892555e955496efc239f089d2b9b89ba31daba73e9564736f6c63430008070033608060405234801561001057600080fd5b5060405161039e38038061039e83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61030b806100936000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c0129d431461003b578063ead710c414610045575b600080fd5b610043610058565b005b610043610053366004610164565b6100d9565b60008054604080517fc0129d43000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169263c0129d439260048084019382900301818387803b1580156100bf57600080fd5b505af11580156100d3573d6000803e3d6000fd5b50505050565b6000546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c49061012f908490600401610233565b600060405180830381600087803b15801561014957600080fd5b505af115801561015d573d6000803e3d6000fd5b5050505050565b60006020828403121561017657600080fd5b813567ffffffffffffffff8082111561018e57600080fd5b818401915084601f8301126101a257600080fd5b8135818111156101b4576101b46102a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101fa576101fa6102a6565b8160405282815287602084870101111561021357600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561026057858101830151858201604001528201610244565b81811115610272576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220bfa72ed9ea0d57905e92811e328260534806dbdb8ad58675306b2582254f247564736f6c63430008070033696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a26469706673582212207e86e36fa543460096d0ce1f27b7239468336340c4a0df5e85d3096f5c47f21e64736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xA474CDB0 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xA474CDB0 EQ PUSH2 0x91 JUMPI DUP1 PUSH4 0xBA414FA6 EQ PUSH2 0x99 JUMPI DUP1 PUSH4 0xFA7626D4 EQ PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0xA9254E4 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x2A11C35D EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0x8DC5D380 EQ PUSH2 0x89 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xCC JUMP JUMPDEST STOP JUMPDEST PUSH2 0x7F PUSH2 0x2DF JUMP JUMPDEST PUSH2 0x7F PUSH2 0x4E1 JUMP JUMPDEST PUSH2 0x7F PUSH2 0x607 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0xAB SWAP1 PUSH2 0x100 SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 SLOAD PUSH2 0xAB SWAP1 PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xD8 SWAP1 PUSH2 0x8CD JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0xF4 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000FFFF AND PUSH3 0x10000 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP4 DUP5 AND DUP2 MUL SWAP2 SWAP1 SWAP2 OR SWAP2 DUP3 SWAP1 SSTORE PUSH1 0x40 MLOAD SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x153 SWAP1 PUSH2 0x8DA JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x18C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x1 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x1E8 SWAP1 PUSH2 0x8DA JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x221 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x2 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xF2FDE38B00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 DUP4 AND PUSH1 0x4 DUP3 ADD MSTORE PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH4 0xF2FDE38B SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2C5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x2D9 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1F7B4F3000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0xA PUSH1 0x4 DUP3 ADD MSTORE PUSH20 0x7109709ECFA91A80626FF3989D68F67F5B1DD12D SWAP1 PUSH4 0x1F7B4F30 SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x345 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x359 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x1 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xC0129D43 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3C7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x3DB JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH2 0x4DF PUSH1 0x0 PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xEF690CC0 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x44A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x45E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x0 DUP3 RETURNDATACOPY PUSH1 0x1F RETURNDATASIZE SWAP1 DUP2 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND DUP3 ADD PUSH1 0x40 MSTORE PUSH2 0x4A4 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x8E7 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x2 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP PUSH2 0x74A JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x2 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xC0129D43 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x54B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL SWAP3 POP POP POP DUP1 ISZERO PUSH2 0x55C JUMPI POP PUSH1 0x1 JUMPDEST PUSH2 0x5D6 JUMPI PUSH2 0x568 PUSH2 0xB3E JUMP JUMPDEST DUP1 PUSH4 0x8C379A0 EQ ISZERO PUSH2 0x5CA JUMPI POP PUSH2 0x57D PUSH2 0xB5A JUMP JUMPDEST DUP1 PUSH2 0x588 JUMPI POP PUSH2 0x5CC JUMP JUMPDEST PUSH2 0x5C7 DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x20 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 DUP2 MSTORE POP PUSH2 0x74A JUMP JUMPDEST POP JUMP JUMPDEST POP JUMPDEST RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST PUSH2 0x4DF PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF AND PUSH2 0x100 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1F7B4F3000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0xB PUSH1 0x4 DUP3 ADD MSTORE PUSH20 0x7109709ECFA91A80626FF3989D68F67F5B1DD12D SWAP1 PUSH4 0x1F7B4F30 SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x66D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x681 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x1 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xC0129D43 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x6EF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL SWAP3 POP POP POP DUP1 ISZERO PUSH2 0x700 JUMPI POP PUSH1 0x1 JUMPDEST PUSH2 0x5D6 JUMPI PUSH2 0x70C PUSH2 0xB3E JUMP JUMPDEST DUP1 PUSH4 0x8C379A0 EQ ISZERO PUSH2 0x5CA JUMPI POP PUSH2 0x721 PUSH2 0xB5A JUMP JUMPDEST DUP1 PUSH2 0x72C JUMPI POP PUSH2 0x5CC JUMP JUMPDEST PUSH2 0x5C7 DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x191D PUSH1 0x21 SWAP2 CODECOPY JUMPDEST DUP1 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x75B SWAP2 SWAP1 PUSH2 0x9E7 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP3 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x782 SWAP2 SWAP1 PUSH2 0x9E7 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ PUSH2 0x8C9 JUMPI PUSH32 0x41304FACD9323D75B11BCDD609CB38EFFFFDB05710F7CAF0E9B16C6D9D709F50 PUSH1 0x40 MLOAD PUSH2 0x822 SWAP1 PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x24 SWAP1 DUP3 ADD MSTORE PUSH32 0x4572726F723A2061203D3D2062206E6F7420736174697366696564205B737472 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x696E675D00000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH32 0x280F4446B28A1372417DDA658D30B95B2992B12AC9C7F378535F29A97ACF3583 DUP3 PUSH1 0x40 MLOAD PUSH2 0x859 SWAP2 SWAP1 PUSH2 0xA03 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH32 0x280F4446B28A1372417DDA658D30B95B2992B12AC9C7F378535F29A97ACF3583 DUP2 PUSH1 0x40 MLOAD PUSH2 0x890 SWAP2 SWAP1 PUSH2 0xA51 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH2 0x8C9 PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF AND PUSH2 0x100 OR SWAP1 SSTORE JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH2 0x97C DUP1 PUSH2 0xC03 DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH2 0x39E DUP1 PUSH2 0x157F DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x8F9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x911 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x925 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD DUP2 DUP2 GT ISZERO PUSH2 0x937 JUMPI PUSH2 0x937 PUSH2 0xB0F JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP2 POP PUSH2 0x96E PUSH1 0x20 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP5 ADD AND ADD DUP4 PUSH2 0xAC4 JUMP JUMPDEST DUP1 DUP3 MSTORE DUP6 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x983 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x994 DUP2 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP7 ADD PUSH2 0xA98 JUMP JUMPDEST POP SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x9B5 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0xA98 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x9F9 DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0xA98 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x40 DUP2 MSTORE PUSH1 0x9 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x202056616C756520610000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x0 PUSH2 0xA4A PUSH1 0x80 DUP4 ADD DUP5 PUSH2 0x99D JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP2 MSTORE PUSH1 0x9 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x202056616C756520620000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x0 PUSH2 0xA4A PUSH1 0x80 DUP4 ADD DUP5 PUSH2 0x99D JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xAB3 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xA9B JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x2D9 JUMPI POP POP PUSH1 0x0 SWAP2 ADD MSTORE JUMP JUMPDEST PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP4 ADD AND DUP2 ADD DUP2 DUP2 LT PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT OR ISZERO PUSH2 0xB08 JUMPI PUSH2 0xB08 PUSH2 0xB0F JUMP JUMPDEST PUSH1 0x40 MSTORE POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST PUSH1 0x0 PUSH1 0x3 RETURNDATASIZE GT ISZERO PUSH2 0xB57 JUMPI PUSH1 0x4 PUSH1 0x0 DUP1 RETURNDATACOPY POP PUSH1 0x0 MLOAD PUSH1 0xE0 SHR JUMPDEST SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x44 RETURNDATASIZE LT ISZERO PUSH2 0xB68 JUMPI SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC DUP1 RETURNDATASIZE ADD PUSH1 0x4 DUP4 RETURNDATACOPY DUP2 MLOAD RETURNDATASIZE PUSH8 0xFFFFFFFFFFFFFFFF DUP2 PUSH1 0x24 DUP5 ADD GT DUP2 DUP5 GT OR ISZERO PUSH2 0xBB6 JUMPI POP POP POP POP POP SWAP1 JUMP JUMPDEST DUP3 DUP6 ADD SWAP2 POP DUP2 MLOAD DUP2 DUP2 GT ISZERO PUSH2 0xBCE JUMPI POP POP POP POP POP POP SWAP1 JUMP JUMPDEST DUP5 RETURNDATASIZE DUP8 ADD ADD PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0xBE8 JUMPI POP POP POP POP POP POP SWAP1 JUMP JUMPDEST PUSH2 0xBF7 PUSH1 0x20 DUP3 DUP7 ADD ADD DUP8 PUSH2 0xAC4 JUMP JUMPDEST POP SWAP1 SWAP6 SWAP5 POP POP POP POP POP JUMP INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1A CALLER PUSH2 0x1F JUMP JUMPDEST PUSH2 0x6F JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 DUP2 AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH2 0x8FE DUP1 PUSH2 0x7E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xEAD710C4 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0xEF690CC0 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0xDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0x715018A6 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0xC0129D43 EQ PUSH2 0xAE JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xF1 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x183 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x67D JUMP JUMPDEST PUSH2 0x2AB JUMP JUMPDEST PUSH2 0xD1 PUSH2 0x37B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xA5 SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xEC CALLDATASIZE PUSH1 0x4 PUSH2 0x640 JUMP JUMPDEST PUSH2 0x409 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x177 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x181 PUSH1 0x0 PUSH2 0x532 JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x204 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x20F PUSH1 0xA NUMBER PUSH2 0x83D JUMP JUMPDEST PUSH1 0x0 EQ PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x8A8 PUSH1 0x21 SWAP2 CODECOPY SWAP1 PUSH2 0x263 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x2 DUP1 DUP3 MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 SWAP1 SWAP3 ADD SWAP2 DUP3 MSTORE PUSH2 0x2A8 SWAP2 PUSH1 0x1 SWAP2 PUSH2 0x5A7 JUMP JUMPDEST POP JUMP JUMPDEST PUSH32 0x71B78290913AF2ADDD8FCBE5766DE306AF2C8AFBC466CA891E207F73638C7270 DUP2 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2DD SWAP2 SWAP1 PUSH2 0x74C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ ISZERO PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP SWAP1 PUSH2 0x363 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP DUP1 MLOAD PUSH2 0x377 SWAP1 PUSH1 0x1 SWAP1 PUSH1 0x20 DUP5 ADD SWAP1 PUSH2 0x5A7 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH2 0x388 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x3B4 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x401 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x3D6 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x401 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x3E4 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x48A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND PUSH2 0x52D JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x26 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A206E6577206F776E657220697320746865207A65726F2061 PUSH1 0x44 DUP3 ADD MSTORE PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000 PUSH1 0x64 DUP3 ADD MSTORE PUSH1 0x84 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x2A8 DUP2 JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x5B3 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x5D5 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0x5EE JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH2 0x61B JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x61B JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x600 JUMP JUMPDEST POP PUSH2 0x627 SWAP3 SWAP2 POP PUSH2 0x62B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x627 JUMPI PUSH1 0x0 DUP2 SSTORE PUSH1 0x1 ADD PUSH2 0x62C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x652 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x676 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x68F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x6A7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x6CD JUMPI PUSH2 0x6CD PUSH2 0x878 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x713 JUMPI PUSH2 0x713 PUSH2 0x878 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x72C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x75E DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 DUP3 MLOAD DUP1 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x787 DUP2 PUSH1 0x40 DUP6 ADD PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP2 SWAP1 SWAP2 ADD PUSH1 0x40 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x7D4 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x7BC JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x7E3 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SHR SWAP1 DUP3 AND DUP1 PUSH2 0x7FD JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 EQ ISZERO PUSH2 0x837 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH2 0x873 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x12 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP MOD SWAP1 JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID PUSH10 0x6E76616C696420626C6F PUSH4 0x6B206E75 PUSH14 0x6265722C20706C65617365207761 PUSH10 0x74A26469706673582212 KECCAK256 SDIV DIV 0x5F GASPRICE RETURNDATACOPY MSTORE MULMOD 0xD1 0xD8 0x29 ADDMOD SWAP3 SSTORE 0x5E SWAP6 SLOAD SWAP7 0xEF 0xC2 CODECOPY CREATE DUP10 0xD2 0xB9 0xB8 SWAP12 LOG3 SAR 0xAB 0xA7 RETURNDATACOPY SWAP6 PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x39E CODESIZE SUB DUP1 PUSH2 0x39E DUP4 CODECOPY DUP2 ADD PUSH1 0x40 DUP2 SWAP1 MSTORE PUSH2 0x2F SWAP2 PUSH2 0x54 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x84 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x66 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH2 0x7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH2 0x30B DUP1 PUSH2 0x93 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC0129D43 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x58 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x43 PUSH2 0x53 CALLDATASIZE PUSH1 0x4 PUSH2 0x164 JUMP JUMPDEST PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0xC0129D4300000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP3 PUSH4 0xC0129D43 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xD3 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x12F SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0x233 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x149 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x15D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x176 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x18E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x1A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1B4 JUMPI PUSH2 0x1B4 PUSH2 0x2A6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x1FA JUMPI PUSH2 0x1FA PUSH2 0x2A6 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x213 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 MSTORE DUP4 MLOAD DUP1 DUP3 DUP6 ADD MSTORE PUSH1 0x0 JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x260 JUMPI DUP6 DUP2 ADD DUP4 ADD MLOAD DUP6 DUP3 ADD PUSH1 0x40 ADD MSTORE DUP3 ADD PUSH2 0x244 JUMP JUMPDEST DUP2 DUP2 GT ISZERO PUSH2 0x272 JUMPI PUSH1 0x0 PUSH1 0x40 DUP4 DUP8 ADD ADD MSTORE JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x40 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xBF 0xA7 0x2E 0xD9 0xEA 0xD JUMPI SWAP1 0x5E SWAP3 DUP2 0x1E ORIGIN DUP3 PUSH1 0x53 BASEFEE MOD 0xDB 0xDB DUP11 0xD5 DUP7 PUSH22 0x306B2582254F247564736F6C63430008070033696E76 PUSH2 0x6C69 PUSH5 0x20626C6F63 PUSH12 0x206E756D6265722C20706C65 PUSH2 0x7365 KECCAK256 PUSH24 0x616974A26469706673582212207E86E36FA543460096D0CE 0x1F 0x27 0xB7 0x23 SWAP5 PUSH9 0x336340C4A0DF5E85D3 MULMOD PUSH16 0x5C47F21E64736F6C6343000807003300 ","sourceMap":"629:588:4:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;619:209:5;;;:::i;:::-;;662:139:4;;;:::i;1026:189::-;;;:::i;807:213::-;;;:::i;1605:18:0:-;;;;;;;;;;;;;;;1817:14:7;;1810:22;1792:41;;1780:2;1765:18;1605::0;;;;;;;1573:26;;;;;;;;;619:209:5;671:13;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;661:7:5;:23;;;;;;;;;;;;;;;;;;;702:26;;719:7;;;;;;702:26;;;:::i;:::-;1597:42:7;1585:55;;;1567:74;;1555:2;1540:18;702:26:5;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;694:5:5;:34;;;;;;;;;;;-1:-1:-1;761:7:5;744:26;;761:7;;;;;;;;744:26;;;:::i;:::-;1597:42:7;1585:55;;;1567:74;;1555:2;1540:18;744:26:5;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;738:3:5;:32;;;;;;;;;;;-1:-1:-1;780:7:5;-1:-1:-1;814:5:5;780:41;;;;;814:5;;;780:41;;;1567:74:7;780:7:5;;;;;;;;:25;;1540:18:7;;780:41:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;619:209::o;662:139:4:-;717:13;;;;;727:2;717:13;;;1999:25:7;1670:64:0;;717:9:4;;1972:18:7;;717:13:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;740:5;;;;;;;;;;;:8;;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;760:34;769:7;;;;;;;;;;;:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;760:34;;;;;;;;;;;;;;;;;:8;:34::i;:::-;662:139::o;1026:189::-;1079:3;;;;;;;;;;;:6;;;:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1075:134;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;1147:51;1156:5;1147:51;;;;;;;;;;;;;;;;;:8;:51::i;:::-;1100:109;662:139::o;1075:134::-;;;;;;;;;;;1090:6;1853::0;:13;;;;;;;;1818:55;807:213:4;864:13;;;;;874:2;864:13;;;1999:25:7;1670:64:0;;864:9:4;;1972:18:7;;864:13:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;891:5;;;;;;;;;;;:8;;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;887:127;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;961:42;970:5;977:25;;;;;;;;;;;;;;;;;13479:342:0;13615:1;13598:19;;;;;;;;:::i;:::-;;;;;;;;;;;;;13588:30;;;;;;13581:1;13564:19;;;;;;;;:::i;:::-;;;;;;;;;;;;;13554:30;;;;;;:64;13550:265;;13639:43;;;;;2428:2:7;2410:21;;;2467:2;2447:18;;;2440:30;2506:34;2501:2;2486:18;;2479:62;2577:6;2572:2;2557:18;;2550:34;2616:3;2601:19;;2226:400;13639:43:0;;;;;;;;13701:32;13731:1;13701:32;;;;;;:::i;:::-;;;;;;;;13752;13782:1;13752:32;;;;;;:::i;:::-;;;;;;;;13798:6;1853;:13;;;;;;;;1818:55;13798:6;13479:342;;:::o;-1:-1:-1:-;;;;;;;;:::o;:::-;;;;;;;;:::o;14:799:7:-;94:6;147:2;135:9;126:7;122:23;118:32;115:52;;;163:1;160;153:12;115:52;196:9;190:16;225:18;266:2;258:6;255:14;252:34;;;282:1;279;272:12;252:34;320:6;309:9;305:22;295:32;;365:7;358:4;354:2;350:13;346:27;336:55;;387:1;384;377:12;336:55;416:2;410:9;438:2;434;431:10;428:36;;;444:18;;:::i;:::-;493:2;487:9;473:23;;505:124;625:2;556:66;549:4;545:2;541:13;537:86;533:95;525:6;505:124;:::i;:::-;653:2;645:6;638:18;693:7;688:2;683;679;675:11;671:20;668:33;665:53;;;714:1;711;704:12;665:53;727:55;779:2;774;766:6;762:15;757:2;753;749:11;727:55;:::i;:::-;-1:-1:-1;801:6:7;14:799;-1:-1:-1;;;;14:799:7:o;818:317::-;860:3;898:5;892:12;925:6;920:3;913:19;941:63;997:6;990:4;985:3;981:14;974:4;967:5;963:16;941:63;:::i;:::-;1049:2;1037:15;1054:66;1033:88;1024:98;;;;1124:4;1020:109;;818:317;-1:-1:-1;;818:317:7:o;1140:276::-;1271:3;1309:6;1303:13;1325:53;1371:6;1366:3;1359:4;1351:6;1347:17;1325:53;:::i;:::-;1394:16;;;;;1140:276;-1:-1:-1;;1140:276:7:o;2631:450::-;2881:2;2870:9;2863:21;2920:1;2915:2;2904:9;2900:18;2893:29;2958:11;2953:2;2942:9;2938:18;2931:39;3008:3;3001:4;2990:9;2986:20;2979:33;2844:4;3029:46;3070:3;3059:9;3055:19;3047:6;3029:46;:::i;:::-;3021:54;2631:450;-1:-1:-1;;;2631:450:7:o;3086:::-;3336:2;3325:9;3318:21;3375:1;3370:2;3359:9;3355:18;3348:29;3413:11;3408:2;3397:9;3393:18;3386:39;3463:3;3456:4;3445:9;3441:20;3434:33;3299:4;3484:46;3525:3;3514:9;3510:19;3502:6;3484:46;:::i;3541:258::-;3613:1;3623:113;3637:6;3634:1;3631:13;3623:113;;;3713:11;;;3707:18;3694:11;;;3687:39;3659:2;3652:10;3623:113;;;3754:6;3751:1;3748:13;3745:48;;;-1:-1:-1;;3789:1:7;3771:16;;3764:27;3541:258::o;3804:308::-;3910:66;3905:2;3899:4;3895:13;3891:86;3883:6;3879:99;4044:6;4032:10;4029:22;4008:18;3996:10;3993:34;3990:62;3987:88;;;4055:18;;:::i;:::-;4091:2;4084:22;-1:-1:-1;;3804:308:7:o;4117:184::-;4169:77;4166:1;4159:88;4266:4;4263:1;4256:15;4290:4;4287:1;4280:15;4306:179;4341:3;4383:1;4365:16;4362:23;4359:120;;;4429:1;4426;4423;4408:23;-1:-1:-1;4466:1:7;4460:8;4455:3;4451:18;4359:120;4306:179;:::o;4490:731::-;4529:3;4571:4;4553:16;4550:26;4547:39;;;4490:731;:::o;4547:39::-;4613:2;4607:9;4635:66;4756:2;4738:16;4734:25;4731:1;4725:4;4710:50;4789:4;4783:11;4813:16;4848:18;4919:2;4912:4;4904:6;4900:17;4897:25;4892:2;4884:6;4881:14;4878:45;4875:58;;;4926:5;;;;;4490:731;:::o;4875:58::-;4963:6;4957:4;4953:17;4942:28;;4999:3;4993:10;5026:2;5018:6;5015:14;5012:27;;;5032:5;;;;;;4490:731;:::o;5012:27::-;5116:2;5097:16;5091:4;5087:27;5083:36;5076:4;5067:6;5062:3;5058:16;5054:27;5051:69;5048:82;;;5123:5;;;;;;4490:731;:::o;5048:82::-;5139:57;5190:4;5181:6;5173;5169:19;5165:30;5159:4;5139:57;:::i;:::-;-1:-1:-1;5212:3:7;;4490:731;-1:-1:-1;;;;;4490:731:7:o"}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log_address\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"log_bytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"log_bytes32\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"name\":\"log_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"val\",\"type\":\"address\"}],\"name\":\"log_named_address\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"val\",\"type\":\"bytes\"}],\"name\":\"log_named_bytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"val\",\"type\":\"bytes32\"}],\"name\":\"log_named_bytes32\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"}],\"name\":\"log_named_decimal_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"}],\"name\":\"log_named_decimal_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"}],\"name\":\"log_named_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"val\",\"type\":\"string\"}],\"name\":\"log_named_string\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"log_named_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log_string\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"logs\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"IS_TEST\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"failed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"setUp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testNonOwnerCannotGm\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testOwnerCanGmOnGoodBlocks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testOwnerCannotGmOnBadBlocks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/test/Greeter.t.sol\":\"Gm\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/ds-test/src/test.sol\":{\"keccak256\":\"0x529f30c5939d75689f6a982f7f96b8898bed30bd90ec5b385b57cab681e12b00\",\"license\":\"GPL-3.0-or-later\",\"urls\":[\"bzz-raw://89075d5a96e87acef1d00cf556b409d1836728ec2e92f5629ceb5cae3d1e4354\",\"dweb:/ipfs/QmPAViJrxffEDns9GEMVSAzmr3soAzfrEg1CVuovwmNfnt\"]},\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x6bb804a310218875e89d12c053e94a13a4607cdf7cc2052f3e52bd32a0dc50a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2ebbbe6d0011175bd9e7268b83de3f9c2f9d8d4cbfbaef12aff977d7d727163\",\"dweb:/ipfs/Qmd5c7Vxtis9wzkDNhxwc6A2QT5H9xn9kfjhx7qx44vpro\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x90565a39ae45c80f0468dc96c7b20d0afc3055f344c8203a0c9258239f350b9f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e8b38a7ac8e7b4463af00cf7fff1bf48ae9875765bf4f7751e100124d0bc8c\",\"dweb:/ipfs/QmWcsmkVr24xmmjfnBQZoemFniXjj3vwT78Cz6uqZW1Hux\"]},\"src/Greeter.sol\":{\"keccak256\":\"0xc34bd8409a4fa4a474f29c6cb7d076cf9379c9c79e257c5cda7e5d114023f0f6\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://9db4f0c61754c54fd3b3ae58dfaf72865f8134e96959f7fc295b1a8e3b7511d7\",\"dweb:/ipfs/QmPuGbtNJ9rRaC7kFWqy76A9sfcGGcYAps6yPRrW28v4xd\"]},\"src/test/Greeter.t.sol\":{\"keccak256\":\"0xf7fe97110b31611de26973a826978b120cf08bb9263444bf52ea639f3f568c16\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://139a8edf691557963f5e6d3925f0f3fdf14c211974bbc399b81c5326f6c9f5ec\",\"dweb:/ipfs/QmVBNcpL91o99MkuDS9Qu5kHe68NPLyphtf3yJTYfCn1oC\"]},\"src/test/utils/GreeterTest.sol\":{\"keccak256\":\"0xc49253ed5e0fc9185d066993945370493f2bb08f00a997680b112fe6f9b5d455\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://d5ff89c2bb371b6ddfb66b905b3c3597aa080e1ca5c1c1303e529f2c8fc98a67\",\"dweb:/ipfs/Qmc28bfatf99DDv6P8dpdo5Zsw7QdSoC1N4FV1TJGZF5Vx\"]},\"src/test/utils/Hevm.sol\":{\"keccak256\":\"0xd477fc888e2bdbaf45c8babf175c93127478ae74543556ffebb9877a8dd823a9\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://7fb2a52878484cea3793a92ae34b3a9f3e77f976eda7c7f91e2edb5b9ba38be3\",\"dweb:/ipfs/Qmf7JsG4uMjd7WX1h8rBPcpXv1m4mF3sdrr6VYzKj1SXUX\"]}},\"version\":1}","storageLayout":{"storage":[{"astId":532,"contract":"src/test/Greeter.t.sol:Gm","label":"IS_TEST","offset":0,"slot":"0","type":"t_bool"},{"astId":534,"contract":"src/test/Greeter.t.sol:Gm","label":"failed","offset":1,"slot":"0","type":"t_bool"},{"astId":260,"contract":"src/test/Greeter.t.sol:Gm","label":"greeter","offset":2,"slot":"0","type":"t_contract(Greeter)60"},{"astId":263,"contract":"src/test/Greeter.t.sol:Gm","label":"alice","offset":0,"slot":"1","type":"t_contract(User)249"},{"astId":266,"contract":"src/test/Greeter.t.sol:Gm","label":"bob","offset":0,"slot":"2","type":"t_contract(User)249"}],"types":{"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_contract(Greeter)60":{"encoding":"inplace","label":"contract Greeter","numberOfBytes":"20"},"t_contract(User)249":{"encoding":"inplace","label":"contract User","numberOfBytes":"20"}}}},"Greet":{"abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"}],"name":"log","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"log_address","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"}],"name":"log_bytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"","type":"bytes32"}],"name":"log_bytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"","type":"int256"}],"name":"log_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"address","name":"val","type":"address"}],"name":"log_named_address","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"bytes","name":"val","type":"bytes"}],"name":"log_named_bytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"bytes32","name":"val","type":"bytes32"}],"name":"log_named_bytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"int256","name":"val","type":"int256"},{"indexed":false,"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"log_named_decimal_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"uint256","name":"val","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"log_named_decimal_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"int256","name":"val","type":"int256"}],"name":"log_named_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"val","type":"string"}],"name":"log_named_string","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"uint256","name":"val","type":"uint256"}],"name":"log_named_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"}],"name":"log_string","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"log_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"}],"name":"logs","type":"event"},{"inputs":[],"name":"IS_TEST","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"failed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"setUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testCanSetGreeting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testCannotGm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"greeting","type":"string"}],"name":"testWorksForAllGreetings","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"60806040526000805460ff1916600117905534801561001d57600080fd5b506119f48061002d6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ba414fa611610050578063ba414fa61461009c578063e0747015146100c2578063fa7626d4146100ca57600080fd5b80630a9254e4146100775780635306d34d146100815780636721f71814610089575b600080fd5b61007f6100d7565b005b61007f6102ea565b61007f6100973660046108de565b610441565b6000546100ae90610100900460ff1681565b604051901515815260200160405180910390f35b61007f610594565b6000546100ae9060ff1681565b6040516100e3906108c4565b604051809103906000f0801580156100ff573d6000803e3d6000fd5b50600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff9384168102919091179182905560405191049091169061015e906108d1565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f080158015610197573d6000803e3d6000fd5b50600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92831617905560005460405162010000909104909116906101f3906108d1565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f08015801561022c573d6000803e3d6000fd5b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283161790556000546001546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081529083166004820152620100009091049091169063f2fde38b90602401600060405180830381600087803b1580156102d057600080fd5b505af11580156102e4573d6000803e3d6000fd5b50505050565b6001546040517fead710c400000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f676d000000000000000000000000000000000000000000000000000000000000604482015273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c490606401600060405180830381600087803b15801561038357600080fd5b505af1925050508015610394575060015b61040e576103a0610be0565b806308c379a0141561040257506103b5610bfc565b806103c05750610404565b6103ff816040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d000000000000000000000000815250610741565b50565b505b3d6000803e3d6000fd5b61043f600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b565b6001546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c490610497908490600401610a4c565b600060405180830381600087803b1580156104b157600080fd5b505af11580156104c5573d6000803e3d6000fd5b505050506103ff600060029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ef690cc06040518163ffffffff1660e01b815260040160006040518083038186803b15801561053457600080fd5b505afa158015610548573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261058e9190810190610964565b82610741565b6001546040517fead710c400000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f6869000000000000000000000000000000000000000000000000000000000000604482015273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c490606401600060405180830381600087803b15801561062d57600080fd5b505af1158015610641573d6000803e3d6000fd5b5050505061043f600060029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ef690cc06040518163ffffffff1660e01b815260040160006040518083038186803b1580156106b057600080fd5b505afa1580156106c4573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261070a9190810190610964565b6040518060400160405280600281526020017f68690000000000000000000000000000000000000000000000000000000000008152505b806040516020016107529190610a30565b60405160208183030381529060405280519060200120826040516020016107799190610a30565b60405160208183030381529060405280519060200120146108c0577f41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f506040516108199060208082526024908201527f4572726f723a2061203d3d2062206e6f7420736174697366696564205b73747260408201527f696e675d00000000000000000000000000000000000000000000000000000000606082015260800190565b60405180910390a17f280f4446b28a1372417dda658d30b95b2992b12ac9c7f378535f29a97acf3583826040516108509190610a66565b60405180910390a17f280f4446b28a1372417dda658d30b95b2992b12ac9c7f378535f29a97acf3583816040516108879190610aad565b60405180910390a16108c0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b5050565b61097c80610ca583390190565b61039e8061162183390190565b6000602082840312156108f057600080fd5b813567ffffffffffffffff81111561090757600080fd5b8201601f8101841361091857600080fd5b803561092381610af4565b6040516109308282610b66565b82815286602084860101111561094557600080fd5b8260208501602083013760009281016020019290925250949350505050565b60006020828403121561097657600080fd5b815167ffffffffffffffff81111561098d57600080fd5b8201601f8101841361099e57600080fd5b80516109a981610af4565b6040516109b68282610b66565b8281528660208486010111156109cb57600080fd5b6109dc836020830160208701610b3a565b9695505050505050565b600081518084526109fe816020860160208601610b3a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008251610a42818460208701610b3a565b9190910192915050565b602081526000610a5f60208301846109e6565b9392505050565b60408152600960408201527f202056616c7565206100000000000000000000000000000000000000000000006060820152608060208201526000610a5f60808301846109e6565b60408152600960408201527f202056616c7565206200000000000000000000000000000000000000000000006060820152608060208201526000610a5f60808301846109e6565b600067ffffffffffffffff821115610b0e57610b0e610bb1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015610b55578181015183820152602001610b3d565b838111156102e45750506000910152565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715610baa57610baa610bb1565b6040525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d1115610bf95760046000803e5060005160e01c5b90565b600060443d1015610c0a5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610c5857505050505090565b8285019150815181811115610c705750505050505090565b843d8701016020828501011115610c8a5750505050505090565b610c9960208286010187610b66565b50909594505050505056fe608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6108fe8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ead710c411610050578063ead710c4146100b6578063ef690cc0146100c9578063f2fde38b146100de57600080fd5b8063715018a6146100775780638da5cb5b14610081578063c0129d43146100ae575b600080fd5b61007f6100f1565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007f610183565b61007f6100c436600461067d565b6102ab565b6100d161037b565b6040516100a59190610768565b61007f6100ec366004610640565b610409565b60005473ffffffffffffffffffffffffffffffffffffffff163314610177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6101816000610532565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b61020f600a4361083d565b6000146040518060600160405280602181526020016108a86021913990610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b506040805180820190915260028082527f676d00000000000000000000000000000000000000000000000000000000000060209092019182526102a8916001916105a7565b50565b7f71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270816040516020016102dd919061074c565b6040516020818303038152906040528051906020012014156040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d00000000000000000000000081525090610363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b5080516103779060019060208401906105a7565b5050565b60018054610388906107e9565b80601f01602080910402602001604051908101604052809291908181526020018280546103b4906107e9565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff16331461048a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b73ffffffffffffffffffffffffffffffffffffffff811661052d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161016e565b6102a8815b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546105b3906107e9565b90600052602060002090601f0160209004810192826105d5576000855561061b565b82601f106105ee57805160ff191683800117855561061b565b8280016001018555821561061b579182015b8281111561061b578251825591602001919060010190610600565b5061062792915061062b565b5090565b5b80821115610627576000815560010161062c565b60006020828403121561065257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461067657600080fd5b9392505050565b60006020828403121561068f57600080fd5b813567ffffffffffffffff808211156106a757600080fd5b818401915084601f8301126106bb57600080fd5b8135818111156106cd576106cd610878565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071357610713610878565b8160405282815287602084870101111561072c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825161075e8184602087016107b9565b9190910192915050565b60208152600082518060208401526107878160408501602087016107b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b838110156107d45781810151838201526020016107bc565b838111156107e3576000848401525b50505050565b600181811c908216806107fd57607f821691505b60208210811415610837577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082610873577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a264697066735822122005045f3a3e5209d1d8290892555e955496efc239f089d2b9b89ba31daba73e9564736f6c63430008070033608060405234801561001057600080fd5b5060405161039e38038061039e83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61030b806100936000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c0129d431461003b578063ead710c414610045575b600080fd5b610043610058565b005b610043610053366004610164565b6100d9565b60008054604080517fc0129d43000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169263c0129d439260048084019382900301818387803b1580156100bf57600080fd5b505af11580156100d3573d6000803e3d6000fd5b50505050565b6000546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c49061012f908490600401610233565b600060405180830381600087803b15801561014957600080fd5b505af115801561015d573d6000803e3d6000fd5b5050505050565b60006020828403121561017657600080fd5b813567ffffffffffffffff8082111561018e57600080fd5b818401915084601f8301126101a257600080fd5b8135818111156101b4576101b46102a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101fa576101fa6102a6565b8160405282815287602084870101111561021357600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561026057858101830151858201604001528201610244565b81811115610272576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220bfa72ed9ea0d57905e92811e328260534806dbdb8ad58675306b2582254f247564736f6c63430008070033a2646970667358221220ad80bd62f261460562ca174ee1c98c204fef7777d1d6f8bacae87697631df73c64736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 SLOAD PUSH1 0xFF NOT AND PUSH1 0x1 OR SWAP1 SSTORE CALLVALUE DUP1 ISZERO PUSH2 0x1D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x19F4 DUP1 PUSH2 0x2D PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xBA414FA6 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xBA414FA6 EQ PUSH2 0x9C JUMPI DUP1 PUSH4 0xE0747015 EQ PUSH2 0xC2 JUMPI DUP1 PUSH4 0xFA7626D4 EQ PUSH2 0xCA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0xA9254E4 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x5306D34D EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0x6721F718 EQ PUSH2 0x89 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xD7 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x7F PUSH2 0x2EA JUMP JUMPDEST PUSH2 0x7F PUSH2 0x97 CALLDATASIZE PUSH1 0x4 PUSH2 0x8DE JUMP JUMPDEST PUSH2 0x441 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0xAE SWAP1 PUSH2 0x100 SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x594 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0xAE SWAP1 PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xE3 SWAP1 PUSH2 0x8C4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0xFF JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000FFFF AND PUSH3 0x10000 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP4 DUP5 AND DUP2 MUL SWAP2 SWAP1 SWAP2 OR SWAP2 DUP3 SWAP1 SSTORE PUSH1 0x40 MLOAD SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x15E SWAP1 PUSH2 0x8D1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x197 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x1 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x1F3 SWAP1 PUSH2 0x8D1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x22C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x2 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xF2FDE38B00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 DUP4 AND PUSH1 0x4 DUP3 ADD MSTORE PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH4 0xF2FDE38B SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2D0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x2E4 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x2 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH1 0x64 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x383 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL SWAP3 POP POP POP DUP1 ISZERO PUSH2 0x394 JUMPI POP PUSH1 0x1 JUMPDEST PUSH2 0x40E JUMPI PUSH2 0x3A0 PUSH2 0xBE0 JUMP JUMPDEST DUP1 PUSH4 0x8C379A0 EQ ISZERO PUSH2 0x402 JUMPI POP PUSH2 0x3B5 PUSH2 0xBFC JUMP JUMPDEST DUP1 PUSH2 0x3C0 JUMPI POP PUSH2 0x404 JUMP JUMPDEST PUSH2 0x3FF DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP PUSH2 0x741 JUMP JUMPDEST POP JUMP JUMPDEST POP JUMPDEST RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST PUSH2 0x43F PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF AND PUSH2 0x100 OR SWAP1 SSTORE JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x497 SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0xA4C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x4B1 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x4C5 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH2 0x3FF PUSH1 0x0 PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xEF690CC0 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x534 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x548 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x0 DUP3 RETURNDATACOPY PUSH1 0x1F RETURNDATASIZE SWAP1 DUP2 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND DUP3 ADD PUSH1 0x40 MSTORE PUSH2 0x58E SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x964 JUMP JUMPDEST DUP3 PUSH2 0x741 JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x2 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x6869000000000000000000000000000000000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH1 0x64 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x62D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x641 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH2 0x43F PUSH1 0x0 PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xEF690CC0 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x6B0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x6C4 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x0 DUP3 RETURNDATACOPY PUSH1 0x1F RETURNDATASIZE SWAP1 DUP2 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND DUP3 ADD PUSH1 0x40 MSTORE PUSH2 0x70A SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x964 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x2 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x6869000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP JUMPDEST DUP1 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x752 SWAP2 SWAP1 PUSH2 0xA30 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP3 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x779 SWAP2 SWAP1 PUSH2 0xA30 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ PUSH2 0x8C0 JUMPI PUSH32 0x41304FACD9323D75B11BCDD609CB38EFFFFDB05710F7CAF0E9B16C6D9D709F50 PUSH1 0x40 MLOAD PUSH2 0x819 SWAP1 PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x24 SWAP1 DUP3 ADD MSTORE PUSH32 0x4572726F723A2061203D3D2062206E6F7420736174697366696564205B737472 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x696E675D00000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH32 0x280F4446B28A1372417DDA658D30B95B2992B12AC9C7F378535F29A97ACF3583 DUP3 PUSH1 0x40 MLOAD PUSH2 0x850 SWAP2 SWAP1 PUSH2 0xA66 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH32 0x280F4446B28A1372417DDA658D30B95B2992B12AC9C7F378535F29A97ACF3583 DUP2 PUSH1 0x40 MLOAD PUSH2 0x887 SWAP2 SWAP1 PUSH2 0xAAD JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH2 0x8C0 PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF AND PUSH2 0x100 OR SWAP1 SSTORE JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH2 0x97C DUP1 PUSH2 0xCA5 DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH2 0x39E DUP1 PUSH2 0x1621 DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x8F0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x907 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 ADD PUSH1 0x1F DUP2 ADD DUP5 SGT PUSH2 0x918 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 CALLDATALOAD PUSH2 0x923 DUP2 PUSH2 0xAF4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x930 DUP3 DUP3 PUSH2 0xB66 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP7 PUSH1 0x20 DUP5 DUP7 ADD ADD GT ISZERO PUSH2 0x945 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP6 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x976 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x98D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 ADD PUSH1 0x1F DUP2 ADD DUP5 SGT PUSH2 0x99E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 MLOAD PUSH2 0x9A9 DUP2 PUSH2 0xAF4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x9B6 DUP3 DUP3 PUSH2 0xB66 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP7 PUSH1 0x20 DUP5 DUP7 ADD ADD GT ISZERO PUSH2 0x9CB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x9DC DUP4 PUSH1 0x20 DUP4 ADD PUSH1 0x20 DUP8 ADD PUSH2 0xB3A JUMP JUMPDEST SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x9FE DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0xB3A JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0xA42 DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0xB3A JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 PUSH2 0xA5F PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0x9E6 JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP2 MSTORE PUSH1 0x9 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x202056616C756520610000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x0 PUSH2 0xA5F PUSH1 0x80 DUP4 ADD DUP5 PUSH2 0x9E6 JUMP JUMPDEST PUSH1 0x40 DUP2 MSTORE PUSH1 0x9 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x202056616C756520620000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x0 PUSH2 0xA5F PUSH1 0x80 DUP4 ADD DUP5 PUSH2 0x9E6 JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0xB0E JUMPI PUSH2 0xB0E PUSH2 0xBB1 JUMP JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xB55 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xB3D JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x2E4 JUMPI POP POP PUSH1 0x0 SWAP2 ADD MSTORE JUMP JUMPDEST PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP4 ADD AND DUP2 ADD DUP2 DUP2 LT PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT OR ISZERO PUSH2 0xBAA JUMPI PUSH2 0xBAA PUSH2 0xBB1 JUMP JUMPDEST PUSH1 0x40 MSTORE POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST PUSH1 0x0 PUSH1 0x3 RETURNDATASIZE GT ISZERO PUSH2 0xBF9 JUMPI PUSH1 0x4 PUSH1 0x0 DUP1 RETURNDATACOPY POP PUSH1 0x0 MLOAD PUSH1 0xE0 SHR JUMPDEST SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x44 RETURNDATASIZE LT ISZERO PUSH2 0xC0A JUMPI SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC DUP1 RETURNDATASIZE ADD PUSH1 0x4 DUP4 RETURNDATACOPY DUP2 MLOAD RETURNDATASIZE PUSH8 0xFFFFFFFFFFFFFFFF DUP2 PUSH1 0x24 DUP5 ADD GT DUP2 DUP5 GT OR ISZERO PUSH2 0xC58 JUMPI POP POP POP POP POP SWAP1 JUMP JUMPDEST DUP3 DUP6 ADD SWAP2 POP DUP2 MLOAD DUP2 DUP2 GT ISZERO PUSH2 0xC70 JUMPI POP POP POP POP POP POP SWAP1 JUMP JUMPDEST DUP5 RETURNDATASIZE DUP8 ADD ADD PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0xC8A JUMPI POP POP POP POP POP POP SWAP1 JUMP JUMPDEST PUSH2 0xC99 PUSH1 0x20 DUP3 DUP7 ADD ADD DUP8 PUSH2 0xB66 JUMP JUMPDEST POP SWAP1 SWAP6 SWAP5 POP POP POP POP POP JUMP INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1A CALLER PUSH2 0x1F JUMP JUMPDEST PUSH2 0x6F JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 DUP2 AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH2 0x8FE DUP1 PUSH2 0x7E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xEAD710C4 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0xEF690CC0 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0xDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0x715018A6 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0xC0129D43 EQ PUSH2 0xAE JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xF1 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x183 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x67D JUMP JUMPDEST PUSH2 0x2AB JUMP JUMPDEST PUSH2 0xD1 PUSH2 0x37B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xA5 SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xEC CALLDATASIZE PUSH1 0x4 PUSH2 0x640 JUMP JUMPDEST PUSH2 0x409 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x177 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x181 PUSH1 0x0 PUSH2 0x532 JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x204 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x20F PUSH1 0xA NUMBER PUSH2 0x83D JUMP JUMPDEST PUSH1 0x0 EQ PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x8A8 PUSH1 0x21 SWAP2 CODECOPY SWAP1 PUSH2 0x263 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x2 DUP1 DUP3 MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 SWAP1 SWAP3 ADD SWAP2 DUP3 MSTORE PUSH2 0x2A8 SWAP2 PUSH1 0x1 SWAP2 PUSH2 0x5A7 JUMP JUMPDEST POP JUMP JUMPDEST PUSH32 0x71B78290913AF2ADDD8FCBE5766DE306AF2C8AFBC466CA891E207F73638C7270 DUP2 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2DD SWAP2 SWAP1 PUSH2 0x74C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ ISZERO PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP SWAP1 PUSH2 0x363 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP DUP1 MLOAD PUSH2 0x377 SWAP1 PUSH1 0x1 SWAP1 PUSH1 0x20 DUP5 ADD SWAP1 PUSH2 0x5A7 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH2 0x388 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x3B4 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x401 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x3D6 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x401 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x3E4 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x48A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND PUSH2 0x52D JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x26 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A206E6577206F776E657220697320746865207A65726F2061 PUSH1 0x44 DUP3 ADD MSTORE PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000 PUSH1 0x64 DUP3 ADD MSTORE PUSH1 0x84 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x2A8 DUP2 JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x5B3 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x5D5 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0x5EE JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH2 0x61B JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x61B JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x600 JUMP JUMPDEST POP PUSH2 0x627 SWAP3 SWAP2 POP PUSH2 0x62B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x627 JUMPI PUSH1 0x0 DUP2 SSTORE PUSH1 0x1 ADD PUSH2 0x62C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x652 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x676 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x68F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x6A7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x6CD JUMPI PUSH2 0x6CD PUSH2 0x878 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x713 JUMPI PUSH2 0x713 PUSH2 0x878 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x72C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x75E DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 DUP3 MLOAD DUP1 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x787 DUP2 PUSH1 0x40 DUP6 ADD PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP2 SWAP1 SWAP2 ADD PUSH1 0x40 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x7D4 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x7BC JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x7E3 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SHR SWAP1 DUP3 AND DUP1 PUSH2 0x7FD JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 EQ ISZERO PUSH2 0x837 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH2 0x873 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x12 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP MOD SWAP1 JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID PUSH10 0x6E76616C696420626C6F PUSH4 0x6B206E75 PUSH14 0x6265722C20706C65617365207761 PUSH10 0x74A26469706673582212 KECCAK256 SDIV DIV 0x5F GASPRICE RETURNDATACOPY MSTORE MULMOD 0xD1 0xD8 0x29 ADDMOD SWAP3 SSTORE 0x5E SWAP6 SLOAD SWAP7 0xEF 0xC2 CODECOPY CREATE DUP10 0xD2 0xB9 0xB8 SWAP12 LOG3 SAR 0xAB 0xA7 RETURNDATACOPY SWAP6 PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x39E CODESIZE SUB DUP1 PUSH2 0x39E DUP4 CODECOPY DUP2 ADD PUSH1 0x40 DUP2 SWAP1 MSTORE PUSH2 0x2F SWAP2 PUSH2 0x54 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x84 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x66 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH2 0x7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH2 0x30B DUP1 PUSH2 0x93 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC0129D43 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x58 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x43 PUSH2 0x53 CALLDATASIZE PUSH1 0x4 PUSH2 0x164 JUMP JUMPDEST PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0xC0129D4300000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP3 PUSH4 0xC0129D43 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xD3 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x12F SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0x233 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x149 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x15D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x176 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x18E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x1A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1B4 JUMPI PUSH2 0x1B4 PUSH2 0x2A6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x1FA JUMPI PUSH2 0x1FA PUSH2 0x2A6 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x213 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 MSTORE DUP4 MLOAD DUP1 DUP3 DUP6 ADD MSTORE PUSH1 0x0 JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x260 JUMPI DUP6 DUP2 ADD DUP4 ADD MLOAD DUP6 DUP3 ADD PUSH1 0x40 ADD MSTORE DUP3 ADD PUSH2 0x244 JUMP JUMPDEST DUP2 DUP2 GT ISZERO PUSH2 0x272 JUMPI PUSH1 0x0 PUSH1 0x40 DUP4 DUP8 ADD ADD MSTORE JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x40 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xBF 0xA7 0x2E 0xD9 0xEA 0xD JUMPI SWAP1 0x5E SWAP3 DUP2 0x1E ORIGIN DUP3 PUSH1 0x53 BASEFEE MOD 0xDB 0xDB DUP11 0xD5 DUP7 PUSH22 0x306B2582254F247564736F6C63430008070033A26469 PUSH17 0x667358221220AD80BD62F261460562CA17 0x4E 0xE1 0xC9 DUP13 KECCAK256 0x4F 0xEF PUSH24 0x77D1D6F8BACAE87697631DF73C64736F6C63430008070033 ","sourceMap":"139:488:4:-:0;;;1573:26:0;;;-1:-1:-1;;1573:26:0;1595:4;1573:26;;;139:488:4;;;;;;;;;;;;;;;;"},"deployedBytecode":{"functionDebugData":{"@IS_TEST_532":{"entryPoint":null,"id":532,"parameterSlots":0,"returnSlots":0},"@assertEq_1977":{"entryPoint":1857,"id":1977,"parameterSlots":2,"returnSlots":0},"@fail_569":{"entryPoint":null,"id":569,"parameterSlots":0,"returnSlots":0},"@failed_534":{"entryPoint":null,"id":534,"parameterSlots":0,"returnSlots":0},"@setUp_308":{"entryPoint":215,"id":308,"parameterSlots":0,"returnSlots":0},"@testCanSetGreeting_109":{"entryPoint":1428,"id":109,"parameterSlots":0,"returnSlots":0},"@testCannotGm_92":{"entryPoint":746,"id":92,"parameterSlots":0,"returnSlots":0},"@testWorksForAllGreetings_128":{"entryPoint":1089,"id":128,"parameterSlots":1,"returnSlots":0},"abi_decode_tuple_t_string_memory_ptr":{"entryPoint":2270,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_tuple_t_string_memory_ptr_fromMemory":{"entryPoint":2404,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_string":{"entryPoint":2534,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed":{"entryPoint":2608,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_address__to_t_address__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":2636,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_stringliteral_58e3ca0e65e73c038df3db6a7cab1bf7de300d13038b802ce0f4435889c48e5e__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":1,"returnSlots":1},"abi_encode_tuple_t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":1,"returnSlots":1},"abi_encode_tuple_t_stringliteral_7624778dedc75f8b322b9fa1632a610d40b85e106c7d9bf0e743a9ce291b9c6f__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":1,"returnSlots":1},"abi_encode_tuple_t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed":{"entryPoint":2662,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed":{"entryPoint":2733,"id":null,"parameterSlots":2,"returnSlots":1},"array_allocation_size_string":{"entryPoint":2804,"id":null,"parameterSlots":1,"returnSlots":1},"copy_memory_to_memory":{"entryPoint":2874,"id":null,"parameterSlots":3,"returnSlots":0},"finalize_allocation":{"entryPoint":2918,"id":null,"parameterSlots":2,"returnSlots":0},"panic_error_0x41":{"entryPoint":2993,"id":null,"parameterSlots":0,"returnSlots":0},"return_data_selector":{"entryPoint":3040,"id":null,"parameterSlots":0,"returnSlots":1},"try_decode_error_message":{"entryPoint":3068,"id":null,"parameterSlots":0,"returnSlots":1}},"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:6603:7","statements":[{"nodeType":"YulBlock","src":"6:3:7","statements":[]},{"body":{"nodeType":"YulBlock","src":"94:649:7","statements":[{"body":{"nodeType":"YulBlock","src":"140:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"149:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"152:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"142:6:7"},"nodeType":"YulFunctionCall","src":"142:12:7"},"nodeType":"YulExpressionStatement","src":"142:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"115:7:7"},{"name":"headStart","nodeType":"YulIdentifier","src":"124:9:7"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"111:3:7"},"nodeType":"YulFunctionCall","src":"111:23:7"},{"kind":"number","nodeType":"YulLiteral","src":"136:2:7","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"107:3:7"},"nodeType":"YulFunctionCall","src":"107:32:7"},"nodeType":"YulIf","src":"104:52:7"},{"nodeType":"YulVariableDeclaration","src":"165:37:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"192:9:7"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"179:12:7"},"nodeType":"YulFunctionCall","src":"179:23:7"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"169:6:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"245:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"254:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"257:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"247:6:7"},"nodeType":"YulFunctionCall","src":"247:12:7"},"nodeType":"YulExpressionStatement","src":"247:12:7"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"217:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"225:18:7","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"214:2:7"},"nodeType":"YulFunctionCall","src":"214:30:7"},"nodeType":"YulIf","src":"211:50:7"},{"nodeType":"YulVariableDeclaration","src":"270:32:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"284:9:7"},{"name":"offset","nodeType":"YulIdentifier","src":"295:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"280:3:7"},"nodeType":"YulFunctionCall","src":"280:22:7"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"274:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"350:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"359:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"362:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"352:6:7"},"nodeType":"YulFunctionCall","src":"352:12:7"},"nodeType":"YulExpressionStatement","src":"352:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_1","nodeType":"YulIdentifier","src":"329:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"333:4:7","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"325:3:7"},"nodeType":"YulFunctionCall","src":"325:13:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"340:7:7"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"321:3:7"},"nodeType":"YulFunctionCall","src":"321:27:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"314:6:7"},"nodeType":"YulFunctionCall","src":"314:35:7"},"nodeType":"YulIf","src":"311:55:7"},{"nodeType":"YulVariableDeclaration","src":"375:26:7","value":{"arguments":[{"name":"_1","nodeType":"YulIdentifier","src":"398:2:7"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"385:12:7"},"nodeType":"YulFunctionCall","src":"385:16:7"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"379:2:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"410:42:7","value":{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"449:2:7"}],"functionName":{"name":"array_allocation_size_string","nodeType":"YulIdentifier","src":"420:28:7"},"nodeType":"YulFunctionCall","src":"420:32:7"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"414:2:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"461:23:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"481:2:7","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"475:5:7"},"nodeType":"YulFunctionCall","src":"475:9:7"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"465:6:7","type":""}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"513:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"521:2:7"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"493:19:7"},"nodeType":"YulFunctionCall","src":"493:31:7"},"nodeType":"YulExpressionStatement","src":"493:31:7"},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"540:6:7"},{"name":"_2","nodeType":"YulIdentifier","src":"548:2:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"533:6:7"},"nodeType":"YulFunctionCall","src":"533:18:7"},"nodeType":"YulExpressionStatement","src":"533:18:7"},{"body":{"nodeType":"YulBlock","src":"597:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"606:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"609:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"599:6:7"},"nodeType":"YulFunctionCall","src":"599:12:7"},"nodeType":"YulExpressionStatement","src":"599:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_1","nodeType":"YulIdentifier","src":"574:2:7"},{"name":"_2","nodeType":"YulIdentifier","src":"578:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"570:3:7"},"nodeType":"YulFunctionCall","src":"570:11:7"},{"kind":"number","nodeType":"YulLiteral","src":"583:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"566:3:7"},"nodeType":"YulFunctionCall","src":"566:20:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"588:7:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"563:2:7"},"nodeType":"YulFunctionCall","src":"563:33:7"},"nodeType":"YulIf","src":"560:53:7"},{"expression":{"arguments":[{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"639:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"647:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"635:3:7"},"nodeType":"YulFunctionCall","src":"635:15:7"},{"arguments":[{"name":"_1","nodeType":"YulIdentifier","src":"656:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"660:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"652:3:7"},"nodeType":"YulFunctionCall","src":"652:11:7"},{"name":"_2","nodeType":"YulIdentifier","src":"665:2:7"}],"functionName":{"name":"calldatacopy","nodeType":"YulIdentifier","src":"622:12:7"},"nodeType":"YulFunctionCall","src":"622:46:7"},"nodeType":"YulExpressionStatement","src":"622:46:7"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"692:6:7"},{"name":"_2","nodeType":"YulIdentifier","src":"700:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"688:3:7"},"nodeType":"YulFunctionCall","src":"688:15:7"},{"kind":"number","nodeType":"YulLiteral","src":"705:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"684:3:7"},"nodeType":"YulFunctionCall","src":"684:24:7"},{"kind":"number","nodeType":"YulLiteral","src":"710:1:7","type":"","value":"0"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"677:6:7"},"nodeType":"YulFunctionCall","src":"677:35:7"},"nodeType":"YulExpressionStatement","src":"677:35:7"},{"nodeType":"YulAssignment","src":"721:16:7","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"731:6:7"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"721:6:7"}]}]},"name":"abi_decode_tuple_t_string_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"60:9:7","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"71:7:7","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"83:6:7","type":""}],"src":"14:729:7"},{"body":{"nodeType":"YulBlock","src":"839:600:7","statements":[{"body":{"nodeType":"YulBlock","src":"885:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"894:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"897:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"887:6:7"},"nodeType":"YulFunctionCall","src":"887:12:7"},"nodeType":"YulExpressionStatement","src":"887:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"860:7:7"},{"name":"headStart","nodeType":"YulIdentifier","src":"869:9:7"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"856:3:7"},"nodeType":"YulFunctionCall","src":"856:23:7"},{"kind":"number","nodeType":"YulLiteral","src":"881:2:7","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"852:3:7"},"nodeType":"YulFunctionCall","src":"852:32:7"},"nodeType":"YulIf","src":"849:52:7"},{"nodeType":"YulVariableDeclaration","src":"910:30:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"930:9:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"924:5:7"},"nodeType":"YulFunctionCall","src":"924:16:7"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"914:6:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"983:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"992:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"995:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"985:6:7"},"nodeType":"YulFunctionCall","src":"985:12:7"},"nodeType":"YulExpressionStatement","src":"985:12:7"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"955:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"963:18:7","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"952:2:7"},"nodeType":"YulFunctionCall","src":"952:30:7"},"nodeType":"YulIf","src":"949:50:7"},{"nodeType":"YulVariableDeclaration","src":"1008:32:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1022:9:7"},{"name":"offset","nodeType":"YulIdentifier","src":"1033:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1018:3:7"},"nodeType":"YulFunctionCall","src":"1018:22:7"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"1012:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"1088:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1097:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1100:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1090:6:7"},"nodeType":"YulFunctionCall","src":"1090:12:7"},"nodeType":"YulExpressionStatement","src":"1090:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_1","nodeType":"YulIdentifier","src":"1067:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"1071:4:7","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1063:3:7"},"nodeType":"YulFunctionCall","src":"1063:13:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"1078:7:7"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"1059:3:7"},"nodeType":"YulFunctionCall","src":"1059:27:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"1052:6:7"},"nodeType":"YulFunctionCall","src":"1052:35:7"},"nodeType":"YulIf","src":"1049:55:7"},{"nodeType":"YulVariableDeclaration","src":"1113:19:7","value":{"arguments":[{"name":"_1","nodeType":"YulIdentifier","src":"1129:2:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1123:5:7"},"nodeType":"YulFunctionCall","src":"1123:9:7"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"1117:2:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1141:42:7","value":{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"1180:2:7"}],"functionName":{"name":"array_allocation_size_string","nodeType":"YulIdentifier","src":"1151:28:7"},"nodeType":"YulFunctionCall","src":"1151:32:7"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"1145:2:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1192:23:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1212:2:7","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1206:5:7"},"nodeType":"YulFunctionCall","src":"1206:9:7"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"1196:6:7","type":""}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1244:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"1252:2:7"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"1224:19:7"},"nodeType":"YulFunctionCall","src":"1224:31:7"},"nodeType":"YulExpressionStatement","src":"1224:31:7"},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1271:6:7"},{"name":"_2","nodeType":"YulIdentifier","src":"1279:2:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1264:6:7"},"nodeType":"YulFunctionCall","src":"1264:18:7"},"nodeType":"YulExpressionStatement","src":"1264:18:7"},{"body":{"nodeType":"YulBlock","src":"1328:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1337:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1340:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1330:6:7"},"nodeType":"YulFunctionCall","src":"1330:12:7"},"nodeType":"YulExpressionStatement","src":"1330:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_1","nodeType":"YulIdentifier","src":"1305:2:7"},{"name":"_2","nodeType":"YulIdentifier","src":"1309:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1301:3:7"},"nodeType":"YulFunctionCall","src":"1301:11:7"},{"kind":"number","nodeType":"YulLiteral","src":"1314:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1297:3:7"},"nodeType":"YulFunctionCall","src":"1297:20:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"1319:7:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1294:2:7"},"nodeType":"YulFunctionCall","src":"1294:33:7"},"nodeType":"YulIf","src":"1291:53:7"},{"expression":{"arguments":[{"arguments":[{"name":"_1","nodeType":"YulIdentifier","src":"1379:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"1383:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1375:3:7"},"nodeType":"YulFunctionCall","src":"1375:11:7"},{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1392:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1400:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1388:3:7"},"nodeType":"YulFunctionCall","src":"1388:15:7"},{"name":"_2","nodeType":"YulIdentifier","src":"1405:2:7"}],"functionName":{"name":"copy_memory_to_memory","nodeType":"YulIdentifier","src":"1353:21:7"},"nodeType":"YulFunctionCall","src":"1353:55:7"},"nodeType":"YulExpressionStatement","src":"1353:55:7"},{"nodeType":"YulAssignment","src":"1417:16:7","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"1427:6:7"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1417:6:7"}]}]},"name":"abi_decode_tuple_t_string_memory_ptr_fromMemory","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"805:9:7","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"816:7:7","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"828:6:7","type":""}],"src":"748:691:7"},{"body":{"nodeType":"YulBlock","src":"1494:267:7","statements":[{"nodeType":"YulVariableDeclaration","src":"1504:26:7","value":{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1524:5:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1518:5:7"},"nodeType":"YulFunctionCall","src":"1518:12:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"1508:6:7","type":""}]},{"expression":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"1546:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"1551:6:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1539:6:7"},"nodeType":"YulFunctionCall","src":"1539:19:7"},"nodeType":"YulExpressionStatement","src":"1539:19:7"},{"expression":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1593:5:7"},{"kind":"number","nodeType":"YulLiteral","src":"1600:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1589:3:7"},"nodeType":"YulFunctionCall","src":"1589:16:7"},{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"1611:3:7"},{"kind":"number","nodeType":"YulLiteral","src":"1616:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1607:3:7"},"nodeType":"YulFunctionCall","src":"1607:14:7"},{"name":"length","nodeType":"YulIdentifier","src":"1623:6:7"}],"functionName":{"name":"copy_memory_to_memory","nodeType":"YulIdentifier","src":"1567:21:7"},"nodeType":"YulFunctionCall","src":"1567:63:7"},"nodeType":"YulExpressionStatement","src":"1567:63:7"},{"nodeType":"YulAssignment","src":"1639:116:7","value":{"arguments":[{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"1654:3:7"},{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1667:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1675:2:7","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1663:3:7"},"nodeType":"YulFunctionCall","src":"1663:15:7"},{"kind":"number","nodeType":"YulLiteral","src":"1680:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"1659:3:7"},"nodeType":"YulFunctionCall","src":"1659:88:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1650:3:7"},"nodeType":"YulFunctionCall","src":"1650:98:7"},{"kind":"number","nodeType":"YulLiteral","src":"1750:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1646:3:7"},"nodeType":"YulFunctionCall","src":"1646:109:7"},"variableNames":[{"name":"end","nodeType":"YulIdentifier","src":"1639:3:7"}]}]},"name":"abi_encode_string","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1471:5:7","type":""},{"name":"pos","nodeType":"YulTypedName","src":"1478:3:7","type":""}],"returnVariables":[{"name":"end","nodeType":"YulTypedName","src":"1486:3:7","type":""}],"src":"1444:317:7"},{"body":{"nodeType":"YulBlock","src":"1905:137:7","statements":[{"nodeType":"YulVariableDeclaration","src":"1915:27:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1935:6:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1929:5:7"},"nodeType":"YulFunctionCall","src":"1929:13:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"1919:6:7","type":""}]},{"expression":{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1977:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1985:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1973:3:7"},"nodeType":"YulFunctionCall","src":"1973:17:7"},{"name":"pos","nodeType":"YulIdentifier","src":"1992:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"1997:6:7"}],"functionName":{"name":"copy_memory_to_memory","nodeType":"YulIdentifier","src":"1951:21:7"},"nodeType":"YulFunctionCall","src":"1951:53:7"},"nodeType":"YulExpressionStatement","src":"1951:53:7"},{"nodeType":"YulAssignment","src":"2013:23:7","value":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"2024:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"2029:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2020:3:7"},"nodeType":"YulFunctionCall","src":"2020:16:7"},"variableNames":[{"name":"end","nodeType":"YulIdentifier","src":"2013:3:7"}]}]},"name":"abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"pos","nodeType":"YulTypedName","src":"1881:3:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1886:6:7","type":""}],"returnVariables":[{"name":"end","nodeType":"YulTypedName","src":"1897:3:7","type":""}],"src":"1766:276:7"},{"body":{"nodeType":"YulBlock","src":"2148:125:7","statements":[{"nodeType":"YulAssignment","src":"2158:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2170:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2181:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2166:3:7"},"nodeType":"YulFunctionCall","src":"2166:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"2158:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2200:9:7"},{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"2215:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"2223:42:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffff"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"2211:3:7"},"nodeType":"YulFunctionCall","src":"2211:55:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2193:6:7"},"nodeType":"YulFunctionCall","src":"2193:74:7"},"nodeType":"YulExpressionStatement","src":"2193:74:7"}]},"name":"abi_encode_tuple_t_address__to_t_address__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2117:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"2128:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2139:4:7","type":""}],"src":"2047:226:7"},{"body":{"nodeType":"YulBlock","src":"2373:92:7","statements":[{"nodeType":"YulAssignment","src":"2383:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2395:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2406:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2391:3:7"},"nodeType":"YulFunctionCall","src":"2391:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"2383:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2425:9:7"},{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"2450:6:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"2443:6:7"},"nodeType":"YulFunctionCall","src":"2443:14:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"2436:6:7"},"nodeType":"YulFunctionCall","src":"2436:22:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2418:6:7"},"nodeType":"YulFunctionCall","src":"2418:41:7"},"nodeType":"YulExpressionStatement","src":"2418:41:7"}]},"name":"abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2342:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"2353:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2364:4:7","type":""}],"src":"2278:187:7"},{"body":{"nodeType":"YulBlock","src":"2591:99:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2608:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2619:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2601:6:7"},"nodeType":"YulFunctionCall","src":"2601:21:7"},"nodeType":"YulExpressionStatement","src":"2601:21:7"},{"nodeType":"YulAssignment","src":"2631:53:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"2657:6:7"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2669:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2680:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2665:3:7"},"nodeType":"YulFunctionCall","src":"2665:18:7"}],"functionName":{"name":"abi_encode_string","nodeType":"YulIdentifier","src":"2639:17:7"},"nodeType":"YulFunctionCall","src":"2639:45:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"2631:4:7"}]}]},"name":"abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2560:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"2571:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2582:4:7","type":""}],"src":"2470:220:7"},{"body":{"nodeType":"YulBlock","src":"2869:226:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2886:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2897:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2879:6:7"},"nodeType":"YulFunctionCall","src":"2879:21:7"},"nodeType":"YulExpressionStatement","src":"2879:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2920:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2931:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2916:3:7"},"nodeType":"YulFunctionCall","src":"2916:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"2936:2:7","type":"","value":"36"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2909:6:7"},"nodeType":"YulFunctionCall","src":"2909:30:7"},"nodeType":"YulExpressionStatement","src":"2909:30:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2959:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"2970:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2955:3:7"},"nodeType":"YulFunctionCall","src":"2955:18:7"},{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b737472","kind":"string","nodeType":"YulLiteral","src":"2975:34:7","type":"","value":"Error: a == b not satisfied [str"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2948:6:7"},"nodeType":"YulFunctionCall","src":"2948:62:7"},"nodeType":"YulExpressionStatement","src":"2948:62:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3030:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3041:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3026:3:7"},"nodeType":"YulFunctionCall","src":"3026:18:7"},{"hexValue":"696e675d","kind":"string","nodeType":"YulLiteral","src":"3046:6:7","type":"","value":"ing]"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3019:6:7"},"nodeType":"YulFunctionCall","src":"3019:34:7"},"nodeType":"YulExpressionStatement","src":"3019:34:7"},{"nodeType":"YulAssignment","src":"3062:27:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3074:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3085:3:7","type":"","value":"128"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3070:3:7"},"nodeType":"YulFunctionCall","src":"3070:19:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3062:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_58e3ca0e65e73c038df3db6a7cab1bf7de300d13038b802ce0f4435889c48e5e__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2846:9:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2860:4:7","type":""}],"src":"2695:400:7"},{"body":{"nodeType":"YulBlock","src":"3274:151:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3291:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3302:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3284:6:7"},"nodeType":"YulFunctionCall","src":"3284:21:7"},"nodeType":"YulExpressionStatement","src":"3284:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3325:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3336:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3321:3:7"},"nodeType":"YulFunctionCall","src":"3321:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"3341:1:7","type":"","value":"2"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3314:6:7"},"nodeType":"YulFunctionCall","src":"3314:29:7"},"nodeType":"YulExpressionStatement","src":"3314:29:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3363:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3374:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3359:3:7"},"nodeType":"YulFunctionCall","src":"3359:18:7"},{"hexValue":"676d","kind":"string","nodeType":"YulLiteral","src":"3379:4:7","type":"","value":"gm"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3352:6:7"},"nodeType":"YulFunctionCall","src":"3352:32:7"},"nodeType":"YulExpressionStatement","src":"3352:32:7"},{"nodeType":"YulAssignment","src":"3393:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3405:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3416:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3401:3:7"},"nodeType":"YulFunctionCall","src":"3401:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3393:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3251:9:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"3265:4:7","type":""}],"src":"3100:325:7"},{"body":{"nodeType":"YulBlock","src":"3604:151:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3621:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3632:2:7","type":"","value":"32"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3614:6:7"},"nodeType":"YulFunctionCall","src":"3614:21:7"},"nodeType":"YulExpressionStatement","src":"3614:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3655:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3666:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3651:3:7"},"nodeType":"YulFunctionCall","src":"3651:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"3671:1:7","type":"","value":"2"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3644:6:7"},"nodeType":"YulFunctionCall","src":"3644:29:7"},"nodeType":"YulExpressionStatement","src":"3644:29:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3693:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3704:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3689:3:7"},"nodeType":"YulFunctionCall","src":"3689:18:7"},{"hexValue":"6869","kind":"string","nodeType":"YulLiteral","src":"3709:4:7","type":"","value":"hi"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3682:6:7"},"nodeType":"YulFunctionCall","src":"3682:32:7"},"nodeType":"YulExpressionStatement","src":"3682:32:7"},{"nodeType":"YulAssignment","src":"3723:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3735:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"3746:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3731:3:7"},"nodeType":"YulFunctionCall","src":"3731:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3723:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_7624778dedc75f8b322b9fa1632a610d40b85e106c7d9bf0e743a9ce291b9c6f__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3581:9:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"3595:4:7","type":""}],"src":"3430:325:7"},{"body":{"nodeType":"YulBlock","src":"3982:228:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3999:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4010:2:7","type":"","value":"64"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3992:6:7"},"nodeType":"YulFunctionCall","src":"3992:21:7"},"nodeType":"YulExpressionStatement","src":"3992:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4033:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4044:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4029:3:7"},"nodeType":"YulFunctionCall","src":"4029:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"4049:1:7","type":"","value":"9"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4022:6:7"},"nodeType":"YulFunctionCall","src":"4022:29:7"},"nodeType":"YulExpressionStatement","src":"4022:29:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4071:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4082:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4067:3:7"},"nodeType":"YulFunctionCall","src":"4067:18:7"},{"hexValue":"202056616c75652061","kind":"string","nodeType":"YulLiteral","src":"4087:11:7","type":"","value":" Value a"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4060:6:7"},"nodeType":"YulFunctionCall","src":"4060:39:7"},"nodeType":"YulExpressionStatement","src":"4060:39:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4119:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4130:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4115:3:7"},"nodeType":"YulFunctionCall","src":"4115:20:7"},{"kind":"number","nodeType":"YulLiteral","src":"4137:3:7","type":"","value":"128"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4108:6:7"},"nodeType":"YulFunctionCall","src":"4108:33:7"},"nodeType":"YulExpressionStatement","src":"4108:33:7"},{"nodeType":"YulAssignment","src":"4150:54:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"4176:6:7"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4188:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4199:3:7","type":"","value":"128"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4184:3:7"},"nodeType":"YulFunctionCall","src":"4184:19:7"}],"functionName":{"name":"abi_encode_string","nodeType":"YulIdentifier","src":"4158:17:7"},"nodeType":"YulFunctionCall","src":"4158:46:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"4150:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3951:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"3962:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"3973:4:7","type":""}],"src":"3760:450:7"},{"body":{"nodeType":"YulBlock","src":"4437:228:7","statements":[{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4454:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4465:2:7","type":"","value":"64"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4447:6:7"},"nodeType":"YulFunctionCall","src":"4447:21:7"},"nodeType":"YulExpressionStatement","src":"4447:21:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4488:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4499:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4484:3:7"},"nodeType":"YulFunctionCall","src":"4484:18:7"},{"kind":"number","nodeType":"YulLiteral","src":"4504:1:7","type":"","value":"9"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4477:6:7"},"nodeType":"YulFunctionCall","src":"4477:29:7"},"nodeType":"YulExpressionStatement","src":"4477:29:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4526:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4537:2:7","type":"","value":"96"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4522:3:7"},"nodeType":"YulFunctionCall","src":"4522:18:7"},{"hexValue":"202056616c75652062","kind":"string","nodeType":"YulLiteral","src":"4542:11:7","type":"","value":" Value b"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4515:6:7"},"nodeType":"YulFunctionCall","src":"4515:39:7"},"nodeType":"YulExpressionStatement","src":"4515:39:7"},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4574:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4585:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4570:3:7"},"nodeType":"YulFunctionCall","src":"4570:20:7"},{"kind":"number","nodeType":"YulLiteral","src":"4592:3:7","type":"","value":"128"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"4563:6:7"},"nodeType":"YulFunctionCall","src":"4563:33:7"},"nodeType":"YulExpressionStatement","src":"4563:33:7"},{"nodeType":"YulAssignment","src":"4605:54:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"4631:6:7"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"4643:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"4654:3:7","type":"","value":"128"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4639:3:7"},"nodeType":"YulFunctionCall","src":"4639:19:7"}],"functionName":{"name":"abi_encode_string","nodeType":"YulIdentifier","src":"4613:17:7"},"nodeType":"YulFunctionCall","src":"4613:46:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"4605:4:7"}]}]},"name":"abi_encode_tuple_t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"4406:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"4417:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"4428:4:7","type":""}],"src":"4215:450:7"},{"body":{"nodeType":"YulBlock","src":"4728:188:7","statements":[{"body":{"nodeType":"YulBlock","src":"4772:22:7","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"4774:16:7"},"nodeType":"YulFunctionCall","src":"4774:18:7"},"nodeType":"YulExpressionStatement","src":"4774:18:7"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"4744:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"4752:18:7","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"4741:2:7"},"nodeType":"YulFunctionCall","src":"4741:30:7"},"nodeType":"YulIf","src":"4738:56:7"},{"nodeType":"YulAssignment","src":"4803:107:7","value":{"arguments":[{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"4823:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"4831:2:7","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4819:3:7"},"nodeType":"YulFunctionCall","src":"4819:15:7"},{"kind":"number","nodeType":"YulLiteral","src":"4836:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"4815:3:7"},"nodeType":"YulFunctionCall","src":"4815:88:7"},{"kind":"number","nodeType":"YulLiteral","src":"4905:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"4811:3:7"},"nodeType":"YulFunctionCall","src":"4811:99:7"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"4803:4:7"}]}]},"name":"array_allocation_size_string","nodeType":"YulFunctionDefinition","parameters":[{"name":"length","nodeType":"YulTypedName","src":"4708:6:7","type":""}],"returnVariables":[{"name":"size","nodeType":"YulTypedName","src":"4719:4:7","type":""}],"src":"4670:246:7"},{"body":{"nodeType":"YulBlock","src":"4974:205:7","statements":[{"nodeType":"YulVariableDeclaration","src":"4984:10:7","value":{"kind":"number","nodeType":"YulLiteral","src":"4993:1:7","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"4988:1:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"5053:63:7","statements":[{"expression":{"arguments":[{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"5078:3:7"},{"name":"i","nodeType":"YulIdentifier","src":"5083:1:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5074:3:7"},"nodeType":"YulFunctionCall","src":"5074:11:7"},{"arguments":[{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"5097:3:7"},{"name":"i","nodeType":"YulIdentifier","src":"5102:1:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5093:3:7"},"nodeType":"YulFunctionCall","src":"5093:11:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"5087:5:7"},"nodeType":"YulFunctionCall","src":"5087:18:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"5067:6:7"},"nodeType":"YulFunctionCall","src":"5067:39:7"},"nodeType":"YulExpressionStatement","src":"5067:39:7"}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"5014:1:7"},{"name":"length","nodeType":"YulIdentifier","src":"5017:6:7"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"5011:2:7"},"nodeType":"YulFunctionCall","src":"5011:13:7"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"5025:19:7","statements":[{"nodeType":"YulAssignment","src":"5027:15:7","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"5036:1:7"},{"kind":"number","nodeType":"YulLiteral","src":"5039:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5032:3:7"},"nodeType":"YulFunctionCall","src":"5032:10:7"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"5027:1:7"}]}]},"pre":{"nodeType":"YulBlock","src":"5007:3:7","statements":[]},"src":"5003:113:7"},{"body":{"nodeType":"YulBlock","src":"5142:31:7","statements":[{"expression":{"arguments":[{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"5155:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"5160:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5151:3:7"},"nodeType":"YulFunctionCall","src":"5151:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"5169:1:7","type":"","value":"0"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"5144:6:7"},"nodeType":"YulFunctionCall","src":"5144:27:7"},"nodeType":"YulExpressionStatement","src":"5144:27:7"}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"5131:1:7"},{"name":"length","nodeType":"YulIdentifier","src":"5134:6:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"5128:2:7"},"nodeType":"YulFunctionCall","src":"5128:13:7"},"nodeType":"YulIf","src":"5125:48:7"}]},"name":"copy_memory_to_memory","nodeType":"YulFunctionDefinition","parameters":[{"name":"src","nodeType":"YulTypedName","src":"4952:3:7","type":""},{"name":"dst","nodeType":"YulTypedName","src":"4957:3:7","type":""},{"name":"length","nodeType":"YulTypedName","src":"4962:6:7","type":""}],"src":"4921:258:7"},{"body":{"nodeType":"YulBlock","src":"5231:261:7","statements":[{"nodeType":"YulVariableDeclaration","src":"5241:117:7","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"5263:6:7"},{"arguments":[{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"5279:4:7"},{"kind":"number","nodeType":"YulLiteral","src":"5285:2:7","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5275:3:7"},"nodeType":"YulFunctionCall","src":"5275:13:7"},{"kind":"number","nodeType":"YulLiteral","src":"5290:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"5271:3:7"},"nodeType":"YulFunctionCall","src":"5271:86:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"5259:3:7"},"nodeType":"YulFunctionCall","src":"5259:99:7"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"5245:10:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"5433:22:7","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"5435:16:7"},"nodeType":"YulFunctionCall","src":"5435:18:7"},"nodeType":"YulExpressionStatement","src":"5435:18:7"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"5376:10:7"},{"kind":"number","nodeType":"YulLiteral","src":"5388:18:7","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"5373:2:7"},"nodeType":"YulFunctionCall","src":"5373:34:7"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"5412:10:7"},{"name":"memPtr","nodeType":"YulIdentifier","src":"5424:6:7"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"5409:2:7"},"nodeType":"YulFunctionCall","src":"5409:22:7"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"5370:2:7"},"nodeType":"YulFunctionCall","src":"5370:62:7"},"nodeType":"YulIf","src":"5367:88:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"5471:2:7","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"5475:10:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"5464:6:7"},"nodeType":"YulFunctionCall","src":"5464:22:7"},"nodeType":"YulExpressionStatement","src":"5464:22:7"}]},"name":"finalize_allocation","nodeType":"YulFunctionDefinition","parameters":[{"name":"memPtr","nodeType":"YulTypedName","src":"5213:6:7","type":""},{"name":"size","nodeType":"YulTypedName","src":"5221:4:7","type":""}],"src":"5184:308:7"},{"body":{"nodeType":"YulBlock","src":"5529:152:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"5546:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"5549:77:7","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"5539:6:7"},"nodeType":"YulFunctionCall","src":"5539:88:7"},"nodeType":"YulExpressionStatement","src":"5539:88:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"5643:1:7","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"5646:4:7","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"5636:6:7"},"nodeType":"YulFunctionCall","src":"5636:15:7"},"nodeType":"YulExpressionStatement","src":"5636:15:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"5667:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"5670:4:7","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"5660:6:7"},"nodeType":"YulFunctionCall","src":"5660:15:7"},"nodeType":"YulExpressionStatement","src":"5660:15:7"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"5497:184:7"},{"body":{"nodeType":"YulBlock","src":"5729:136:7","statements":[{"body":{"nodeType":"YulBlock","src":"5774:85:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"5803:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"5806:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"5809:1:7","type":"","value":"4"}],"functionName":{"name":"returndatacopy","nodeType":"YulIdentifier","src":"5788:14:7"},"nodeType":"YulFunctionCall","src":"5788:23:7"},"nodeType":"YulExpressionStatement","src":"5788:23:7"},{"nodeType":"YulAssignment","src":"5824:25:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"5835:3:7","type":"","value":"224"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"5846:1:7","type":"","value":"0"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"5840:5:7"},"nodeType":"YulFunctionCall","src":"5840:8:7"}],"functionName":{"name":"shr","nodeType":"YulIdentifier","src":"5831:3:7"},"nodeType":"YulFunctionCall","src":"5831:18:7"},"variableNames":[{"name":"sig","nodeType":"YulIdentifier","src":"5824:3:7"}]}]},"condition":{"arguments":[{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"5745:14:7"},"nodeType":"YulFunctionCall","src":"5745:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"5763:1:7","type":"","value":"3"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"5742:2:7"},"nodeType":"YulFunctionCall","src":"5742:23:7"},"nodeType":"YulIf","src":"5739:120:7"}]},"name":"return_data_selector","nodeType":"YulFunctionDefinition","returnVariables":[{"name":"sig","nodeType":"YulTypedName","src":"5721:3:7","type":""}],"src":"5686:179:7"},{"body":{"nodeType":"YulBlock","src":"5917:684:7","statements":[{"body":{"nodeType":"YulBlock","src":"5957:9:7","statements":[{"nodeType":"YulLeave","src":"5959:5:7"}]},"condition":{"arguments":[{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"5933:14:7"},"nodeType":"YulFunctionCall","src":"5933:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"5951:4:7","type":"","value":"0x44"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"5930:2:7"},"nodeType":"YulFunctionCall","src":"5930:26:7"},"nodeType":"YulIf","src":"5927:39:7"},{"nodeType":"YulVariableDeclaration","src":"5975:21:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"5993:2:7","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"5987:5:7"},"nodeType":"YulFunctionCall","src":"5987:9:7"},"variables":[{"name":"data","nodeType":"YulTypedName","src":"5979:4:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"6005:76:7","value":{"kind":"number","nodeType":"YulLiteral","src":"6015:66:7","type":"","value":"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"6009:2:7","type":""}]},{"expression":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"6105:4:7"},{"kind":"number","nodeType":"YulLiteral","src":"6111:1:7","type":"","value":"4"},{"arguments":[{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"6118:14:7"},"nodeType":"YulFunctionCall","src":"6118:16:7"},{"name":"_1","nodeType":"YulIdentifier","src":"6136:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6114:3:7"},"nodeType":"YulFunctionCall","src":"6114:25:7"}],"functionName":{"name":"returndatacopy","nodeType":"YulIdentifier","src":"6090:14:7"},"nodeType":"YulFunctionCall","src":"6090:50:7"},"nodeType":"YulExpressionStatement","src":"6090:50:7"},{"nodeType":"YulVariableDeclaration","src":"6149:25:7","value":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"6169:4:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"6163:5:7"},"nodeType":"YulFunctionCall","src":"6163:11:7"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"6153:6:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"6183:26:7","value":{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"6193:14:7"},"nodeType":"YulFunctionCall","src":"6193:16:7"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"6187:2:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"6218:28:7","value":{"kind":"number","nodeType":"YulLiteral","src":"6228:18:7","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"6222:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"6304:9:7","statements":[{"nodeType":"YulLeave","src":"6306:5:7"}]},"condition":{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"6264:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"6272:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"6261:2:7"},"nodeType":"YulFunctionCall","src":"6261:14:7"},{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"6284:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"6292:4:7","type":"","value":"0x24"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6280:3:7"},"nodeType":"YulFunctionCall","src":"6280:17:7"},{"name":"_2","nodeType":"YulIdentifier","src":"6299:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"6277:2:7"},"nodeType":"YulFunctionCall","src":"6277:25:7"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"6258:2:7"},"nodeType":"YulFunctionCall","src":"6258:45:7"},"nodeType":"YulIf","src":"6255:58:7"},{"nodeType":"YulVariableDeclaration","src":"6322:28:7","value":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"6337:4:7"},{"name":"offset","nodeType":"YulIdentifier","src":"6343:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6333:3:7"},"nodeType":"YulFunctionCall","src":"6333:17:7"},"variables":[{"name":"msg","nodeType":"YulTypedName","src":"6326:3:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"6359:24:7","value":{"arguments":[{"name":"msg","nodeType":"YulIdentifier","src":"6379:3:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"6373:5:7"},"nodeType":"YulFunctionCall","src":"6373:10:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"6363:6:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"6410:9:7","statements":[{"nodeType":"YulLeave","src":"6412:5:7"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"6398:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"6406:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"6395:2:7"},"nodeType":"YulFunctionCall","src":"6395:14:7"},"nodeType":"YulIf","src":"6392:27:7"},{"body":{"nodeType":"YulBlock","src":"6501:9:7","statements":[{"nodeType":"YulLeave","src":"6503:5:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"msg","nodeType":"YulIdentifier","src":"6442:3:7"},{"name":"length","nodeType":"YulIdentifier","src":"6447:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6438:3:7"},"nodeType":"YulFunctionCall","src":"6438:16:7"},{"kind":"number","nodeType":"YulLiteral","src":"6456:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6434:3:7"},"nodeType":"YulFunctionCall","src":"6434:27:7"},{"arguments":[{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"6471:4:7"},{"arguments":[],"functionName":{"name":"returndatasize","nodeType":"YulIdentifier","src":"6477:14:7"},"nodeType":"YulFunctionCall","src":"6477:16:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6467:3:7"},"nodeType":"YulFunctionCall","src":"6467:27:7"},{"name":"_1","nodeType":"YulIdentifier","src":"6496:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6463:3:7"},"nodeType":"YulFunctionCall","src":"6463:36:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"6431:2:7"},"nodeType":"YulFunctionCall","src":"6431:69:7"},"nodeType":"YulIf","src":"6428:82:7"},{"expression":{"arguments":[{"name":"data","nodeType":"YulIdentifier","src":"6539:4:7"},{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"6553:6:7"},{"name":"length","nodeType":"YulIdentifier","src":"6561:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6549:3:7"},"nodeType":"YulFunctionCall","src":"6549:19:7"},{"kind":"number","nodeType":"YulLiteral","src":"6570:4:7","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"6545:3:7"},"nodeType":"YulFunctionCall","src":"6545:30:7"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"6519:19:7"},"nodeType":"YulFunctionCall","src":"6519:57:7"},"nodeType":"YulExpressionStatement","src":"6519:57:7"},{"nodeType":"YulAssignment","src":"6585:10:7","value":{"name":"msg","nodeType":"YulIdentifier","src":"6592:3:7"},"variableNames":[{"name":"ret","nodeType":"YulIdentifier","src":"6585:3:7"}]}]},"name":"try_decode_error_message","nodeType":"YulFunctionDefinition","returnVariables":[{"name":"ret","nodeType":"YulTypedName","src":"5909:3:7","type":""}],"src":"5870:731:7"}]},"contents":"{\n { }\n function abi_decode_tuple_t_string_memory_ptr(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n let offset := calldataload(headStart)\n if gt(offset, 0xffffffffffffffff) { revert(0, 0) }\n let _1 := add(headStart, offset)\n if iszero(slt(add(_1, 0x1f), dataEnd)) { revert(0, 0) }\n let _2 := calldataload(_1)\n let _3 := array_allocation_size_string(_2)\n let memPtr := mload(64)\n finalize_allocation(memPtr, _3)\n mstore(memPtr, _2)\n if gt(add(add(_1, _2), 32), dataEnd) { revert(0, 0) }\n calldatacopy(add(memPtr, 32), add(_1, 32), _2)\n mstore(add(add(memPtr, _2), 32), 0)\n value0 := memPtr\n }\n function abi_decode_tuple_t_string_memory_ptr_fromMemory(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n let offset := mload(headStart)\n if gt(offset, 0xffffffffffffffff) { revert(0, 0) }\n let _1 := add(headStart, offset)\n if iszero(slt(add(_1, 0x1f), dataEnd)) { revert(0, 0) }\n let _2 := mload(_1)\n let _3 := array_allocation_size_string(_2)\n let memPtr := mload(64)\n finalize_allocation(memPtr, _3)\n mstore(memPtr, _2)\n if gt(add(add(_1, _2), 32), dataEnd) { revert(0, 0) }\n copy_memory_to_memory(add(_1, 32), add(memPtr, 32), _2)\n value0 := memPtr\n }\n function abi_encode_string(value, pos) -> end\n {\n let length := mload(value)\n mstore(pos, length)\n copy_memory_to_memory(add(value, 0x20), add(pos, 0x20), length)\n end := add(add(pos, and(add(length, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)), 0x20)\n }\n function abi_encode_tuple_packed_t_string_memory_ptr__to_t_string_memory_ptr__nonPadded_inplace_fromStack_reversed(pos, value0) -> end\n {\n let length := mload(value0)\n copy_memory_to_memory(add(value0, 0x20), pos, length)\n end := add(pos, length)\n }\n function abi_encode_tuple_t_address__to_t_address__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, and(value0, 0xffffffffffffffffffffffffffffffffffffffff))\n }\n function abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, iszero(iszero(value0)))\n }\n function abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed(headStart, value0) -> tail\n {\n mstore(headStart, 32)\n tail := abi_encode_string(value0, add(headStart, 32))\n }\n function abi_encode_tuple_t_stringliteral_58e3ca0e65e73c038df3db6a7cab1bf7de300d13038b802ce0f4435889c48e5e__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 36)\n mstore(add(headStart, 64), \"Error: a == b not satisfied [str\")\n mstore(add(headStart, 96), \"ing]\")\n tail := add(headStart, 128)\n }\n function abi_encode_tuple_t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 2)\n mstore(add(headStart, 64), \"gm\")\n tail := add(headStart, 96)\n }\n function abi_encode_tuple_t_stringliteral_7624778dedc75f8b322b9fa1632a610d40b85e106c7d9bf0e743a9ce291b9c6f__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 2)\n mstore(add(headStart, 64), \"hi\")\n tail := add(headStart, 96)\n }\n function abi_encode_tuple_t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed(headStart, value0) -> tail\n {\n mstore(headStart, 64)\n mstore(add(headStart, 64), 9)\n mstore(add(headStart, 96), \" Value a\")\n mstore(add(headStart, 0x20), 128)\n tail := abi_encode_string(value0, add(headStart, 128))\n }\n function abi_encode_tuple_t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3_t_string_memory_ptr__to_t_string_memory_ptr_t_string_memory_ptr__fromStack_reversed(headStart, value0) -> tail\n {\n mstore(headStart, 64)\n mstore(add(headStart, 64), 9)\n mstore(add(headStart, 96), \" Value b\")\n mstore(add(headStart, 0x20), 128)\n tail := abi_encode_string(value0, add(headStart, 128))\n }\n function array_allocation_size_string(length) -> size\n {\n if gt(length, 0xffffffffffffffff) { panic_error_0x41() }\n size := add(and(add(length, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0), 0x20)\n }\n function copy_memory_to_memory(src, dst, length)\n {\n let i := 0\n for { } lt(i, length) { i := add(i, 32) }\n {\n mstore(add(dst, i), mload(add(src, i)))\n }\n if gt(i, length) { mstore(add(dst, length), 0) }\n }\n function finalize_allocation(memPtr, size)\n {\n let newFreePtr := add(memPtr, and(add(size, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0))\n if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }\n mstore(64, newFreePtr)\n }\n function panic_error_0x41()\n {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x41)\n revert(0, 0x24)\n }\n function return_data_selector() -> sig\n {\n if gt(returndatasize(), 3)\n {\n returndatacopy(0, 0, 4)\n sig := shr(224, mload(0))\n }\n }\n function try_decode_error_message() -> ret\n {\n if lt(returndatasize(), 0x44) { leave }\n let data := mload(64)\n let _1 := 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc\n returndatacopy(data, 4, add(returndatasize(), _1))\n let offset := mload(data)\n let _2 := returndatasize()\n let _3 := 0xffffffffffffffff\n if or(gt(offset, _3), gt(add(offset, 0x24), _2)) { leave }\n let msg := add(data, offset)\n let length := mload(msg)\n if gt(length, _3) { leave }\n if gt(add(add(msg, length), 0x20), add(add(data, returndatasize()), _1)) { leave }\n finalize_allocation(data, add(add(offset, length), 0x20))\n ret := msg\n }\n}","id":7,"language":"Yul","name":"#utility.yul"}],"immutableReferences":{},"linkReferences":{},"object":"608060405234801561001057600080fd5b50600436106100725760003560e01c8063ba414fa611610050578063ba414fa61461009c578063e0747015146100c2578063fa7626d4146100ca57600080fd5b80630a9254e4146100775780635306d34d146100815780636721f71814610089575b600080fd5b61007f6100d7565b005b61007f6102ea565b61007f6100973660046108de565b610441565b6000546100ae90610100900460ff1681565b604051901515815260200160405180910390f35b61007f610594565b6000546100ae9060ff1681565b6040516100e3906108c4565b604051809103906000f0801580156100ff573d6000803e3d6000fd5b50600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff9384168102919091179182905560405191049091169061015e906108d1565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f080158015610197573d6000803e3d6000fd5b50600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92831617905560005460405162010000909104909116906101f3906108d1565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f08015801561022c573d6000803e3d6000fd5b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283161790556000546001546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081529083166004820152620100009091049091169063f2fde38b90602401600060405180830381600087803b1580156102d057600080fd5b505af11580156102e4573d6000803e3d6000fd5b50505050565b6001546040517fead710c400000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f676d000000000000000000000000000000000000000000000000000000000000604482015273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c490606401600060405180830381600087803b15801561038357600080fd5b505af1925050508015610394575060015b61040e576103a0610be0565b806308c379a0141561040257506103b5610bfc565b806103c05750610404565b6103ff816040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d000000000000000000000000815250610741565b50565b505b3d6000803e3d6000fd5b61043f600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b565b6001546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c490610497908490600401610a4c565b600060405180830381600087803b1580156104b157600080fd5b505af11580156104c5573d6000803e3d6000fd5b505050506103ff600060029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ef690cc06040518163ffffffff1660e01b815260040160006040518083038186803b15801561053457600080fd5b505afa158015610548573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261058e9190810190610964565b82610741565b6001546040517fead710c400000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f6869000000000000000000000000000000000000000000000000000000000000604482015273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c490606401600060405180830381600087803b15801561062d57600080fd5b505af1158015610641573d6000803e3d6000fd5b5050505061043f600060029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ef690cc06040518163ffffffff1660e01b815260040160006040518083038186803b1580156106b057600080fd5b505afa1580156106c4573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261070a9190810190610964565b6040518060400160405280600281526020017f68690000000000000000000000000000000000000000000000000000000000008152505b806040516020016107529190610a30565b60405160208183030381529060405280519060200120826040516020016107799190610a30565b60405160208183030381529060405280519060200120146108c0577f41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f506040516108199060208082526024908201527f4572726f723a2061203d3d2062206e6f7420736174697366696564205b73747260408201527f696e675d00000000000000000000000000000000000000000000000000000000606082015260800190565b60405180910390a17f280f4446b28a1372417dda658d30b95b2992b12ac9c7f378535f29a97acf3583826040516108509190610a66565b60405180910390a17f280f4446b28a1372417dda658d30b95b2992b12ac9c7f378535f29a97acf3583816040516108879190610aad565b60405180910390a16108c0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b5050565b61097c80610ca583390190565b61039e8061162183390190565b6000602082840312156108f057600080fd5b813567ffffffffffffffff81111561090757600080fd5b8201601f8101841361091857600080fd5b803561092381610af4565b6040516109308282610b66565b82815286602084860101111561094557600080fd5b8260208501602083013760009281016020019290925250949350505050565b60006020828403121561097657600080fd5b815167ffffffffffffffff81111561098d57600080fd5b8201601f8101841361099e57600080fd5b80516109a981610af4565b6040516109b68282610b66565b8281528660208486010111156109cb57600080fd5b6109dc836020830160208701610b3a565b9695505050505050565b600081518084526109fe816020860160208601610b3a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008251610a42818460208701610b3a565b9190910192915050565b602081526000610a5f60208301846109e6565b9392505050565b60408152600960408201527f202056616c7565206100000000000000000000000000000000000000000000006060820152608060208201526000610a5f60808301846109e6565b60408152600960408201527f202056616c7565206200000000000000000000000000000000000000000000006060820152608060208201526000610a5f60808301846109e6565b600067ffffffffffffffff821115610b0e57610b0e610bb1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015610b55578181015183820152602001610b3d565b838111156102e45750506000910152565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715610baa57610baa610bb1565b6040525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d1115610bf95760046000803e5060005160e01c5b90565b600060443d1015610c0a5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610c5857505050505090565b8285019150815181811115610c705750505050505090565b843d8701016020828501011115610c8a5750505050505090565b610c9960208286010187610b66565b50909594505050505056fe608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6108fe8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ead710c411610050578063ead710c4146100b6578063ef690cc0146100c9578063f2fde38b146100de57600080fd5b8063715018a6146100775780638da5cb5b14610081578063c0129d43146100ae575b600080fd5b61007f6100f1565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007f610183565b61007f6100c436600461067d565b6102ab565b6100d161037b565b6040516100a59190610768565b61007f6100ec366004610640565b610409565b60005473ffffffffffffffffffffffffffffffffffffffff163314610177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6101816000610532565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b61020f600a4361083d565b6000146040518060600160405280602181526020016108a86021913990610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b506040805180820190915260028082527f676d00000000000000000000000000000000000000000000000000000000000060209092019182526102a8916001916105a7565b50565b7f71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270816040516020016102dd919061074c565b6040516020818303038152906040528051906020012014156040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d00000000000000000000000081525090610363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b5080516103779060019060208401906105a7565b5050565b60018054610388906107e9565b80601f01602080910402602001604051908101604052809291908181526020018280546103b4906107e9565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff16331461048a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b73ffffffffffffffffffffffffffffffffffffffff811661052d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161016e565b6102a8815b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546105b3906107e9565b90600052602060002090601f0160209004810192826105d5576000855561061b565b82601f106105ee57805160ff191683800117855561061b565b8280016001018555821561061b579182015b8281111561061b578251825591602001919060010190610600565b5061062792915061062b565b5090565b5b80821115610627576000815560010161062c565b60006020828403121561065257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461067657600080fd5b9392505050565b60006020828403121561068f57600080fd5b813567ffffffffffffffff808211156106a757600080fd5b818401915084601f8301126106bb57600080fd5b8135818111156106cd576106cd610878565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071357610713610878565b8160405282815287602084870101111561072c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825161075e8184602087016107b9565b9190910192915050565b60208152600082518060208401526107878160408501602087016107b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b838110156107d45781810151838201526020016107bc565b838111156107e3576000848401525b50505050565b600181811c908216806107fd57607f821691505b60208210811415610837577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082610873577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a264697066735822122005045f3a3e5209d1d8290892555e955496efc239f089d2b9b89ba31daba73e9564736f6c63430008070033608060405234801561001057600080fd5b5060405161039e38038061039e83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61030b806100936000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c0129d431461003b578063ead710c414610045575b600080fd5b610043610058565b005b610043610053366004610164565b6100d9565b60008054604080517fc0129d43000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169263c0129d439260048084019382900301818387803b1580156100bf57600080fd5b505af11580156100d3573d6000803e3d6000fd5b50505050565b6000546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c49061012f908490600401610233565b600060405180830381600087803b15801561014957600080fd5b505af115801561015d573d6000803e3d6000fd5b5050505050565b60006020828403121561017657600080fd5b813567ffffffffffffffff8082111561018e57600080fd5b818401915084601f8301126101a257600080fd5b8135818111156101b4576101b46102a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101fa576101fa6102a6565b8160405282815287602084870101111561021357600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561026057858101830151858201604001528201610244565b81811115610272576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220bfa72ed9ea0d57905e92811e328260534806dbdb8ad58675306b2582254f247564736f6c63430008070033a2646970667358221220ad80bd62f261460562ca174ee1c98c204fef7777d1d6f8bacae87697631df73c64736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xBA414FA6 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xBA414FA6 EQ PUSH2 0x9C JUMPI DUP1 PUSH4 0xE0747015 EQ PUSH2 0xC2 JUMPI DUP1 PUSH4 0xFA7626D4 EQ PUSH2 0xCA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0xA9254E4 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x5306D34D EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0x6721F718 EQ PUSH2 0x89 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xD7 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x7F PUSH2 0x2EA JUMP JUMPDEST PUSH2 0x7F PUSH2 0x97 CALLDATASIZE PUSH1 0x4 PUSH2 0x8DE JUMP JUMPDEST PUSH2 0x441 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0xAE SWAP1 PUSH2 0x100 SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x594 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0xAE SWAP1 PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xE3 SWAP1 PUSH2 0x8C4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0xFF JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000FFFF AND PUSH3 0x10000 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP4 DUP5 AND DUP2 MUL SWAP2 SWAP1 SWAP2 OR SWAP2 DUP3 SWAP1 SSTORE PUSH1 0x40 MLOAD SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x15E SWAP1 PUSH2 0x8D1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x197 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x1 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x1F3 SWAP1 PUSH2 0x8D1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x22C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x2 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xF2FDE38B00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 DUP4 AND PUSH1 0x4 DUP3 ADD MSTORE PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH4 0xF2FDE38B SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2D0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x2E4 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x2 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH1 0x64 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x383 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL SWAP3 POP POP POP DUP1 ISZERO PUSH2 0x394 JUMPI POP PUSH1 0x1 JUMPDEST PUSH2 0x40E JUMPI PUSH2 0x3A0 PUSH2 0xBE0 JUMP JUMPDEST DUP1 PUSH4 0x8C379A0 EQ ISZERO PUSH2 0x402 JUMPI POP PUSH2 0x3B5 PUSH2 0xBFC JUMP JUMPDEST DUP1 PUSH2 0x3C0 JUMPI POP PUSH2 0x404 JUMP JUMPDEST PUSH2 0x3FF DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP PUSH2 0x741 JUMP JUMPDEST POP JUMP JUMPDEST POP JUMPDEST RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST PUSH2 0x43F PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF AND PUSH2 0x100 OR SWAP1 SSTORE JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x497 SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0xA4C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x4B1 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x4C5 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH2 0x3FF PUSH1 0x0 PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xEF690CC0 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x534 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x548 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x0 DUP3 RETURNDATACOPY PUSH1 0x1F RETURNDATASIZE SWAP1 DUP2 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND DUP3 ADD PUSH1 0x40 MSTORE PUSH2 0x58E SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x964 JUMP JUMPDEST DUP3 PUSH2 0x741 JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x2 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x6869000000000000000000000000000000000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH1 0x64 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x62D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x641 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH2 0x43F PUSH1 0x0 PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0xEF690CC0 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x6B0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x6C4 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x0 DUP3 RETURNDATACOPY PUSH1 0x1F RETURNDATASIZE SWAP1 DUP2 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND DUP3 ADD PUSH1 0x40 MSTORE PUSH2 0x70A SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x964 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x2 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x6869000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP JUMPDEST DUP1 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x752 SWAP2 SWAP1 PUSH2 0xA30 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP3 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x779 SWAP2 SWAP1 PUSH2 0xA30 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ PUSH2 0x8C0 JUMPI PUSH32 0x41304FACD9323D75B11BCDD609CB38EFFFFDB05710F7CAF0E9B16C6D9D709F50 PUSH1 0x40 MLOAD PUSH2 0x819 SWAP1 PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x24 SWAP1 DUP3 ADD MSTORE PUSH32 0x4572726F723A2061203D3D2062206E6F7420736174697366696564205B737472 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x696E675D00000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH32 0x280F4446B28A1372417DDA658D30B95B2992B12AC9C7F378535F29A97ACF3583 DUP3 PUSH1 0x40 MLOAD PUSH2 0x850 SWAP2 SWAP1 PUSH2 0xA66 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH32 0x280F4446B28A1372417DDA658D30B95B2992B12AC9C7F378535F29A97ACF3583 DUP2 PUSH1 0x40 MLOAD PUSH2 0x887 SWAP2 SWAP1 PUSH2 0xAAD JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG1 PUSH2 0x8C0 PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF AND PUSH2 0x100 OR SWAP1 SSTORE JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH2 0x97C DUP1 PUSH2 0xCA5 DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH2 0x39E DUP1 PUSH2 0x1621 DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x8F0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x907 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 ADD PUSH1 0x1F DUP2 ADD DUP5 SGT PUSH2 0x918 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 CALLDATALOAD PUSH2 0x923 DUP2 PUSH2 0xAF4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x930 DUP3 DUP3 PUSH2 0xB66 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP7 PUSH1 0x20 DUP5 DUP7 ADD ADD GT ISZERO PUSH2 0x945 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP6 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x976 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x98D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 ADD PUSH1 0x1F DUP2 ADD DUP5 SGT PUSH2 0x99E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 MLOAD PUSH2 0x9A9 DUP2 PUSH2 0xAF4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x9B6 DUP3 DUP3 PUSH2 0xB66 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP7 PUSH1 0x20 DUP5 DUP7 ADD ADD GT ISZERO PUSH2 0x9CB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x9DC DUP4 PUSH1 0x20 DUP4 ADD PUSH1 0x20 DUP8 ADD PUSH2 0xB3A JUMP JUMPDEST SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x9FE DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0xB3A JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0xA42 DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0xB3A JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 PUSH2 0xA5F PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0x9E6 JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP2 MSTORE PUSH1 0x9 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x202056616C756520610000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x0 PUSH2 0xA5F PUSH1 0x80 DUP4 ADD DUP5 PUSH2 0x9E6 JUMP JUMPDEST PUSH1 0x40 DUP2 MSTORE PUSH1 0x9 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x202056616C756520620000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x0 PUSH2 0xA5F PUSH1 0x80 DUP4 ADD DUP5 PUSH2 0x9E6 JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0xB0E JUMPI PUSH2 0xB0E PUSH2 0xBB1 JUMP JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xB55 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xB3D JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x2E4 JUMPI POP POP PUSH1 0x0 SWAP2 ADD MSTORE JUMP JUMPDEST PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP4 ADD AND DUP2 ADD DUP2 DUP2 LT PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT OR ISZERO PUSH2 0xBAA JUMPI PUSH2 0xBAA PUSH2 0xBB1 JUMP JUMPDEST PUSH1 0x40 MSTORE POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST PUSH1 0x0 PUSH1 0x3 RETURNDATASIZE GT ISZERO PUSH2 0xBF9 JUMPI PUSH1 0x4 PUSH1 0x0 DUP1 RETURNDATACOPY POP PUSH1 0x0 MLOAD PUSH1 0xE0 SHR JUMPDEST SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x44 RETURNDATASIZE LT ISZERO PUSH2 0xC0A JUMPI SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC DUP1 RETURNDATASIZE ADD PUSH1 0x4 DUP4 RETURNDATACOPY DUP2 MLOAD RETURNDATASIZE PUSH8 0xFFFFFFFFFFFFFFFF DUP2 PUSH1 0x24 DUP5 ADD GT DUP2 DUP5 GT OR ISZERO PUSH2 0xC58 JUMPI POP POP POP POP POP SWAP1 JUMP JUMPDEST DUP3 DUP6 ADD SWAP2 POP DUP2 MLOAD DUP2 DUP2 GT ISZERO PUSH2 0xC70 JUMPI POP POP POP POP POP POP SWAP1 JUMP JUMPDEST DUP5 RETURNDATASIZE DUP8 ADD ADD PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0xC8A JUMPI POP POP POP POP POP POP SWAP1 JUMP JUMPDEST PUSH2 0xC99 PUSH1 0x20 DUP3 DUP7 ADD ADD DUP8 PUSH2 0xB66 JUMP JUMPDEST POP SWAP1 SWAP6 SWAP5 POP POP POP POP POP JUMP INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1A CALLER PUSH2 0x1F JUMP JUMPDEST PUSH2 0x6F JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 DUP2 AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH2 0x8FE DUP1 PUSH2 0x7E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xEAD710C4 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0xEF690CC0 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0xDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0x715018A6 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0xC0129D43 EQ PUSH2 0xAE JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xF1 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x183 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x67D JUMP JUMPDEST PUSH2 0x2AB JUMP JUMPDEST PUSH2 0xD1 PUSH2 0x37B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xA5 SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xEC CALLDATASIZE PUSH1 0x4 PUSH2 0x640 JUMP JUMPDEST PUSH2 0x409 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x177 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x181 PUSH1 0x0 PUSH2 0x532 JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x204 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x20F PUSH1 0xA NUMBER PUSH2 0x83D JUMP JUMPDEST PUSH1 0x0 EQ PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x8A8 PUSH1 0x21 SWAP2 CODECOPY SWAP1 PUSH2 0x263 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x2 DUP1 DUP3 MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 SWAP1 SWAP3 ADD SWAP2 DUP3 MSTORE PUSH2 0x2A8 SWAP2 PUSH1 0x1 SWAP2 PUSH2 0x5A7 JUMP JUMPDEST POP JUMP JUMPDEST PUSH32 0x71B78290913AF2ADDD8FCBE5766DE306AF2C8AFBC466CA891E207F73638C7270 DUP2 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2DD SWAP2 SWAP1 PUSH2 0x74C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ ISZERO PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP SWAP1 PUSH2 0x363 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP DUP1 MLOAD PUSH2 0x377 SWAP1 PUSH1 0x1 SWAP1 PUSH1 0x20 DUP5 ADD SWAP1 PUSH2 0x5A7 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH2 0x388 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x3B4 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x401 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x3D6 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x401 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x3E4 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x48A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND PUSH2 0x52D JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x26 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A206E6577206F776E657220697320746865207A65726F2061 PUSH1 0x44 DUP3 ADD MSTORE PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000 PUSH1 0x64 DUP3 ADD MSTORE PUSH1 0x84 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x2A8 DUP2 JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x5B3 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x5D5 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0x5EE JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH2 0x61B JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x61B JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x600 JUMP JUMPDEST POP PUSH2 0x627 SWAP3 SWAP2 POP PUSH2 0x62B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x627 JUMPI PUSH1 0x0 DUP2 SSTORE PUSH1 0x1 ADD PUSH2 0x62C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x652 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x676 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x68F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x6A7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x6CD JUMPI PUSH2 0x6CD PUSH2 0x878 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x713 JUMPI PUSH2 0x713 PUSH2 0x878 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x72C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x75E DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 DUP3 MLOAD DUP1 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x787 DUP2 PUSH1 0x40 DUP6 ADD PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP2 SWAP1 SWAP2 ADD PUSH1 0x40 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x7D4 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x7BC JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x7E3 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SHR SWAP1 DUP3 AND DUP1 PUSH2 0x7FD JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 EQ ISZERO PUSH2 0x837 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH2 0x873 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x12 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP MOD SWAP1 JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID PUSH10 0x6E76616C696420626C6F PUSH4 0x6B206E75 PUSH14 0x6265722C20706C65617365207761 PUSH10 0x74A26469706673582212 KECCAK256 SDIV DIV 0x5F GASPRICE RETURNDATACOPY MSTORE MULMOD 0xD1 0xD8 0x29 ADDMOD SWAP3 SSTORE 0x5E SWAP6 SLOAD SWAP7 0xEF 0xC2 CODECOPY CREATE DUP10 0xD2 0xB9 0xB8 SWAP12 LOG3 SAR 0xAB 0xA7 RETURNDATACOPY SWAP6 PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x39E CODESIZE SUB DUP1 PUSH2 0x39E DUP4 CODECOPY DUP2 ADD PUSH1 0x40 DUP2 SWAP1 MSTORE PUSH2 0x2F SWAP2 PUSH2 0x54 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x84 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x66 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH2 0x7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH2 0x30B DUP1 PUSH2 0x93 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC0129D43 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x58 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x43 PUSH2 0x53 CALLDATASIZE PUSH1 0x4 PUSH2 0x164 JUMP JUMPDEST PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0xC0129D4300000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP3 PUSH4 0xC0129D43 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xD3 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x12F SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0x233 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x149 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x15D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x176 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x18E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x1A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1B4 JUMPI PUSH2 0x1B4 PUSH2 0x2A6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x1FA JUMPI PUSH2 0x1FA PUSH2 0x2A6 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x213 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 MSTORE DUP4 MLOAD DUP1 DUP3 DUP6 ADD MSTORE PUSH1 0x0 JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x260 JUMPI DUP6 DUP2 ADD DUP4 ADD MLOAD DUP6 DUP3 ADD PUSH1 0x40 ADD MSTORE DUP3 ADD PUSH2 0x244 JUMP JUMPDEST DUP2 DUP2 GT ISZERO PUSH2 0x272 JUMPI PUSH1 0x0 PUSH1 0x40 DUP4 DUP8 ADD ADD MSTORE JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x40 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xBF 0xA7 0x2E 0xD9 0xEA 0xD JUMPI SWAP1 0x5E SWAP3 DUP2 0x1E ORIGIN DUP3 PUSH1 0x53 BASEFEE MOD 0xDB 0xDB DUP11 0xD5 DUP7 PUSH22 0x306B2582254F247564736F6C63430008070033A26469 PUSH17 0x667358221220AD80BD62F261460562CA17 0x4E 0xE1 0xC9 DUP13 KECCAK256 0x4F 0xEF PUSH24 0x77D1D6F8BACAE87697631DF73C64736F6C63430008070033 ","sourceMap":"139:488:4:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;619:209:5;;;:::i;:::-;;175:171:4;;;:::i;473:151::-;;;;;;:::i;:::-;;:::i;1605:18:0:-;;;;;;;;;;;;;;;2443:14:7;;2436:22;2418:41;;2406:2;2391:18;1605::0;;;;;;;352:115:4;;;:::i;1573:26:0:-;;;;;;;;;619:209:5;671:13;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;661:7:5;:23;;;;;;;;;;;;;;;;;;;702:26;;719:7;;;;;;702:26;;;:::i;:::-;2223:42:7;2211:55;;;2193:74;;2181:2;2166:18;702:26:5;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;694:5:5;:34;;;;;;;;;;;-1:-1:-1;761:7:5;744:26;;761:7;;;;;;;;744:26;;;:::i;:::-;2223:42:7;2211:55;;;2193:74;;2181:2;2166:18;744:26:5;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;738:3:5;:32;;;;;;;;;;;-1:-1:-1;780:7:5;-1:-1:-1;814:5:5;780:41;;;;;814:5;;;780:41;;;2193:74:7;780:7:5;;;;;;;;:25;;2166:18:7;;780:41:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;619:209::o;175:171:4:-;220:5;;:17;;;;;3302:2:7;220:17:4;;;3284:21:7;3341:1;3321:18;;;3314:29;3379:4;3359:18;;;3352:32;220:5:4;;;;;:11;;3401:18:7;;220:17:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;216:124;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;297:32;306:5;313:15;;;;;;;;;;;;;;;;;297:8;:32::i;:::-;250:90;175:171::o;216:124::-;;;;;;;;;;;240:6;1853::0;:13;;;;;;;;1818:55;240:6:4;175:171::o;473:151::-;548:5;;:21;;;;;:5;;;;;:11;;:21;;560:8;;548:21;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;579:38;588:7;;;;;;;;;;;:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;608:8;579;:38::i;352:115::-;399:5;;:17;;;;;3632:2:7;399:17:4;;;3614:21:7;3671:1;3651:18;;;3644:29;3709:4;3689:18;;;3682:32;399:5:4;;;;;:11;;3731:18:7;;399:17:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;426:34;435:7;;;;;;;;;;;:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;426:34;;;;;;;;;;;;;;;;;13479:342:0;13615:1;13598:19;;;;;;;;:::i;:::-;;;;;;;;;;;;;13588:30;;;;;;13581:1;13564:19;;;;;;;;:::i;:::-;;;;;;;;;;;;;13554:30;;;;;;:64;13550:265;;13639:43;;;;;2897:2:7;2879:21;;;2936:2;2916:18;;;2909:30;2975:34;2970:2;2955:18;;2948:62;3046:6;3041:2;3026:18;;3019:34;3085:3;3070:19;;2695:400;13639:43:0;;;;;;;;13701:32;13731:1;13701:32;;;;;;:::i;:::-;;;;;;;;13752;13782:1;13752:32;;;;;;:::i;:::-;;;;;;;;13798:6;1853;:13;;;;;;;;1818:55;13798:6;13479:342;;:::o;-1:-1:-1:-;;;;;;;;:::o;:::-;;;;;;;;:::o;14:729:7:-;83:6;136:2;124:9;115:7;111:23;107:32;104:52;;;152:1;149;142:12;104:52;192:9;179:23;225:18;217:6;214:30;211:50;;;257:1;254;247:12;211:50;280:22;;333:4;325:13;;321:27;-1:-1:-1;311:55:7;;362:1;359;352:12;311:55;398:2;385:16;420:32;449:2;420:32;:::i;:::-;481:2;475:9;493:31;521:2;513:6;493:31;:::i;:::-;548:2;540:6;533:18;588:7;583:2;578;574;570:11;566:20;563:33;560:53;;;609:1;606;599:12;560:53;665:2;660;656;652:11;647:2;639:6;635:15;622:46;710:1;688:15;;;705:2;684:24;677:35;;;;-1:-1:-1;692:6:7;14:729;-1:-1:-1;;;;14:729:7:o;748:691::-;828:6;881:2;869:9;860:7;856:23;852:32;849:52;;;897:1;894;887:12;849:52;930:9;924:16;963:18;955:6;952:30;949:50;;;995:1;992;985:12;949:50;1018:22;;1071:4;1063:13;;1059:27;-1:-1:-1;1049:55:7;;1100:1;1097;1090:12;1049:55;1129:2;1123:9;1151:32;1180:2;1151:32;:::i;:::-;1212:2;1206:9;1224:31;1252:2;1244:6;1224:31;:::i;:::-;1279:2;1271:6;1264:18;1319:7;1314:2;1309;1305;1301:11;1297:20;1294:33;1291:53;;;1340:1;1337;1330:12;1291:53;1353:55;1405:2;1400;1392:6;1388:15;1383:2;1379;1375:11;1353:55;:::i;:::-;1427:6;748:691;-1:-1:-1;;;;;;748:691:7:o;1444:317::-;1486:3;1524:5;1518:12;1551:6;1546:3;1539:19;1567:63;1623:6;1616:4;1611:3;1607:14;1600:4;1593:5;1589:16;1567:63;:::i;:::-;1675:2;1663:15;1680:66;1659:88;1650:98;;;;1750:4;1646:109;;1444:317;-1:-1:-1;;1444:317:7:o;1766:276::-;1897:3;1935:6;1929:13;1951:53;1997:6;1992:3;1985:4;1977:6;1973:17;1951:53;:::i;:::-;2020:16;;;;;1766:276;-1:-1:-1;;1766:276:7:o;2470:220::-;2619:2;2608:9;2601:21;2582:4;2639:45;2680:2;2669:9;2665:18;2657:6;2639:45;:::i;:::-;2631:53;2470:220;-1:-1:-1;;;2470:220:7:o;3760:450::-;4010:2;3999:9;3992:21;4049:1;4044:2;4033:9;4029:18;4022:29;4087:11;4082:2;4071:9;4067:18;4060:39;4137:3;4130:4;4119:9;4115:20;4108:33;3973:4;4158:46;4199:3;4188:9;4184:19;4176:6;4158:46;:::i;4215:450::-;4465:2;4454:9;4447:21;4504:1;4499:2;4488:9;4484:18;4477:29;4542:11;4537:2;4526:9;4522:18;4515:39;4592:3;4585:4;4574:9;4570:20;4563:33;4428:4;4613:46;4654:3;4643:9;4639:19;4631:6;4613:46;:::i;4670:246::-;4719:4;4752:18;4744:6;4741:30;4738:56;;;4774:18;;:::i;:::-;-1:-1:-1;4831:2:7;4819:15;4836:66;4815:88;4905:4;4811:99;;4670:246::o;4921:258::-;4993:1;5003:113;5017:6;5014:1;5011:13;5003:113;;;5093:11;;;5087:18;5074:11;;;5067:39;5039:2;5032:10;5003:113;;;5134:6;5131:1;5128:13;5125:48;;;-1:-1:-1;;5169:1:7;5151:16;;5144:27;4921:258::o;5184:308::-;5290:66;5285:2;5279:4;5275:13;5271:86;5263:6;5259:99;5424:6;5412:10;5409:22;5388:18;5376:10;5373:34;5370:62;5367:88;;;5435:18;;:::i;:::-;5471:2;5464:22;-1:-1:-1;;5184:308:7:o;5497:184::-;5549:77;5546:1;5539:88;5646:4;5643:1;5636:15;5670:4;5667:1;5660:15;5686:179;5721:3;5763:1;5745:16;5742:23;5739:120;;;5809:1;5806;5803;5788:23;-1:-1:-1;5846:1:7;5840:8;5835:3;5831:18;5739:120;5686:179;:::o;5870:731::-;5909:3;5951:4;5933:16;5930:26;5927:39;;;5870:731;:::o;5927:39::-;5993:2;5987:9;6015:66;6136:2;6118:16;6114:25;6111:1;6105:4;6090:50;6169:4;6163:11;6193:16;6228:18;6299:2;6292:4;6284:6;6280:17;6277:25;6272:2;6264:6;6261:14;6258:45;6255:58;;;6306:5;;;;;5870:731;:::o;6255:58::-;6343:6;6337:4;6333:17;6322:28;;6379:3;6373:10;6406:2;6398:6;6395:14;6392:27;;;6412:5;;;;;;5870:731;:::o;6392:27::-;6496:2;6477:16;6471:4;6467:27;6463:36;6456:4;6447:6;6442:3;6438:16;6434:27;6431:69;6428:82;;;6503:5;;;;;;5870:731;:::o;6428:82::-;6519:57;6570:4;6561:6;6553;6549:19;6545:30;6539:4;6519:57;:::i;:::-;-1:-1:-1;6592:3:7;;5870:731;-1:-1:-1;;;;;5870:731:7:o"}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log_address\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"log_bytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"log_bytes32\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"name\":\"log_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"val\",\"type\":\"address\"}],\"name\":\"log_named_address\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"val\",\"type\":\"bytes\"}],\"name\":\"log_named_bytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"val\",\"type\":\"bytes32\"}],\"name\":\"log_named_bytes32\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"}],\"name\":\"log_named_decimal_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"}],\"name\":\"log_named_decimal_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"}],\"name\":\"log_named_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"val\",\"type\":\"string\"}],\"name\":\"log_named_string\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"log_named_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log_string\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"logs\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"IS_TEST\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"failed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"setUp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testCanSetGreeting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testCannotGm\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"greeting\",\"type\":\"string\"}],\"name\":\"testWorksForAllGreetings\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/test/Greeter.t.sol\":\"Greet\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/ds-test/src/test.sol\":{\"keccak256\":\"0x529f30c5939d75689f6a982f7f96b8898bed30bd90ec5b385b57cab681e12b00\",\"license\":\"GPL-3.0-or-later\",\"urls\":[\"bzz-raw://89075d5a96e87acef1d00cf556b409d1836728ec2e92f5629ceb5cae3d1e4354\",\"dweb:/ipfs/QmPAViJrxffEDns9GEMVSAzmr3soAzfrEg1CVuovwmNfnt\"]},\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x6bb804a310218875e89d12c053e94a13a4607cdf7cc2052f3e52bd32a0dc50a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2ebbbe6d0011175bd9e7268b83de3f9c2f9d8d4cbfbaef12aff977d7d727163\",\"dweb:/ipfs/Qmd5c7Vxtis9wzkDNhxwc6A2QT5H9xn9kfjhx7qx44vpro\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x90565a39ae45c80f0468dc96c7b20d0afc3055f344c8203a0c9258239f350b9f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e8b38a7ac8e7b4463af00cf7fff1bf48ae9875765bf4f7751e100124d0bc8c\",\"dweb:/ipfs/QmWcsmkVr24xmmjfnBQZoemFniXjj3vwT78Cz6uqZW1Hux\"]},\"src/Greeter.sol\":{\"keccak256\":\"0xc34bd8409a4fa4a474f29c6cb7d076cf9379c9c79e257c5cda7e5d114023f0f6\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://9db4f0c61754c54fd3b3ae58dfaf72865f8134e96959f7fc295b1a8e3b7511d7\",\"dweb:/ipfs/QmPuGbtNJ9rRaC7kFWqy76A9sfcGGcYAps6yPRrW28v4xd\"]},\"src/test/Greeter.t.sol\":{\"keccak256\":\"0xf7fe97110b31611de26973a826978b120cf08bb9263444bf52ea639f3f568c16\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://139a8edf691557963f5e6d3925f0f3fdf14c211974bbc399b81c5326f6c9f5ec\",\"dweb:/ipfs/QmVBNcpL91o99MkuDS9Qu5kHe68NPLyphtf3yJTYfCn1oC\"]},\"src/test/utils/GreeterTest.sol\":{\"keccak256\":\"0xc49253ed5e0fc9185d066993945370493f2bb08f00a997680b112fe6f9b5d455\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://d5ff89c2bb371b6ddfb66b905b3c3597aa080e1ca5c1c1303e529f2c8fc98a67\",\"dweb:/ipfs/Qmc28bfatf99DDv6P8dpdo5Zsw7QdSoC1N4FV1TJGZF5Vx\"]},\"src/test/utils/Hevm.sol\":{\"keccak256\":\"0xd477fc888e2bdbaf45c8babf175c93127478ae74543556ffebb9877a8dd823a9\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://7fb2a52878484cea3793a92ae34b3a9f3e77f976eda7c7f91e2edb5b9ba38be3\",\"dweb:/ipfs/Qmf7JsG4uMjd7WX1h8rBPcpXv1m4mF3sdrr6VYzKj1SXUX\"]}},\"version\":1}","storageLayout":{"storage":[{"astId":532,"contract":"src/test/Greeter.t.sol:Greet","label":"IS_TEST","offset":0,"slot":"0","type":"t_bool"},{"astId":534,"contract":"src/test/Greeter.t.sol:Greet","label":"failed","offset":1,"slot":"0","type":"t_bool"},{"astId":260,"contract":"src/test/Greeter.t.sol:Greet","label":"greeter","offset":2,"slot":"0","type":"t_contract(Greeter)60"},{"astId":263,"contract":"src/test/Greeter.t.sol:Greet","label":"alice","offset":0,"slot":"1","type":"t_contract(User)249"},{"astId":266,"contract":"src/test/Greeter.t.sol:Greet","label":"bob","offset":0,"slot":"2","type":"t_contract(User)249"}],"types":{"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_contract(Greeter)60":{"encoding":"inplace","label":"contract Greeter","numberOfBytes":"20"},"t_contract(User)249":{"encoding":"inplace","label":"contract User","numberOfBytes":"20"}}}}},"src/test/utils/GreeterTest.sol":{"GreeterTest":{"abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"}],"name":"log","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"log_address","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"}],"name":"log_bytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"","type":"bytes32"}],"name":"log_bytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"","type":"int256"}],"name":"log_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"address","name":"val","type":"address"}],"name":"log_named_address","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"bytes","name":"val","type":"bytes"}],"name":"log_named_bytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"bytes32","name":"val","type":"bytes32"}],"name":"log_named_bytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"int256","name":"val","type":"int256"},{"indexed":false,"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"log_named_decimal_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"uint256","name":"val","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"log_named_decimal_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"int256","name":"val","type":"int256"}],"name":"log_named_int","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"val","type":"string"}],"name":"log_named_string","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"uint256","name":"val","type":"uint256"}],"name":"log_named_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"}],"name":"log_string","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"log_uint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"}],"name":"logs","type":"event"},{"inputs":[],"name":"IS_TEST","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"failed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"setUp","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"60806040526000805460ff1916600117905534801561001d57600080fd5b506110008061002d6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80630a9254e414610046578063ba414fa614610050578063fa7626d414610076575b600080fd5b61004e610083565b005b60005461006290610100900460ff1681565b604051901515815260200160405180910390f35b6000546100629060ff1681565b60405161008f90610296565b604051809103906000f0801580156100ab573d6000803e3d6000fd5b50600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff9384168102919091179182905560405191049091169061010a906102a3565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f080158015610143573d6000803e3d6000fd5b50600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055600054604051620100009091049091169061019f906102a3565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f0801580156101d8573d6000803e3d6000fd5b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283161790556000546001546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081529083166004820152620100009091049091169063f2fde38b90602401600060405180830381600087803b15801561027c57600080fd5b505af1158015610290573d6000803e3d6000fd5b50505050565b61097c806102b183390190565b61039e80610c2d8339019056fe608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6108fe8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ead710c411610050578063ead710c4146100b6578063ef690cc0146100c9578063f2fde38b146100de57600080fd5b8063715018a6146100775780638da5cb5b14610081578063c0129d43146100ae575b600080fd5b61007f6100f1565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007f610183565b61007f6100c436600461067d565b6102ab565b6100d161037b565b6040516100a59190610768565b61007f6100ec366004610640565b610409565b60005473ffffffffffffffffffffffffffffffffffffffff163314610177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6101816000610532565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b61020f600a4361083d565b6000146040518060600160405280602181526020016108a86021913990610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b506040805180820190915260028082527f676d00000000000000000000000000000000000000000000000000000000000060209092019182526102a8916001916105a7565b50565b7f71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270816040516020016102dd919061074c565b6040516020818303038152906040528051906020012014156040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d00000000000000000000000081525090610363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b5080516103779060019060208401906105a7565b5050565b60018054610388906107e9565b80601f01602080910402602001604051908101604052809291908181526020018280546103b4906107e9565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff16331461048a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b73ffffffffffffffffffffffffffffffffffffffff811661052d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161016e565b6102a8815b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546105b3906107e9565b90600052602060002090601f0160209004810192826105d5576000855561061b565b82601f106105ee57805160ff191683800117855561061b565b8280016001018555821561061b579182015b8281111561061b578251825591602001919060010190610600565b5061062792915061062b565b5090565b5b80821115610627576000815560010161062c565b60006020828403121561065257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461067657600080fd5b9392505050565b60006020828403121561068f57600080fd5b813567ffffffffffffffff808211156106a757600080fd5b818401915084601f8301126106bb57600080fd5b8135818111156106cd576106cd610878565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071357610713610878565b8160405282815287602084870101111561072c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825161075e8184602087016107b9565b9190910192915050565b60208152600082518060208401526107878160408501602087016107b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b838110156107d45781810151838201526020016107bc565b838111156107e3576000848401525b50505050565b600181811c908216806107fd57607f821691505b60208210811415610837577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082610873577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a264697066735822122005045f3a3e5209d1d8290892555e955496efc239f089d2b9b89ba31daba73e9564736f6c63430008070033608060405234801561001057600080fd5b5060405161039e38038061039e83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61030b806100936000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c0129d431461003b578063ead710c414610045575b600080fd5b610043610058565b005b610043610053366004610164565b6100d9565b60008054604080517fc0129d43000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169263c0129d439260048084019382900301818387803b1580156100bf57600080fd5b505af11580156100d3573d6000803e3d6000fd5b50505050565b6000546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c49061012f908490600401610233565b600060405180830381600087803b15801561014957600080fd5b505af115801561015d573d6000803e3d6000fd5b5050505050565b60006020828403121561017657600080fd5b813567ffffffffffffffff8082111561018e57600080fd5b818401915084601f8301126101a257600080fd5b8135818111156101b4576101b46102a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101fa576101fa6102a6565b8160405282815287602084870101111561021357600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561026057858101830151858201604001528201610244565b81811115610272576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220bfa72ed9ea0d57905e92811e328260534806dbdb8ad58675306b2582254f247564736f6c63430008070033a2646970667358221220e06545f20edeee00d94d15f0094fdadbddebdb01441ea964df3d7e79cc86950964736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 SLOAD PUSH1 0xFF NOT AND PUSH1 0x1 OR SWAP1 SSTORE CALLVALUE DUP1 ISZERO PUSH2 0x1D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1000 DUP1 PUSH2 0x2D PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x41 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xA9254E4 EQ PUSH2 0x46 JUMPI DUP1 PUSH4 0xBA414FA6 EQ PUSH2 0x50 JUMPI DUP1 PUSH4 0xFA7626D4 EQ PUSH2 0x76 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x4E PUSH2 0x83 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0x62 SWAP1 PUSH2 0x100 SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 SLOAD PUSH2 0x62 SWAP1 PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x8F SWAP1 PUSH2 0x296 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0xAB JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000FFFF AND PUSH3 0x10000 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP4 DUP5 AND DUP2 MUL SWAP2 SWAP1 SWAP2 OR SWAP2 DUP3 SWAP1 SSTORE PUSH1 0x40 MLOAD SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x10A SWAP1 PUSH2 0x2A3 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x143 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x1 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x19F SWAP1 PUSH2 0x2A3 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x1D8 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x2 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xF2FDE38B00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 DUP4 AND PUSH1 0x4 DUP3 ADD MSTORE PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH4 0xF2FDE38B SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x27C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x290 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH2 0x97C DUP1 PUSH2 0x2B1 DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH2 0x39E DUP1 PUSH2 0xC2D DUP4 CODECOPY ADD SWAP1 JUMP INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1A CALLER PUSH2 0x1F JUMP JUMPDEST PUSH2 0x6F JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 DUP2 AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH2 0x8FE DUP1 PUSH2 0x7E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xEAD710C4 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0xEF690CC0 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0xDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0x715018A6 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0xC0129D43 EQ PUSH2 0xAE JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xF1 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x183 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x67D JUMP JUMPDEST PUSH2 0x2AB JUMP JUMPDEST PUSH2 0xD1 PUSH2 0x37B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xA5 SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xEC CALLDATASIZE PUSH1 0x4 PUSH2 0x640 JUMP JUMPDEST PUSH2 0x409 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x177 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x181 PUSH1 0x0 PUSH2 0x532 JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x204 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x20F PUSH1 0xA NUMBER PUSH2 0x83D JUMP JUMPDEST PUSH1 0x0 EQ PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x8A8 PUSH1 0x21 SWAP2 CODECOPY SWAP1 PUSH2 0x263 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x2 DUP1 DUP3 MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 SWAP1 SWAP3 ADD SWAP2 DUP3 MSTORE PUSH2 0x2A8 SWAP2 PUSH1 0x1 SWAP2 PUSH2 0x5A7 JUMP JUMPDEST POP JUMP JUMPDEST PUSH32 0x71B78290913AF2ADDD8FCBE5766DE306AF2C8AFBC466CA891E207F73638C7270 DUP2 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2DD SWAP2 SWAP1 PUSH2 0x74C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ ISZERO PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP SWAP1 PUSH2 0x363 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP DUP1 MLOAD PUSH2 0x377 SWAP1 PUSH1 0x1 SWAP1 PUSH1 0x20 DUP5 ADD SWAP1 PUSH2 0x5A7 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH2 0x388 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x3B4 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x401 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x3D6 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x401 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x3E4 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x48A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND PUSH2 0x52D JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x26 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A206E6577206F776E657220697320746865207A65726F2061 PUSH1 0x44 DUP3 ADD MSTORE PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000 PUSH1 0x64 DUP3 ADD MSTORE PUSH1 0x84 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x2A8 DUP2 JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x5B3 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x5D5 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0x5EE JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH2 0x61B JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x61B JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x600 JUMP JUMPDEST POP PUSH2 0x627 SWAP3 SWAP2 POP PUSH2 0x62B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x627 JUMPI PUSH1 0x0 DUP2 SSTORE PUSH1 0x1 ADD PUSH2 0x62C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x652 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x676 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x68F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x6A7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x6CD JUMPI PUSH2 0x6CD PUSH2 0x878 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x713 JUMPI PUSH2 0x713 PUSH2 0x878 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x72C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x75E DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 DUP3 MLOAD DUP1 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x787 DUP2 PUSH1 0x40 DUP6 ADD PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP2 SWAP1 SWAP2 ADD PUSH1 0x40 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x7D4 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x7BC JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x7E3 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SHR SWAP1 DUP3 AND DUP1 PUSH2 0x7FD JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 EQ ISZERO PUSH2 0x837 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH2 0x873 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x12 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP MOD SWAP1 JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID PUSH10 0x6E76616C696420626C6F PUSH4 0x6B206E75 PUSH14 0x6265722C20706C65617365207761 PUSH10 0x74A26469706673582212 KECCAK256 SDIV DIV 0x5F GASPRICE RETURNDATACOPY MSTORE MULMOD 0xD1 0xD8 0x29 ADDMOD SWAP3 SSTORE 0x5E SWAP6 SLOAD SWAP7 0xEF 0xC2 CODECOPY CREATE DUP10 0xD2 0xB9 0xB8 SWAP12 LOG3 SAR 0xAB 0xA7 RETURNDATACOPY SWAP6 PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x39E CODESIZE SUB DUP1 PUSH2 0x39E DUP4 CODECOPY DUP2 ADD PUSH1 0x40 DUP2 SWAP1 MSTORE PUSH2 0x2F SWAP2 PUSH2 0x54 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x84 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x66 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH2 0x7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH2 0x30B DUP1 PUSH2 0x93 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC0129D43 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x58 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x43 PUSH2 0x53 CALLDATASIZE PUSH1 0x4 PUSH2 0x164 JUMP JUMPDEST PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0xC0129D4300000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP3 PUSH4 0xC0129D43 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xD3 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x12F SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0x233 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x149 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x15D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x176 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x18E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x1A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1B4 JUMPI PUSH2 0x1B4 PUSH2 0x2A6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x1FA JUMPI PUSH2 0x1FA PUSH2 0x2A6 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x213 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 MSTORE DUP4 MLOAD DUP1 DUP3 DUP6 ADD MSTORE PUSH1 0x0 JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x260 JUMPI DUP6 DUP2 ADD DUP4 ADD MLOAD DUP6 DUP3 ADD PUSH1 0x40 ADD MSTORE DUP3 ADD PUSH2 0x244 JUMP JUMPDEST DUP2 DUP2 GT ISZERO PUSH2 0x272 JUMPI PUSH1 0x0 PUSH1 0x40 DUP4 DUP8 ADD ADD MSTORE JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x40 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xBF 0xA7 0x2E 0xD9 0xEA 0xD JUMPI SWAP1 0x5E SWAP3 DUP2 0x1E ORIGIN DUP3 PUSH1 0x53 BASEFEE MOD 0xDB 0xDB DUP11 0xD5 DUP7 PUSH22 0x306B2582254F247564736F6C63430008070033A26469 PUSH17 0x667358221220E06545F20EDEEE00D94D15 CREATE MULMOD 0x4F 0xDA 0xDB 0xDD 0xEB 0xDB ADD DIFFICULTY 0x1E 0xA9 PUSH5 0xDF3D7E79CC DUP7 SWAP6 MULMOD PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER ","sourceMap":"417:413:5:-:0;;;1573:26:0;;;-1:-1:-1;;1573:26:0;1595:4;1573:26;;;417:413:5;;;;;;;;;;;;;;;;"},"deployedBytecode":{"functionDebugData":{"@IS_TEST_532":{"entryPoint":null,"id":532,"parameterSlots":0,"returnSlots":0},"@failed_534":{"entryPoint":null,"id":534,"parameterSlots":0,"returnSlots":0},"@setUp_308":{"entryPoint":131,"id":308,"parameterSlots":0,"returnSlots":0},"abi_encode_tuple_t_address__to_t_address__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed":{"entryPoint":null,"id":null,"parameterSlots":2,"returnSlots":1}},"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:434:7","statements":[{"nodeType":"YulBlock","src":"6:3:7","statements":[]},{"body":{"nodeType":"YulBlock","src":"115:125:7","statements":[{"nodeType":"YulAssignment","src":"125:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"137:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"148:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"133:3:7"},"nodeType":"YulFunctionCall","src":"133:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"125:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"167:9:7"},{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"182:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"190:42:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffff"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"178:3:7"},"nodeType":"YulFunctionCall","src":"178:55:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"160:6:7"},"nodeType":"YulFunctionCall","src":"160:74:7"},"nodeType":"YulExpressionStatement","src":"160:74:7"}]},"name":"abi_encode_tuple_t_address__to_t_address__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"84:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"95:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"106:4:7","type":""}],"src":"14:226:7"},{"body":{"nodeType":"YulBlock","src":"340:92:7","statements":[{"nodeType":"YulAssignment","src":"350:26:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"362:9:7"},{"kind":"number","nodeType":"YulLiteral","src":"373:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"358:3:7"},"nodeType":"YulFunctionCall","src":"358:18:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"350:4:7"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"392:9:7"},{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"417:6:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"410:6:7"},"nodeType":"YulFunctionCall","src":"410:14:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"403:6:7"},"nodeType":"YulFunctionCall","src":"403:22:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"385:6:7"},"nodeType":"YulFunctionCall","src":"385:41:7"},"nodeType":"YulExpressionStatement","src":"385:41:7"}]},"name":"abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"309:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"320:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"331:4:7","type":""}],"src":"245:187:7"}]},"contents":"{\n { }\n function abi_encode_tuple_t_address__to_t_address__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, and(value0, 0xffffffffffffffffffffffffffffffffffffffff))\n }\n function abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, iszero(iszero(value0)))\n }\n}","id":7,"language":"Yul","name":"#utility.yul"}],"immutableReferences":{},"linkReferences":{},"object":"608060405234801561001057600080fd5b50600436106100415760003560e01c80630a9254e414610046578063ba414fa614610050578063fa7626d414610076575b600080fd5b61004e610083565b005b60005461006290610100900460ff1681565b604051901515815260200160405180910390f35b6000546100629060ff1681565b60405161008f90610296565b604051809103906000f0801580156100ab573d6000803e3d6000fd5b50600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff9384168102919091179182905560405191049091169061010a906102a3565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f080158015610143573d6000803e3d6000fd5b50600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055600054604051620100009091049091169061019f906102a3565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f0801580156101d8573d6000803e3d6000fd5b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283161790556000546001546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081529083166004820152620100009091049091169063f2fde38b90602401600060405180830381600087803b15801561027c57600080fd5b505af1158015610290573d6000803e3d6000fd5b50505050565b61097c806102b183390190565b61039e80610c2d8339019056fe608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6108fe8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ead710c411610050578063ead710c4146100b6578063ef690cc0146100c9578063f2fde38b146100de57600080fd5b8063715018a6146100775780638da5cb5b14610081578063c0129d43146100ae575b600080fd5b61007f6100f1565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007f610183565b61007f6100c436600461067d565b6102ab565b6100d161037b565b6040516100a59190610768565b61007f6100ec366004610640565b610409565b60005473ffffffffffffffffffffffffffffffffffffffff163314610177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6101816000610532565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b61020f600a4361083d565b6000146040518060600160405280602181526020016108a86021913990610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b506040805180820190915260028082527f676d00000000000000000000000000000000000000000000000000000000000060209092019182526102a8916001916105a7565b50565b7f71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270816040516020016102dd919061074c565b6040516020818303038152906040528051906020012014156040518060400160405280601481526020017f63616e6e6f74206772656574207769746820676d00000000000000000000000081525090610363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016e9190610768565b5080516103779060019060208401906105a7565b5050565b60018054610388906107e9565b80601f01602080910402602001604051908101604052809291908181526020018280546103b4906107e9565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff16331461048a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161016e565b73ffffffffffffffffffffffffffffffffffffffff811661052d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161016e565b6102a8815b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546105b3906107e9565b90600052602060002090601f0160209004810192826105d5576000855561061b565b82601f106105ee57805160ff191683800117855561061b565b8280016001018555821561061b579182015b8281111561061b578251825591602001919060010190610600565b5061062792915061062b565b5090565b5b80821115610627576000815560010161062c565b60006020828403121561065257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461067657600080fd5b9392505050565b60006020828403121561068f57600080fd5b813567ffffffffffffffff808211156106a757600080fd5b818401915084601f8301126106bb57600080fd5b8135818111156106cd576106cd610878565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071357610713610878565b8160405282815287602084870101111561072c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825161075e8184602087016107b9565b9190910192915050565b60208152600082518060208401526107878160408501602087016107b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b838110156107d45781810151838201526020016107bc565b838111156107e3576000848401525b50505050565b600181811c908216806107fd57607f821691505b60208210811415610837577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082610873577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974a264697066735822122005045f3a3e5209d1d8290892555e955496efc239f089d2b9b89ba31daba73e9564736f6c63430008070033608060405234801561001057600080fd5b5060405161039e38038061039e83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61030b806100936000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c0129d431461003b578063ead710c414610045575b600080fd5b610043610058565b005b610043610053366004610164565b6100d9565b60008054604080517fc0129d43000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169263c0129d439260048084019382900301818387803b1580156100bf57600080fd5b505af11580156100d3573d6000803e3d6000fd5b50505050565b6000546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c49061012f908490600401610233565b600060405180830381600087803b15801561014957600080fd5b505af115801561015d573d6000803e3d6000fd5b5050505050565b60006020828403121561017657600080fd5b813567ffffffffffffffff8082111561018e57600080fd5b818401915084601f8301126101a257600080fd5b8135818111156101b4576101b46102a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101fa576101fa6102a6565b8160405282815287602084870101111561021357600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561026057858101830151858201604001528201610244565b81811115610272576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220bfa72ed9ea0d57905e92811e328260534806dbdb8ad58675306b2582254f247564736f6c63430008070033a2646970667358221220e06545f20edeee00d94d15f0094fdadbddebdb01441ea964df3d7e79cc86950964736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x41 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xA9254E4 EQ PUSH2 0x46 JUMPI DUP1 PUSH4 0xBA414FA6 EQ PUSH2 0x50 JUMPI DUP1 PUSH4 0xFA7626D4 EQ PUSH2 0x76 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x4E PUSH2 0x83 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0x62 SWAP1 PUSH2 0x100 SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD SWAP1 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 SLOAD PUSH2 0x62 SWAP1 PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x8F SWAP1 PUSH2 0x296 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0xAB JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000FFFF AND PUSH3 0x10000 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP4 DUP5 AND DUP2 MUL SWAP2 SWAP1 SWAP2 OR SWAP2 DUP3 SWAP1 SSTORE PUSH1 0x40 MLOAD SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x10A SWAP1 PUSH2 0x2A3 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x143 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x1 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH2 0x19F SWAP1 PUSH2 0x2A3 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 PUSH1 0x0 CREATE DUP1 ISZERO DUP1 ISZERO PUSH2 0x1D8 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP PUSH1 0x2 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 DUP4 AND OR SWAP1 SSTORE PUSH1 0x0 SLOAD PUSH1 0x1 SLOAD PUSH1 0x40 MLOAD PUSH32 0xF2FDE38B00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 DUP4 AND PUSH1 0x4 DUP3 ADD MSTORE PUSH3 0x10000 SWAP1 SWAP2 DIV SWAP1 SWAP2 AND SWAP1 PUSH4 0xF2FDE38B SWAP1 PUSH1 0x24 ADD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x27C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x290 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH2 0x97C DUP1 PUSH2 0x2B1 DUP4 CODECOPY ADD SWAP1 JUMP JUMPDEST PUSH2 0x39E DUP1 PUSH2 0xC2D DUP4 CODECOPY ADD SWAP1 JUMP INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1A CALLER PUSH2 0x1F JUMP JUMPDEST PUSH2 0x6F JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 DUP2 AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH2 0x8FE DUP1 PUSH2 0x7E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x72 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xEAD710C4 GT PUSH2 0x50 JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0xEF690CC0 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0xF2FDE38B EQ PUSH2 0xDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH4 0x715018A6 EQ PUSH2 0x77 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0x81 JUMPI DUP1 PUSH4 0xC0129D43 EQ PUSH2 0xAE JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x7F PUSH2 0xF1 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x7F PUSH2 0x183 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x67D JUMP JUMPDEST PUSH2 0x2AB JUMP JUMPDEST PUSH2 0xD1 PUSH2 0x37B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xA5 SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST PUSH2 0x7F PUSH2 0xEC CALLDATASIZE PUSH1 0x4 PUSH2 0x640 JUMP JUMPDEST PUSH2 0x409 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x177 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x181 PUSH1 0x0 PUSH2 0x532 JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x204 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x20F PUSH1 0xA NUMBER PUSH2 0x83D JUMP JUMPDEST PUSH1 0x0 EQ PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x8A8 PUSH1 0x21 SWAP2 CODECOPY SWAP1 PUSH2 0x263 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x2 DUP1 DUP3 MSTORE PUSH32 0x676D000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 SWAP1 SWAP3 ADD SWAP2 DUP3 MSTORE PUSH2 0x2A8 SWAP2 PUSH1 0x1 SWAP2 PUSH2 0x5A7 JUMP JUMPDEST POP JUMP JUMPDEST PUSH32 0x71B78290913AF2ADDD8FCBE5766DE306AF2C8AFBC466CA891E207F73638C7270 DUP2 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2DD SWAP2 SWAP1 PUSH2 0x74C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 EQ ISZERO PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x14 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x63616E6E6F74206772656574207769746820676D000000000000000000000000 DUP2 MSTORE POP SWAP1 PUSH2 0x363 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x16E SWAP2 SWAP1 PUSH2 0x768 JUMP JUMPDEST POP DUP1 MLOAD PUSH2 0x377 SWAP1 PUSH1 0x1 SWAP1 PUSH1 0x20 DUP5 ADD SWAP1 PUSH2 0x5A7 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH2 0x388 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x3B4 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x401 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x3D6 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x401 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x3E4 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x48A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD DUP2 SWAP1 MSTORE PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A2063616C6C6572206973206E6F7420746865206F776E6572 PUSH1 0x44 DUP3 ADD MSTORE PUSH1 0x64 ADD PUSH2 0x16E JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND PUSH2 0x52D JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x26 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x4F776E61626C653A206E6577206F776E657220697320746865207A65726F2061 PUSH1 0x44 DUP3 ADD MSTORE PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000 PUSH1 0x64 DUP3 ADD MSTORE PUSH1 0x84 ADD PUSH2 0x16E JUMP JUMPDEST PUSH2 0x2A8 DUP2 JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 DUP4 AND DUP2 OR DUP5 SSTORE PUSH1 0x40 MLOAD SWAP2 SWAP1 SWAP3 AND SWAP3 DUP4 SWAP2 PUSH32 0x8BE0079C531659141344CD1FD0A4F28419497F9722A3DAAFE3B4186F6B6457E0 SWAP2 SWAP1 LOG3 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x5B3 SWAP1 PUSH2 0x7E9 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x5D5 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0x5EE JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH2 0x61B JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH2 0x61B JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x61B JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x600 JUMP JUMPDEST POP PUSH2 0x627 SWAP3 SWAP2 POP PUSH2 0x62B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x627 JUMPI PUSH1 0x0 DUP2 SSTORE PUSH1 0x1 ADD PUSH2 0x62C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x652 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x676 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x68F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x6A7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x6BB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x6CD JUMPI PUSH2 0x6CD PUSH2 0x878 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x713 JUMPI PUSH2 0x713 PUSH2 0x878 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x72C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 MLOAD PUSH2 0x75E DUP2 DUP5 PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 DUP2 MSTORE PUSH1 0x0 DUP3 MLOAD DUP1 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x787 DUP2 PUSH1 0x40 DUP6 ADD PUSH1 0x20 DUP8 ADD PUSH2 0x7B9 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP2 SWAP1 SWAP2 ADD PUSH1 0x40 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x7D4 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x7BC JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x7E3 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SHR SWAP1 DUP3 AND DUP1 PUSH2 0x7FD JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 EQ ISZERO PUSH2 0x837 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH2 0x873 JUMPI PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x12 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST POP MOD SWAP1 JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID PUSH10 0x6E76616C696420626C6F PUSH4 0x6B206E75 PUSH14 0x6265722C20706C65617365207761 PUSH10 0x74A26469706673582212 KECCAK256 SDIV DIV 0x5F GASPRICE RETURNDATACOPY MSTORE MULMOD 0xD1 0xD8 0x29 ADDMOD SWAP3 SSTORE 0x5E SWAP6 SLOAD SWAP7 0xEF 0xC2 CODECOPY CREATE DUP10 0xD2 0xB9 0xB8 SWAP12 LOG3 SAR 0xAB 0xA7 RETURNDATACOPY SWAP6 PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x39E CODESIZE SUB DUP1 PUSH2 0x39E DUP4 CODECOPY DUP2 ADD PUSH1 0x40 DUP2 SWAP1 MSTORE PUSH2 0x2F SWAP2 PUSH2 0x54 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x84 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x66 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH2 0x7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH2 0x30B DUP1 PUSH2 0x93 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC0129D43 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x58 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x43 PUSH2 0x53 CALLDATASIZE PUSH1 0x4 PUSH2 0x164 JUMP JUMPDEST PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0xC0129D4300000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP3 PUSH4 0xC0129D43 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xD3 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x12F SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0x233 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x149 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x15D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x176 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x18E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x1A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1B4 JUMPI PUSH2 0x1B4 PUSH2 0x2A6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x1FA JUMPI PUSH2 0x1FA PUSH2 0x2A6 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x213 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 MSTORE DUP4 MLOAD DUP1 DUP3 DUP6 ADD MSTORE PUSH1 0x0 JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x260 JUMPI DUP6 DUP2 ADD DUP4 ADD MLOAD DUP6 DUP3 ADD PUSH1 0x40 ADD MSTORE DUP3 ADD PUSH2 0x244 JUMP JUMPDEST DUP2 DUP2 GT ISZERO PUSH2 0x272 JUMPI PUSH1 0x0 PUSH1 0x40 DUP4 DUP8 ADD ADD MSTORE JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x40 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xBF 0xA7 0x2E 0xD9 0xEA 0xD JUMPI SWAP1 0x5E SWAP3 DUP2 0x1E ORIGIN DUP3 PUSH1 0x53 BASEFEE MOD 0xDB 0xDB DUP11 0xD5 DUP7 PUSH22 0x306B2582254F247564736F6C63430008070033A26469 PUSH17 0x667358221220E06545F20EDEEE00D94D15 CREATE MULMOD 0x4F 0xDA 0xDB 0xDD 0xEB 0xDB ADD DIFFICULTY 0x1E 0xA9 PUSH5 0xDF3D7E79CC DUP7 SWAP6 MULMOD PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER ","sourceMap":"417:413:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;619:209;;;:::i;:::-;;1605:18:0;;;;;;;;;;;;;;;410:14:7;;403:22;385:41;;373:2;358:18;1605::0;;;;;;;1573:26;;;;;;;;;619:209:5;671:13;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;661:7:5;:23;;;;;;;;;;;;;;;;;;;702:26;;719:7;;;;;;702:26;;;:::i;:::-;190:42:7;178:55;;;160:74;;148:2;133:18;702:26:5;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;694:5:5;:34;;;;;;;;;;;-1:-1:-1;761:7:5;744:26;;761:7;;;;;;;;744:26;;;:::i;:::-;190:42:7;178:55;;;160:74;;148:2;133:18;744:26:5;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;738:3:5;:32;;;;;;;;;;;-1:-1:-1;780:7:5;-1:-1:-1;814:5:5;780:41;;;;;814:5;;;780:41;;;160:74:7;780:7:5;;;;;;;;:25;;133:18:7;;780:41:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;619:209::o;-1:-1:-1:-;;;;;;;;:::o;:::-;;;;;;;;:::o"}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log_address\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"log_bytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"log_bytes32\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"name\":\"log_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"val\",\"type\":\"address\"}],\"name\":\"log_named_address\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"val\",\"type\":\"bytes\"}],\"name\":\"log_named_bytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"val\",\"type\":\"bytes32\"}],\"name\":\"log_named_bytes32\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"}],\"name\":\"log_named_decimal_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"}],\"name\":\"log_named_decimal_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"}],\"name\":\"log_named_int\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"val\",\"type\":\"string\"}],\"name\":\"log_named_string\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"log_named_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log_string\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log_uint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"logs\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"IS_TEST\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"failed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"setUp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/test/utils/GreeterTest.sol\":\"GreeterTest\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/ds-test/src/test.sol\":{\"keccak256\":\"0x529f30c5939d75689f6a982f7f96b8898bed30bd90ec5b385b57cab681e12b00\",\"license\":\"GPL-3.0-or-later\",\"urls\":[\"bzz-raw://89075d5a96e87acef1d00cf556b409d1836728ec2e92f5629ceb5cae3d1e4354\",\"dweb:/ipfs/QmPAViJrxffEDns9GEMVSAzmr3soAzfrEg1CVuovwmNfnt\"]},\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x6bb804a310218875e89d12c053e94a13a4607cdf7cc2052f3e52bd32a0dc50a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2ebbbe6d0011175bd9e7268b83de3f9c2f9d8d4cbfbaef12aff977d7d727163\",\"dweb:/ipfs/Qmd5c7Vxtis9wzkDNhxwc6A2QT5H9xn9kfjhx7qx44vpro\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x90565a39ae45c80f0468dc96c7b20d0afc3055f344c8203a0c9258239f350b9f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e8b38a7ac8e7b4463af00cf7fff1bf48ae9875765bf4f7751e100124d0bc8c\",\"dweb:/ipfs/QmWcsmkVr24xmmjfnBQZoemFniXjj3vwT78Cz6uqZW1Hux\"]},\"src/Greeter.sol\":{\"keccak256\":\"0xc34bd8409a4fa4a474f29c6cb7d076cf9379c9c79e257c5cda7e5d114023f0f6\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://9db4f0c61754c54fd3b3ae58dfaf72865f8134e96959f7fc295b1a8e3b7511d7\",\"dweb:/ipfs/QmPuGbtNJ9rRaC7kFWqy76A9sfcGGcYAps6yPRrW28v4xd\"]},\"src/test/utils/GreeterTest.sol\":{\"keccak256\":\"0xc49253ed5e0fc9185d066993945370493f2bb08f00a997680b112fe6f9b5d455\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://d5ff89c2bb371b6ddfb66b905b3c3597aa080e1ca5c1c1303e529f2c8fc98a67\",\"dweb:/ipfs/Qmc28bfatf99DDv6P8dpdo5Zsw7QdSoC1N4FV1TJGZF5Vx\"]},\"src/test/utils/Hevm.sol\":{\"keccak256\":\"0xd477fc888e2bdbaf45c8babf175c93127478ae74543556ffebb9877a8dd823a9\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://7fb2a52878484cea3793a92ae34b3a9f3e77f976eda7c7f91e2edb5b9ba38be3\",\"dweb:/ipfs/Qmf7JsG4uMjd7WX1h8rBPcpXv1m4mF3sdrr6VYzKj1SXUX\"]}},\"version\":1}","storageLayout":{"storage":[{"astId":532,"contract":"src/test/utils/GreeterTest.sol:GreeterTest","label":"IS_TEST","offset":0,"slot":"0","type":"t_bool"},{"astId":534,"contract":"src/test/utils/GreeterTest.sol:GreeterTest","label":"failed","offset":1,"slot":"0","type":"t_bool"},{"astId":260,"contract":"src/test/utils/GreeterTest.sol:GreeterTest","label":"greeter","offset":2,"slot":"0","type":"t_contract(Greeter)60"},{"astId":263,"contract":"src/test/utils/GreeterTest.sol:GreeterTest","label":"alice","offset":0,"slot":"1","type":"t_contract(User)249"},{"astId":266,"contract":"src/test/utils/GreeterTest.sol:GreeterTest","label":"bob","offset":0,"slot":"2","type":"t_contract(User)249"}],"types":{"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_contract(Greeter)60":{"encoding":"inplace","label":"contract Greeter","numberOfBytes":"20"},"t_contract(User)249":{"encoding":"inplace","label":"contract User","numberOfBytes":"20"}}}},"User":{"abi":[{"inputs":[{"internalType":"address","name":"_greeter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"gm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"greeting","type":"string"}],"name":"greet","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{"@_227":{"entryPoint":null,"id":227,"parameterSlots":1,"returnSlots":0},"abi_decode_tuple_t_address_fromMemory":{"entryPoint":84,"id":null,"parameterSlots":2,"returnSlots":1}},"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:306:7","statements":[{"nodeType":"YulBlock","src":"6:3:7","statements":[]},{"body":{"nodeType":"YulBlock","src":"95:209:7","statements":[{"body":{"nodeType":"YulBlock","src":"141:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"150:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"153:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"143:6:7"},"nodeType":"YulFunctionCall","src":"143:12:7"},"nodeType":"YulExpressionStatement","src":"143:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"116:7:7"},{"name":"headStart","nodeType":"YulIdentifier","src":"125:9:7"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"112:3:7"},"nodeType":"YulFunctionCall","src":"112:23:7"},{"kind":"number","nodeType":"YulLiteral","src":"137:2:7","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"108:3:7"},"nodeType":"YulFunctionCall","src":"108:32:7"},"nodeType":"YulIf","src":"105:52:7"},{"nodeType":"YulVariableDeclaration","src":"166:29:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"185:9:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"179:5:7"},"nodeType":"YulFunctionCall","src":"179:16:7"},"variables":[{"name":"value","nodeType":"YulTypedName","src":"170:5:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"258:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"267:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"270:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"260:6:7"},"nodeType":"YulFunctionCall","src":"260:12:7"},"nodeType":"YulExpressionStatement","src":"260:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"217:5:7"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"228:5:7"},{"arguments":[{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"243:3:7","type":"","value":"160"},{"kind":"number","nodeType":"YulLiteral","src":"248:1:7","type":"","value":"1"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"239:3:7"},"nodeType":"YulFunctionCall","src":"239:11:7"},{"kind":"number","nodeType":"YulLiteral","src":"252:1:7","type":"","value":"1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"235:3:7"},"nodeType":"YulFunctionCall","src":"235:19:7"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"224:3:7"},"nodeType":"YulFunctionCall","src":"224:31:7"}],"functionName":{"name":"eq","nodeType":"YulIdentifier","src":"214:2:7"},"nodeType":"YulFunctionCall","src":"214:42:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"207:6:7"},"nodeType":"YulFunctionCall","src":"207:50:7"},"nodeType":"YulIf","src":"204:70:7"},{"nodeType":"YulAssignment","src":"283:15:7","value":{"name":"value","nodeType":"YulIdentifier","src":"293:5:7"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"283:6:7"}]}]},"name":"abi_decode_tuple_t_address_fromMemory","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"61:9:7","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"72:7:7","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"84:6:7","type":""}],"src":"14:290:7"}]},"contents":"{\n { }\n function abi_decode_tuple_t_address_fromMemory(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n let value := mload(headStart)\n if iszero(eq(value, and(value, sub(shl(160, 1), 1)))) { revert(0, 0) }\n value0 := value\n }\n}","id":7,"language":"Yul","name":"#utility.yul"}],"linkReferences":{},"object":"608060405234801561001057600080fd5b5060405161039e38038061039e83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61030b806100936000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c0129d431461003b578063ead710c414610045575b600080fd5b610043610058565b005b610043610053366004610164565b6100d9565b60008054604080517fc0129d43000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169263c0129d439260048084019382900301818387803b1580156100bf57600080fd5b505af11580156100d3573d6000803e3d6000fd5b50505050565b6000546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c49061012f908490600401610233565b600060405180830381600087803b15801561014957600080fd5b505af115801561015d573d6000803e3d6000fd5b5050505050565b60006020828403121561017657600080fd5b813567ffffffffffffffff8082111561018e57600080fd5b818401915084601f8301126101a257600080fd5b8135818111156101b4576101b46102a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101fa576101fa6102a6565b8160405282815287602084870101111561021357600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561026057858101830151858201604001528201610244565b81811115610272576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220bfa72ed9ea0d57905e92811e328260534806dbdb8ad58675306b2582254f247564736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x39E CODESIZE SUB DUP1 PUSH2 0x39E DUP4 CODECOPY DUP2 ADD PUSH1 0x40 DUP2 SWAP1 MSTORE PUSH2 0x2F SWAP2 PUSH2 0x54 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x84 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x66 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH2 0x7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH2 0x30B DUP1 PUSH2 0x93 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC0129D43 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x58 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x43 PUSH2 0x53 CALLDATASIZE PUSH1 0x4 PUSH2 0x164 JUMP JUMPDEST PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0xC0129D4300000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP3 PUSH4 0xC0129D43 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xD3 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x12F SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0x233 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x149 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x15D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x176 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x18E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x1A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1B4 JUMPI PUSH2 0x1B4 PUSH2 0x2A6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x1FA JUMPI PUSH2 0x1FA PUSH2 0x2A6 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x213 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 MSTORE DUP4 MLOAD DUP1 DUP3 DUP6 ADD MSTORE PUSH1 0x0 JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x260 JUMPI DUP6 DUP2 ADD DUP4 ADD MLOAD DUP6 DUP3 ADD PUSH1 0x40 ADD MSTORE DUP3 ADD PUSH2 0x244 JUMP JUMPDEST DUP2 DUP2 GT ISZERO PUSH2 0x272 JUMPI PUSH1 0x0 PUSH1 0x40 DUP4 DUP8 ADD ADD MSTORE JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x40 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xBF 0xA7 0x2E 0xD9 0xEA 0xD JUMPI SWAP1 0x5E SWAP3 DUP2 0x1E ORIGIN DUP3 PUSH1 0x53 BASEFEE MOD 0xDB 0xDB DUP11 0xD5 DUP7 PUSH22 0x306B2582254F247564736F6C63430008070033000000 ","sourceMap":"140:275:5:-:0;;;191:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;231:7;:27;;-1:-1:-1;231:27:5;-1:-1:-1;231:27:5;;;;;;;;;;140:275;;14:290:7;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;224:31:7;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:7:o;:::-;140:275:5;;;;;;"},"deployedBytecode":{"functionDebugData":{"@gm_248":{"entryPoint":88,"id":248,"parameterSlots":0,"returnSlots":0},"@greet_239":{"entryPoint":217,"id":239,"parameterSlots":1,"returnSlots":0},"abi_decode_tuple_t_string_memory_ptr":{"entryPoint":356,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed":{"entryPoint":563,"id":null,"parameterSlots":2,"returnSlots":1},"panic_error_0x41":{"entryPoint":678,"id":null,"parameterSlots":0,"returnSlots":0}},"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:1847:7","statements":[{"nodeType":"YulBlock","src":"6:3:7","statements":[]},{"body":{"nodeType":"YulBlock","src":"94:901:7","statements":[{"body":{"nodeType":"YulBlock","src":"140:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"149:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"152:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"142:6:7"},"nodeType":"YulFunctionCall","src":"142:12:7"},"nodeType":"YulExpressionStatement","src":"142:12:7"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"115:7:7"},{"name":"headStart","nodeType":"YulIdentifier","src":"124:9:7"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"111:3:7"},"nodeType":"YulFunctionCall","src":"111:23:7"},{"kind":"number","nodeType":"YulLiteral","src":"136:2:7","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"107:3:7"},"nodeType":"YulFunctionCall","src":"107:32:7"},"nodeType":"YulIf","src":"104:52:7"},{"nodeType":"YulVariableDeclaration","src":"165:37:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"192:9:7"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"179:12:7"},"nodeType":"YulFunctionCall","src":"179:23:7"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"169:6:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"211:28:7","value":{"kind":"number","nodeType":"YulLiteral","src":"221:18:7","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"215:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"266:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"275:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"278:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"268:6:7"},"nodeType":"YulFunctionCall","src":"268:12:7"},"nodeType":"YulExpressionStatement","src":"268:12:7"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"254:6:7"},{"name":"_1","nodeType":"YulIdentifier","src":"262:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"251:2:7"},"nodeType":"YulFunctionCall","src":"251:14:7"},"nodeType":"YulIf","src":"248:34:7"},{"nodeType":"YulVariableDeclaration","src":"291:32:7","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"305:9:7"},{"name":"offset","nodeType":"YulIdentifier","src":"316:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"301:3:7"},"nodeType":"YulFunctionCall","src":"301:22:7"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"295:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"371:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"380:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"383:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"373:6:7"},"nodeType":"YulFunctionCall","src":"373:12:7"},"nodeType":"YulExpressionStatement","src":"373:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"350:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"354:4:7","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"346:3:7"},"nodeType":"YulFunctionCall","src":"346:13:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"361:7:7"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"342:3:7"},"nodeType":"YulFunctionCall","src":"342:27:7"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"335:6:7"},"nodeType":"YulFunctionCall","src":"335:35:7"},"nodeType":"YulIf","src":"332:55:7"},{"nodeType":"YulVariableDeclaration","src":"396:26:7","value":{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"419:2:7"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"406:12:7"},"nodeType":"YulFunctionCall","src":"406:16:7"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"400:2:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"445:22:7","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"447:16:7"},"nodeType":"YulFunctionCall","src":"447:18:7"},"nodeType":"YulExpressionStatement","src":"447:18:7"}]},"condition":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"437:2:7"},{"name":"_1","nodeType":"YulIdentifier","src":"441:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"434:2:7"},"nodeType":"YulFunctionCall","src":"434:10:7"},"nodeType":"YulIf","src":"431:36:7"},{"nodeType":"YulVariableDeclaration","src":"476:76:7","value":{"kind":"number","nodeType":"YulLiteral","src":"486:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"},"variables":[{"name":"_4","nodeType":"YulTypedName","src":"480:2:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"561:23:7","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"581:2:7","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"575:5:7"},"nodeType":"YulFunctionCall","src":"575:9:7"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"565:6:7","type":""}]},{"nodeType":"YulVariableDeclaration","src":"593:71:7","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"615:6:7"},{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"639:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"643:4:7","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"635:3:7"},"nodeType":"YulFunctionCall","src":"635:13:7"},{"name":"_4","nodeType":"YulIdentifier","src":"650:2:7"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"631:3:7"},"nodeType":"YulFunctionCall","src":"631:22:7"},{"kind":"number","nodeType":"YulLiteral","src":"655:2:7","type":"","value":"63"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"627:3:7"},"nodeType":"YulFunctionCall","src":"627:31:7"},{"name":"_4","nodeType":"YulIdentifier","src":"660:2:7"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"623:3:7"},"nodeType":"YulFunctionCall","src":"623:40:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"611:3:7"},"nodeType":"YulFunctionCall","src":"611:53:7"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"597:10:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"723:22:7","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"725:16:7"},"nodeType":"YulFunctionCall","src":"725:18:7"},"nodeType":"YulExpressionStatement","src":"725:18:7"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"682:10:7"},{"name":"_1","nodeType":"YulIdentifier","src":"694:2:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"679:2:7"},"nodeType":"YulFunctionCall","src":"679:18:7"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"702:10:7"},{"name":"memPtr","nodeType":"YulIdentifier","src":"714:6:7"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"699:2:7"},"nodeType":"YulFunctionCall","src":"699:22:7"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"676:2:7"},"nodeType":"YulFunctionCall","src":"676:46:7"},"nodeType":"YulIf","src":"673:72:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"761:2:7","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"765:10:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"754:6:7"},"nodeType":"YulFunctionCall","src":"754:22:7"},"nodeType":"YulExpressionStatement","src":"754:22:7"},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"792:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"800:2:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"785:6:7"},"nodeType":"YulFunctionCall","src":"785:18:7"},"nodeType":"YulExpressionStatement","src":"785:18:7"},{"body":{"nodeType":"YulBlock","src":"849:16:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"858:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"861:1:7","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"851:6:7"},"nodeType":"YulFunctionCall","src":"851:12:7"},"nodeType":"YulExpressionStatement","src":"851:12:7"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"826:2:7"},{"name":"_3","nodeType":"YulIdentifier","src":"830:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"822:3:7"},"nodeType":"YulFunctionCall","src":"822:11:7"},{"kind":"number","nodeType":"YulLiteral","src":"835:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"818:3:7"},"nodeType":"YulFunctionCall","src":"818:20:7"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"840:7:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"815:2:7"},"nodeType":"YulFunctionCall","src":"815:33:7"},"nodeType":"YulIf","src":"812:53:7"},{"expression":{"arguments":[{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"891:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"899:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"887:3:7"},"nodeType":"YulFunctionCall","src":"887:15:7"},{"arguments":[{"name":"_2","nodeType":"YulIdentifier","src":"908:2:7"},{"kind":"number","nodeType":"YulLiteral","src":"912:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"904:3:7"},"nodeType":"YulFunctionCall","src":"904:11:7"},{"name":"_3","nodeType":"YulIdentifier","src":"917:2:7"}],"functionName":{"name":"calldatacopy","nodeType":"YulIdentifier","src":"874:12:7"},"nodeType":"YulFunctionCall","src":"874:46:7"},"nodeType":"YulExpressionStatement","src":"874:46:7"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"944:6:7"},{"name":"_3","nodeType":"YulIdentifier","src":"952:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"940:3:7"},"nodeType":"YulFunctionCall","src":"940:15:7"},{"kind":"number","nodeType":"YulLiteral","src":"957:2:7","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"936:3:7"},"nodeType":"YulFunctionCall","src":"936:24:7"},{"kind":"number","nodeType":"YulLiteral","src":"962:1:7","type":"","value":"0"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"929:6:7"},"nodeType":"YulFunctionCall","src":"929:35:7"},"nodeType":"YulExpressionStatement","src":"929:35:7"},{"nodeType":"YulAssignment","src":"973:16:7","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"983:6:7"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"973:6:7"}]}]},"name":"abi_decode_tuple_t_string_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"60:9:7","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"71:7:7","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"83:6:7","type":""}],"src":"14:981:7"},{"body":{"nodeType":"YulBlock","src":"1121:535:7","statements":[{"nodeType":"YulVariableDeclaration","src":"1131:12:7","value":{"kind":"number","nodeType":"YulLiteral","src":"1141:2:7","type":"","value":"32"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"1135:2:7","type":""}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1159:9:7"},{"name":"_1","nodeType":"YulIdentifier","src":"1170:2:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1152:6:7"},"nodeType":"YulFunctionCall","src":"1152:21:7"},"nodeType":"YulExpressionStatement","src":"1152:21:7"},{"nodeType":"YulVariableDeclaration","src":"1182:27:7","value":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1202:6:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1196:5:7"},"nodeType":"YulFunctionCall","src":"1196:13:7"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"1186:6:7","type":""}]},{"expression":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1229:9:7"},{"name":"_1","nodeType":"YulIdentifier","src":"1240:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1225:3:7"},"nodeType":"YulFunctionCall","src":"1225:18:7"},{"name":"length","nodeType":"YulIdentifier","src":"1245:6:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1218:6:7"},"nodeType":"YulFunctionCall","src":"1218:34:7"},"nodeType":"YulExpressionStatement","src":"1218:34:7"},{"nodeType":"YulVariableDeclaration","src":"1261:10:7","value":{"kind":"number","nodeType":"YulLiteral","src":"1270:1:7","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"1265:1:7","type":""}]},{"body":{"nodeType":"YulBlock","src":"1330:90:7","statements":[{"expression":{"arguments":[{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1359:9:7"},{"name":"i","nodeType":"YulIdentifier","src":"1370:1:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1355:3:7"},"nodeType":"YulFunctionCall","src":"1355:17:7"},{"kind":"number","nodeType":"YulLiteral","src":"1374:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1351:3:7"},"nodeType":"YulFunctionCall","src":"1351:26:7"},{"arguments":[{"arguments":[{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1393:6:7"},{"name":"i","nodeType":"YulIdentifier","src":"1401:1:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1389:3:7"},"nodeType":"YulFunctionCall","src":"1389:14:7"},{"name":"_1","nodeType":"YulIdentifier","src":"1405:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1385:3:7"},"nodeType":"YulFunctionCall","src":"1385:23:7"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1379:5:7"},"nodeType":"YulFunctionCall","src":"1379:30:7"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1344:6:7"},"nodeType":"YulFunctionCall","src":"1344:66:7"},"nodeType":"YulExpressionStatement","src":"1344:66:7"}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"1291:1:7"},{"name":"length","nodeType":"YulIdentifier","src":"1294:6:7"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"1288:2:7"},"nodeType":"YulFunctionCall","src":"1288:13:7"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"1302:19:7","statements":[{"nodeType":"YulAssignment","src":"1304:15:7","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"1313:1:7"},{"name":"_1","nodeType":"YulIdentifier","src":"1316:2:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1309:3:7"},"nodeType":"YulFunctionCall","src":"1309:10:7"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"1304:1:7"}]}]},"pre":{"nodeType":"YulBlock","src":"1284:3:7","statements":[]},"src":"1280:140:7"},{"body":{"nodeType":"YulBlock","src":"1454:66:7","statements":[{"expression":{"arguments":[{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1483:9:7"},{"name":"length","nodeType":"YulIdentifier","src":"1494:6:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1479:3:7"},"nodeType":"YulFunctionCall","src":"1479:22:7"},{"kind":"number","nodeType":"YulLiteral","src":"1503:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1475:3:7"},"nodeType":"YulFunctionCall","src":"1475:31:7"},{"kind":"number","nodeType":"YulLiteral","src":"1508:1:7","type":"","value":"0"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1468:6:7"},"nodeType":"YulFunctionCall","src":"1468:42:7"},"nodeType":"YulExpressionStatement","src":"1468:42:7"}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"1435:1:7"},{"name":"length","nodeType":"YulIdentifier","src":"1438:6:7"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1432:2:7"},"nodeType":"YulFunctionCall","src":"1432:13:7"},"nodeType":"YulIf","src":"1429:91:7"},{"nodeType":"YulAssignment","src":"1529:121:7","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1545:9:7"},{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1564:6:7"},{"kind":"number","nodeType":"YulLiteral","src":"1572:2:7","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1560:3:7"},"nodeType":"YulFunctionCall","src":"1560:15:7"},{"kind":"number","nodeType":"YulLiteral","src":"1577:66:7","type":"","value":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"1556:3:7"},"nodeType":"YulFunctionCall","src":"1556:88:7"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1541:3:7"},"nodeType":"YulFunctionCall","src":"1541:104:7"},{"kind":"number","nodeType":"YulLiteral","src":"1647:2:7","type":"","value":"64"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1537:3:7"},"nodeType":"YulFunctionCall","src":"1537:113:7"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1529:4:7"}]}]},"name":"abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1090:9:7","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1101:6:7","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1112:4:7","type":""}],"src":"1000:656:7"},{"body":{"nodeType":"YulBlock","src":"1693:152:7","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1710:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1713:77:7","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1703:6:7"},"nodeType":"YulFunctionCall","src":"1703:88:7"},"nodeType":"YulExpressionStatement","src":"1703:88:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1807:1:7","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"1810:4:7","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1800:6:7"},"nodeType":"YulFunctionCall","src":"1800:15:7"},"nodeType":"YulExpressionStatement","src":"1800:15:7"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1831:1:7","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1834:4:7","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1824:6:7"},"nodeType":"YulFunctionCall","src":"1824:15:7"},"nodeType":"YulExpressionStatement","src":"1824:15:7"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"1661:184:7"}]},"contents":"{\n { }\n function abi_decode_tuple_t_string_memory_ptr(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n let offset := calldataload(headStart)\n let _1 := 0xffffffffffffffff\n if gt(offset, _1) { revert(0, 0) }\n let _2 := add(headStart, offset)\n if iszero(slt(add(_2, 0x1f), dataEnd)) { revert(0, 0) }\n let _3 := calldataload(_2)\n if gt(_3, _1) { panic_error_0x41() }\n let _4 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0\n let memPtr := mload(64)\n let newFreePtr := add(memPtr, and(add(and(add(_3, 0x1f), _4), 63), _4))\n if or(gt(newFreePtr, _1), lt(newFreePtr, memPtr)) { panic_error_0x41() }\n mstore(64, newFreePtr)\n mstore(memPtr, _3)\n if gt(add(add(_2, _3), 32), dataEnd) { revert(0, 0) }\n calldatacopy(add(memPtr, 32), add(_2, 32), _3)\n mstore(add(add(memPtr, _3), 32), 0)\n value0 := memPtr\n }\n function abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed(headStart, value0) -> tail\n {\n let _1 := 32\n mstore(headStart, _1)\n let length := mload(value0)\n mstore(add(headStart, _1), length)\n let i := 0\n for { } lt(i, length) { i := add(i, _1) }\n {\n mstore(add(add(headStart, i), 64), mload(add(add(value0, i), _1)))\n }\n if gt(i, length)\n {\n mstore(add(add(headStart, length), 64), 0)\n }\n tail := add(add(headStart, and(add(length, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)), 64)\n }\n function panic_error_0x41()\n {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x41)\n revert(0, 0x24)\n }\n}","id":7,"language":"Yul","name":"#utility.yul"}],"immutableReferences":{},"linkReferences":{},"object":"608060405234801561001057600080fd5b50600436106100365760003560e01c8063c0129d431461003b578063ead710c414610045575b600080fd5b610043610058565b005b610043610053366004610164565b6100d9565b60008054604080517fc0129d43000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169263c0129d439260048084019382900301818387803b1580156100bf57600080fd5b505af11580156100d3573d6000803e3d6000fd5b50505050565b6000546040517fead710c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063ead710c49061012f908490600401610233565b600060405180830381600087803b15801561014957600080fd5b505af115801561015d573d6000803e3d6000fd5b5050505050565b60006020828403121561017657600080fd5b813567ffffffffffffffff8082111561018e57600080fd5b818401915084601f8301126101a257600080fd5b8135818111156101b4576101b46102a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101fa576101fa6102a6565b8160405282815287602084870101111561021357600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561026057858101830151858201604001528201610244565b81811115610272576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220bfa72ed9ea0d57905e92811e328260534806dbdb8ad58675306b2582254f247564736f6c63430008070033","opcodes":"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC0129D43 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0xEAD710C4 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x58 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x43 PUSH2 0x53 CALLDATASIZE PUSH1 0x4 PUSH2 0x164 JUMP JUMPDEST PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0xC0129D4300000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP3 PUSH4 0xC0129D43 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xBF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xD3 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0xEAD710C400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0xEAD710C4 SWAP1 PUSH2 0x12F SWAP1 DUP5 SWAP1 PUSH1 0x4 ADD PUSH2 0x233 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x149 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x15D JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x176 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x18E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 DUP5 ADD SWAP2 POP DUP5 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x1A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1B4 JUMPI PUSH2 0x1B4 PUSH2 0x2A6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x1F DUP3 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 DUP2 AND PUSH1 0x3F ADD AND DUP2 ADD SWAP1 DUP4 DUP3 GT DUP2 DUP4 LT OR ISZERO PUSH2 0x1FA JUMPI PUSH2 0x1FA PUSH2 0x2A6 JUMP JUMPDEST DUP2 PUSH1 0x40 MSTORE DUP3 DUP2 MSTORE DUP8 PUSH1 0x20 DUP5 DUP8 ADD ADD GT ISZERO PUSH2 0x213 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP4 ADD CALLDATACOPY PUSH1 0x0 SWAP3 DUP2 ADD PUSH1 0x20 ADD SWAP3 SWAP1 SWAP3 MSTORE POP SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 MSTORE DUP4 MLOAD DUP1 DUP3 DUP6 ADD MSTORE PUSH1 0x0 JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x260 JUMPI DUP6 DUP2 ADD DUP4 ADD MLOAD DUP6 DUP3 ADD PUSH1 0x40 ADD MSTORE DUP3 ADD PUSH2 0x244 JUMP JUMPDEST DUP2 DUP2 GT ISZERO PUSH2 0x272 JUMPI PUSH1 0x0 PUSH1 0x40 DUP4 DUP8 ADD ADD MSTORE JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x40 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xBF 0xA7 0x2E 0xD9 0xEA 0xD JUMPI SWAP1 0x5E SWAP3 DUP2 0x1E ORIGIN DUP3 PUSH1 0x53 BASEFEE MOD 0xDB 0xDB DUP11 0xD5 DUP7 PUSH22 0x306B2582254F247564736F6C63430008070033000000 ","sourceMap":"140:275:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;363:50;;;:::i;:::-;;271:86;;;;;;:::i;:::-;;:::i;363:50::-;394:7;;;:12;;;;;;;;:7;;;;;:10;;:12;;;;;;;;;;:7;;:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;363:50::o;271:86::-;327:7;;:23;;;;;:7;;;;;:13;;:23;;341:8;;327:23;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;271:86;:::o;14:981:7:-;83:6;136:2;124:9;115:7;111:23;107:32;104:52;;;152:1;149;142:12;104:52;192:9;179:23;221:18;262:2;254:6;251:14;248:34;;;278:1;275;268:12;248:34;316:6;305:9;301:22;291:32;;361:7;354:4;350:2;346:13;342:27;332:55;;383:1;380;373:12;332:55;419:2;406:16;441:2;437;434:10;431:36;;;447:18;;:::i;:::-;581:2;575:9;643:4;635:13;;486:66;631:22;;;655:2;627:31;623:40;611:53;;;679:18;;;699:22;;;676:46;673:72;;;725:18;;:::i;:::-;765:10;761:2;754:22;800:2;792:6;785:18;840:7;835:2;830;826;822:11;818:20;815:33;812:53;;;861:1;858;851:12;812:53;917:2;912;908;904:11;899:2;891:6;887:15;874:46;962:1;940:15;;;957:2;936:24;929:35;;;;-1:-1:-1;944:6:7;14:981;-1:-1:-1;;;;;14:981:7:o;1000:656::-;1112:4;1141:2;1170;1159:9;1152:21;1202:6;1196:13;1245:6;1240:2;1229:9;1225:18;1218:34;1270:1;1280:140;1294:6;1291:1;1288:13;1280:140;;;1389:14;;;1385:23;;1379:30;1355:17;;;1374:2;1351:26;1344:66;1309:10;;1280:140;;;1438:6;1435:1;1432:13;1429:91;;;1508:1;1503:2;1494:6;1483:9;1479:22;1475:31;1468:42;1429:91;-1:-1:-1;1572:2:7;1560:15;1577:66;1556:88;1541:104;;;;1647:2;1537:113;;1000:656;-1:-1:-1;;;1000:656:7:o;1661:184::-;1713:77;1710:1;1703:88;1810:4;1807:1;1800:15;1834:4;1831:1;1824:15"}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_greeter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"gm\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"greeting\",\"type\":\"string\"}],\"name\":\"greet\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/test/utils/GreeterTest.sol\":\"User\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"lib/ds-test/src/test.sol\":{\"keccak256\":\"0x529f30c5939d75689f6a982f7f96b8898bed30bd90ec5b385b57cab681e12b00\",\"license\":\"GPL-3.0-or-later\",\"urls\":[\"bzz-raw://89075d5a96e87acef1d00cf556b409d1836728ec2e92f5629ceb5cae3d1e4354\",\"dweb:/ipfs/QmPAViJrxffEDns9GEMVSAzmr3soAzfrEg1CVuovwmNfnt\"]},\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x6bb804a310218875e89d12c053e94a13a4607cdf7cc2052f3e52bd32a0dc50a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2ebbbe6d0011175bd9e7268b83de3f9c2f9d8d4cbfbaef12aff977d7d727163\",\"dweb:/ipfs/Qmd5c7Vxtis9wzkDNhxwc6A2QT5H9xn9kfjhx7qx44vpro\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x90565a39ae45c80f0468dc96c7b20d0afc3055f344c8203a0c9258239f350b9f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e8b38a7ac8e7b4463af00cf7fff1bf48ae9875765bf4f7751e100124d0bc8c\",\"dweb:/ipfs/QmWcsmkVr24xmmjfnBQZoemFniXjj3vwT78Cz6uqZW1Hux\"]},\"src/Greeter.sol\":{\"keccak256\":\"0xc34bd8409a4fa4a474f29c6cb7d076cf9379c9c79e257c5cda7e5d114023f0f6\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://9db4f0c61754c54fd3b3ae58dfaf72865f8134e96959f7fc295b1a8e3b7511d7\",\"dweb:/ipfs/QmPuGbtNJ9rRaC7kFWqy76A9sfcGGcYAps6yPRrW28v4xd\"]},\"src/test/utils/GreeterTest.sol\":{\"keccak256\":\"0xc49253ed5e0fc9185d066993945370493f2bb08f00a997680b112fe6f9b5d455\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://d5ff89c2bb371b6ddfb66b905b3c3597aa080e1ca5c1c1303e529f2c8fc98a67\",\"dweb:/ipfs/Qmc28bfatf99DDv6P8dpdo5Zsw7QdSoC1N4FV1TJGZF5Vx\"]},\"src/test/utils/Hevm.sol\":{\"keccak256\":\"0xd477fc888e2bdbaf45c8babf175c93127478ae74543556ffebb9877a8dd823a9\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://7fb2a52878484cea3793a92ae34b3a9f3e77f976eda7c7f91e2edb5b9ba38be3\",\"dweb:/ipfs/Qmf7JsG4uMjd7WX1h8rBPcpXv1m4mF3sdrr6VYzKj1SXUX\"]}},\"version\":1}","storageLayout":{"storage":[{"astId":215,"contract":"src/test/utils/GreeterTest.sol:User","label":"greeter","offset":0,"slot":"0","type":"t_contract(Greeter)60"}],"types":{"t_contract(Greeter)60":{"encoding":"inplace","label":"contract Greeter","numberOfBytes":"20"}}}}},"src/test/utils/Hevm.sol":{"Hevm":{"abi":[{"inputs":[{"internalType":"string[]","name":"","type":"string[]"}],"name":"ffi","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"roll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"c","type":"address"},{"internalType":"bytes32","name":"loc","type":"bytes32"},{"internalType":"bytes32","name":"val","type":"bytes32"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"warp","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"immutableReferences":{},"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"metadata":"{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"name\":\"ffi\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"roll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"c\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"loc\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"val\",\"type\":\"bytes32\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"warp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/test/utils/Hevm.sol\":\"Hevm\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":ds-test/=lib/ds-test/src/\"]},\"sources\":{\"src/test/utils/Hevm.sol\":{\"keccak256\":\"0xd477fc888e2bdbaf45c8babf175c93127478ae74543556ffebb9877a8dd823a9\",\"license\":\"Unlicense\",\"urls\":[\"bzz-raw://7fb2a52878484cea3793a92ae34b3a9f3e77f976eda7c7f91e2edb5b9ba38be3\",\"dweb:/ipfs/Qmf7JsG4uMjd7WX1h8rBPcpXv1m4mF3sdrr6VYzKj1SXUX\"]}},\"version\":1}","storageLayout":{"storage":[],"types":null}}}},"sources":{"lib/ds-test/src/test.sol":{"ast":{"absolutePath":"lib/ds-test/src/test.sol","exportedSymbols":{"DSTest":[2124]},"id":2125,"license":"GPL-3.0-or-later","nodeType":"SourceUnit","nodes":[{"id":445,"literals":["solidity",">=","0.4",".23"],"nodeType":"PragmaDirective","src":"689:25:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":2124,"linearizedBaseContracts":[2124],"name":"DSTest","nameLocation":"725:6:0","nodeType":"ContractDefinition","nodes":[{"anonymous":false,"id":449,"name":"log","nameLocation":"744:3:0","nodeType":"EventDefinition","parameters":{"id":448,"nodeType":"ParameterList","parameters":[{"constant":false,"id":447,"indexed":false,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":449,"src":"768:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":446,"name":"string","nodeType":"ElementaryTypeName","src":"768:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"767:8:0"},"src":"738:38:0"},{"anonymous":false,"id":453,"name":"logs","nameLocation":"787:4:0","nodeType":"EventDefinition","parameters":{"id":452,"nodeType":"ParameterList","parameters":[{"constant":false,"id":451,"indexed":false,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":453,"src":"811:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":450,"name":"bytes","nodeType":"ElementaryTypeName","src":"811:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"810:7:0"},"src":"781:37:0"},{"anonymous":false,"id":457,"name":"log_address","nameLocation":"830:11:0","nodeType":"EventDefinition","parameters":{"id":456,"nodeType":"ParameterList","parameters":[{"constant":false,"id":455,"indexed":false,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":457,"src":"854:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":454,"name":"address","nodeType":"ElementaryTypeName","src":"854:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"853:9:0"},"src":"824:39:0"},{"anonymous":false,"id":461,"name":"log_bytes32","nameLocation":"874:11:0","nodeType":"EventDefinition","parameters":{"id":460,"nodeType":"ParameterList","parameters":[{"constant":false,"id":459,"indexed":false,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":461,"src":"898:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":458,"name":"bytes32","nodeType":"ElementaryTypeName","src":"898:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"src":"897:9:0"},"src":"868:39:0"},{"anonymous":false,"id":465,"name":"log_int","nameLocation":"918:7:0","nodeType":"EventDefinition","parameters":{"id":464,"nodeType":"ParameterList","parameters":[{"constant":false,"id":463,"indexed":false,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":465,"src":"942:3:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":462,"name":"int","nodeType":"ElementaryTypeName","src":"942:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"}],"src":"941:5:0"},"src":"912:35:0"},{"anonymous":false,"id":469,"name":"log_uint","nameLocation":"958:8:0","nodeType":"EventDefinition","parameters":{"id":468,"nodeType":"ParameterList","parameters":[{"constant":false,"id":467,"indexed":false,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":469,"src":"982:4:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":466,"name":"uint","nodeType":"ElementaryTypeName","src":"982:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"981:6:0"},"src":"952:36:0"},{"anonymous":false,"id":473,"name":"log_bytes","nameLocation":"999:9:0","nodeType":"EventDefinition","parameters":{"id":472,"nodeType":"ParameterList","parameters":[{"constant":false,"id":471,"indexed":false,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":473,"src":"1023:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":470,"name":"bytes","nodeType":"ElementaryTypeName","src":"1023:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1022:7:0"},"src":"993:37:0"},{"anonymous":false,"id":477,"name":"log_string","nameLocation":"1041:10:0","nodeType":"EventDefinition","parameters":{"id":476,"nodeType":"ParameterList","parameters":[{"constant":false,"id":475,"indexed":false,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":477,"src":"1065:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":474,"name":"string","nodeType":"ElementaryTypeName","src":"1065:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1064:8:0"},"src":"1035:38:0"},{"anonymous":false,"id":483,"name":"log_named_address","nameLocation":"1085:17:0","nodeType":"EventDefinition","parameters":{"id":482,"nodeType":"ParameterList","parameters":[{"constant":false,"id":479,"indexed":false,"mutability":"mutable","name":"key","nameLocation":"1116:3:0","nodeType":"VariableDeclaration","scope":483,"src":"1109:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":478,"name":"string","nodeType":"ElementaryTypeName","src":"1109:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":481,"indexed":false,"mutability":"mutable","name":"val","nameLocation":"1129:3:0","nodeType":"VariableDeclaration","scope":483,"src":"1121:11:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":480,"name":"address","nodeType":"ElementaryTypeName","src":"1121:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1108:25:0"},"src":"1079:55:0"},{"anonymous":false,"id":489,"name":"log_named_bytes32","nameLocation":"1145:17:0","nodeType":"EventDefinition","parameters":{"id":488,"nodeType":"ParameterList","parameters":[{"constant":false,"id":485,"indexed":false,"mutability":"mutable","name":"key","nameLocation":"1176:3:0","nodeType":"VariableDeclaration","scope":489,"src":"1169:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":484,"name":"string","nodeType":"ElementaryTypeName","src":"1169:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":487,"indexed":false,"mutability":"mutable","name":"val","nameLocation":"1189:3:0","nodeType":"VariableDeclaration","scope":489,"src":"1181:11:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":486,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1181:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"src":"1168:25:0"},"src":"1139:55:0"},{"anonymous":false,"id":497,"name":"log_named_decimal_int","nameLocation":"1205:21:0","nodeType":"EventDefinition","parameters":{"id":496,"nodeType":"ParameterList","parameters":[{"constant":false,"id":491,"indexed":false,"mutability":"mutable","name":"key","nameLocation":"1236:3:0","nodeType":"VariableDeclaration","scope":497,"src":"1229:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":490,"name":"string","nodeType":"ElementaryTypeName","src":"1229:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":493,"indexed":false,"mutability":"mutable","name":"val","nameLocation":"1245:3:0","nodeType":"VariableDeclaration","scope":497,"src":"1241:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":492,"name":"int","nodeType":"ElementaryTypeName","src":"1241:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":495,"indexed":false,"mutability":"mutable","name":"decimals","nameLocation":"1255:8:0","nodeType":"VariableDeclaration","scope":497,"src":"1250:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":494,"name":"uint","nodeType":"ElementaryTypeName","src":"1250:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1228:36:0"},"src":"1199:66:0"},{"anonymous":false,"id":505,"name":"log_named_decimal_uint","nameLocation":"1276:22:0","nodeType":"EventDefinition","parameters":{"id":504,"nodeType":"ParameterList","parameters":[{"constant":false,"id":499,"indexed":false,"mutability":"mutable","name":"key","nameLocation":"1307:3:0","nodeType":"VariableDeclaration","scope":505,"src":"1300:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":498,"name":"string","nodeType":"ElementaryTypeName","src":"1300:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":501,"indexed":false,"mutability":"mutable","name":"val","nameLocation":"1317:3:0","nodeType":"VariableDeclaration","scope":505,"src":"1312:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":500,"name":"uint","nodeType":"ElementaryTypeName","src":"1312:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":503,"indexed":false,"mutability":"mutable","name":"decimals","nameLocation":"1327:8:0","nodeType":"VariableDeclaration","scope":505,"src":"1322:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":502,"name":"uint","nodeType":"ElementaryTypeName","src":"1322:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1299:37:0"},"src":"1270:67:0"},{"anonymous":false,"id":511,"name":"log_named_int","nameLocation":"1348:13:0","nodeType":"EventDefinition","parameters":{"id":510,"nodeType":"ParameterList","parameters":[{"constant":false,"id":507,"indexed":false,"mutability":"mutable","name":"key","nameLocation":"1379:3:0","nodeType":"VariableDeclaration","scope":511,"src":"1372:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":506,"name":"string","nodeType":"ElementaryTypeName","src":"1372:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":509,"indexed":false,"mutability":"mutable","name":"val","nameLocation":"1388:3:0","nodeType":"VariableDeclaration","scope":511,"src":"1384:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":508,"name":"int","nodeType":"ElementaryTypeName","src":"1384:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"}],"src":"1371:21:0"},"src":"1342:51:0"},{"anonymous":false,"id":517,"name":"log_named_uint","nameLocation":"1404:14:0","nodeType":"EventDefinition","parameters":{"id":516,"nodeType":"ParameterList","parameters":[{"constant":false,"id":513,"indexed":false,"mutability":"mutable","name":"key","nameLocation":"1435:3:0","nodeType":"VariableDeclaration","scope":517,"src":"1428:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":512,"name":"string","nodeType":"ElementaryTypeName","src":"1428:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":515,"indexed":false,"mutability":"mutable","name":"val","nameLocation":"1445:3:0","nodeType":"VariableDeclaration","scope":517,"src":"1440:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":514,"name":"uint","nodeType":"ElementaryTypeName","src":"1440:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1427:22:0"},"src":"1398:52:0"},{"anonymous":false,"id":523,"name":"log_named_bytes","nameLocation":"1461:15:0","nodeType":"EventDefinition","parameters":{"id":522,"nodeType":"ParameterList","parameters":[{"constant":false,"id":519,"indexed":false,"mutability":"mutable","name":"key","nameLocation":"1492:3:0","nodeType":"VariableDeclaration","scope":523,"src":"1485:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":518,"name":"string","nodeType":"ElementaryTypeName","src":"1485:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":521,"indexed":false,"mutability":"mutable","name":"val","nameLocation":"1503:3:0","nodeType":"VariableDeclaration","scope":523,"src":"1497:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":520,"name":"bytes","nodeType":"ElementaryTypeName","src":"1497:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1484:23:0"},"src":"1455:53:0"},{"anonymous":false,"id":529,"name":"log_named_string","nameLocation":"1519:16:0","nodeType":"EventDefinition","parameters":{"id":528,"nodeType":"ParameterList","parameters":[{"constant":false,"id":525,"indexed":false,"mutability":"mutable","name":"key","nameLocation":"1550:3:0","nodeType":"VariableDeclaration","scope":529,"src":"1543:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":524,"name":"string","nodeType":"ElementaryTypeName","src":"1543:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":527,"indexed":false,"mutability":"mutable","name":"val","nameLocation":"1562:3:0","nodeType":"VariableDeclaration","scope":529,"src":"1555:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":526,"name":"string","nodeType":"ElementaryTypeName","src":"1555:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1542:24:0"},"src":"1513:54:0"},{"constant":false,"functionSelector":"fa7626d4","id":532,"mutability":"mutable","name":"IS_TEST","nameLocation":"1585:7:0","nodeType":"VariableDeclaration","scope":2124,"src":"1573:26:0","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":530,"name":"bool","nodeType":"ElementaryTypeName","src":"1573:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"value":{"hexValue":"74727565","id":531,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"1595:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"true"},"visibility":"public"},{"constant":false,"functionSelector":"ba414fa6","id":534,"mutability":"mutable","name":"failed","nameLocation":"1617:6:0","nodeType":"VariableDeclaration","scope":2124,"src":"1605:18:0","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":533,"name":"bool","nodeType":"ElementaryTypeName","src":"1605:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"public"},{"constant":true,"id":551,"mutability":"constant","name":"HEVM_ADDRESS","nameLocation":"1647:12:0","nodeType":"VariableDeclaration","scope":2124,"src":"1630:104:0","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":535,"name":"address","nodeType":"ElementaryTypeName","src":"1630:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":545,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1712:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":544,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"1702:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":546,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1702:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":543,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1694:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":542,"name":"uint256","nodeType":"ElementaryTypeName","src":"1694:7:0","typeDescriptions":{}}},"id":547,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1694:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":541,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1686:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":540,"name":"uint160","nodeType":"ElementaryTypeName","src":"1686:7:0","typeDescriptions":{}}},"id":548,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1686:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":539,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1678:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes20_$","typeString":"type(bytes20)"},"typeName":{"id":538,"name":"bytes20","nodeType":"ElementaryTypeName","src":"1678:7:0","typeDescriptions":{}}},"id":549,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1678:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes20","typeString":"bytes20"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes20","typeString":"bytes20"}],"id":537,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1670:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":536,"name":"address","nodeType":"ElementaryTypeName","src":"1670:7:0","typeDescriptions":{}}},"id":550,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1670:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"body":{"id":554,"nodeType":"Block","src":"1762:6:0","statements":[{"id":553,"nodeType":"PlaceholderStatement","src":"1764:1:0"}]},"id":555,"name":"mayRevert","nameLocation":"1750:9:0","nodeType":"ModifierDefinition","parameters":{"id":552,"nodeType":"ParameterList","parameters":[],"src":"1759:2:0"},"src":"1741:27:0","virtual":false,"visibility":"internal"},{"body":{"id":560,"nodeType":"Block","src":"1806:6:0","statements":[{"id":559,"nodeType":"PlaceholderStatement","src":"1808:1:0"}]},"id":561,"name":"testopts","nameLocation":"1782:8:0","nodeType":"ModifierDefinition","parameters":{"id":558,"nodeType":"ParameterList","parameters":[{"constant":false,"id":557,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":561,"src":"1791:13:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":556,"name":"string","nodeType":"ElementaryTypeName","src":"1791:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1790:15:0"},"src":"1773:39:0","virtual":false,"visibility":"internal"},{"body":{"id":568,"nodeType":"Block","src":"1843:30:0","statements":[{"expression":{"id":566,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":564,"name":"failed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":534,"src":"1853:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"74727565","id":565,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"1862:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"true"},"src":"1853:13:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":567,"nodeType":"ExpressionStatement","src":"1853:13:0"}]},"id":569,"implemented":true,"kind":"function","modifiers":[],"name":"fail","nameLocation":"1827:4:0","nodeType":"FunctionDefinition","parameters":{"id":562,"nodeType":"ParameterList","parameters":[],"src":"1831:2:0"},"returnParameters":{"id":563,"nodeType":"ParameterList","parameters":[],"src":"1843:0:0"},"scope":2124,"src":"1818:55:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":589,"nodeType":"Block","src":"1899:141:0","statements":[{"assignments":[572],"declarations":[{"constant":false,"id":572,"mutability":"mutable","name":"startGas","nameLocation":"1914:8:0","nodeType":"VariableDeclaration","scope":589,"src":"1909:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":571,"name":"uint","nodeType":"ElementaryTypeName","src":"1909:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":575,"initialValue":{"arguments":[],"expression":{"argumentTypes":[],"id":573,"name":"gasleft","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-7,"src":"1925:7:0","typeDescriptions":{"typeIdentifier":"t_function_gasleft_view$__$returns$_t_uint256_$","typeString":"function () view returns (uint256)"}},"id":574,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1925:9:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1909:25:0"},{"id":576,"nodeType":"PlaceholderStatement","src":"1944:1:0"},{"assignments":[578],"declarations":[{"constant":false,"id":578,"mutability":"mutable","name":"endGas","nameLocation":"1960:6:0","nodeType":"VariableDeclaration","scope":589,"src":"1955:11:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":577,"name":"uint","nodeType":"ElementaryTypeName","src":"1955:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":581,"initialValue":{"arguments":[],"expression":{"argumentTypes":[],"id":579,"name":"gasleft","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-7,"src":"1969:7:0","typeDescriptions":{"typeIdentifier":"t_function_gasleft_view$__$returns$_t_uint256_$","typeString":"function () view returns (uint256)"}},"id":580,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1969:9:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1955:23:0"},{"eventCall":{"arguments":[{"hexValue":"676173","id":583,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2008:5:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4498c2139ad6cf2beef3ae7bec34c4856d471c8680dfd28d553f117df74df6b7","typeString":"literal_string \"gas\""},"value":"gas"},{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":586,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":584,"name":"startGas","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":572,"src":"2015:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"-","rightExpression":{"id":585,"name":"endGas","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":578,"src":"2026:6:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"2015:17:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4498c2139ad6cf2beef3ae7bec34c4856d471c8680dfd28d553f117df74df6b7","typeString":"literal_string \"gas\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":582,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"1993:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":587,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1993:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":588,"nodeType":"EmitStatement","src":"1988:45:0"}]},"id":590,"name":"logs_gas","nameLocation":"1888:8:0","nodeType":"ModifierDefinition","parameters":{"id":570,"nodeType":"ParameterList","parameters":[],"src":"1896:2:0"},"src":"1879:161:0","virtual":false,"visibility":"internal"},{"body":{"id":606,"nodeType":"Block","src":"2091:112:0","statements":[{"condition":{"id":596,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"!","prefix":true,"src":"2105:10:0","subExpression":{"id":595,"name":"condition","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":592,"src":"2106:9:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":605,"nodeType":"IfStatement","src":"2101:96:0","trueBody":{"id":604,"nodeType":"Block","src":"2117:80:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a20417373657274696f6e204661696c6564","id":598,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2140:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_cc8bd7d7034d6f139e4d0b1fc61bcb3025672e801833991d94fa7390aceb1687","typeString":"literal_string \"Error: Assertion Failed\""},"value":"Error: Assertion Failed"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_cc8bd7d7034d6f139e4d0b1fc61bcb3025672e801833991d94fa7390aceb1687","typeString":"literal_string \"Error: Assertion Failed\""}],"id":597,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"2136:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":599,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2136:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":600,"nodeType":"EmitStatement","src":"2131:35:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":601,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"2180:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":602,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2180:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":603,"nodeType":"ExpressionStatement","src":"2180:6:0"}]}}]},"id":607,"implemented":true,"kind":"function","modifiers":[],"name":"assertTrue","nameLocation":"2055:10:0","nodeType":"FunctionDefinition","parameters":{"id":593,"nodeType":"ParameterList","parameters":[{"constant":false,"id":592,"mutability":"mutable","name":"condition","nameLocation":"2071:9:0","nodeType":"VariableDeclaration","scope":607,"src":"2066:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":591,"name":"bool","nodeType":"ElementaryTypeName","src":"2066:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"2065:16:0"},"returnParameters":{"id":594,"nodeType":"ParameterList","parameters":[],"src":"2091:0:0"},"scope":2124,"src":"2046:157:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":627,"nodeType":"Block","src":"2273:127:0","statements":[{"condition":{"id":615,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"!","prefix":true,"src":"2287:10:0","subExpression":{"id":614,"name":"condition","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":609,"src":"2288:9:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":626,"nodeType":"IfStatement","src":"2283:111:0","trueBody":{"id":625,"nodeType":"Block","src":"2299:95:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":617,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2335:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":618,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":611,"src":"2344:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":616,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"2318:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2318:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":620,"nodeType":"EmitStatement","src":"2313:35:0"},{"expression":{"arguments":[{"id":622,"name":"condition","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":609,"src":"2373:9:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":621,"name":"assertTrue","nodeType":"Identifier","overloadedDeclarations":[607,628],"referencedDeclaration":607,"src":"2362:10:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_bool_$returns$__$","typeString":"function (bool)"}},"id":623,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2362:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":624,"nodeType":"ExpressionStatement","src":"2362:21:0"}]}}]},"id":628,"implemented":true,"kind":"function","modifiers":[],"name":"assertTrue","nameLocation":"2218:10:0","nodeType":"FunctionDefinition","parameters":{"id":612,"nodeType":"ParameterList","parameters":[{"constant":false,"id":609,"mutability":"mutable","name":"condition","nameLocation":"2234:9:0","nodeType":"VariableDeclaration","scope":628,"src":"2229:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":608,"name":"bool","nodeType":"ElementaryTypeName","src":"2229:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"},{"constant":false,"id":611,"mutability":"mutable","name":"err","nameLocation":"2259:3:0","nodeType":"VariableDeclaration","scope":628,"src":"2245:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":610,"name":"string","nodeType":"ElementaryTypeName","src":"2245:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2228:35:0"},"returnParameters":{"id":613,"nodeType":"ParameterList","parameters":[],"src":"2273:0:0"},"scope":2124,"src":"2209:191:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":657,"nodeType":"Block","src":"2455:228:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":637,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":635,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":630,"src":"2469:1:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":636,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":632,"src":"2474:1:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"2469:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":656,"nodeType":"IfStatement","src":"2465:212:0","trueBody":{"id":655,"nodeType":"Block","src":"2477:200:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b616464726573735d","id":639,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2500:39:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_9fc6ddd126630392f6812bf6b1418b5ec062ae84acc54ee474317255c7d57017","typeString":"literal_string \"Error: a == b not satisfied [address]\""},"value":"Error: a == b not satisfied [address]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_9fc6ddd126630392f6812bf6b1418b5ec062ae84acc54ee474317255c7d57017","typeString":"literal_string \"Error: a == b not satisfied [address]\""}],"id":638,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"2496:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":640,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2496:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":641,"nodeType":"EmitStatement","src":"2491:49:0"},{"eventCall":{"arguments":[{"hexValue":"20204578706563746564","id":643,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2577:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},"value":" Expected"},{"id":644,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":632,"src":"2591:1:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},{"typeIdentifier":"t_address","typeString":"address"}],"id":642,"name":"log_named_address","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":483,"src":"2559:17:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address)"}},"id":645,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2559:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":646,"nodeType":"EmitStatement","src":"2554:39:0"},{"eventCall":{"arguments":[{"hexValue":"2020202041637475616c","id":648,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2630:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},"value":" Actual"},{"id":649,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":630,"src":"2644:1:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},{"typeIdentifier":"t_address","typeString":"address"}],"id":647,"name":"log_named_address","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":483,"src":"2612:17:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address)"}},"id":650,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2612:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":651,"nodeType":"EmitStatement","src":"2607:39:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":652,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"2660:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2660:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":654,"nodeType":"ExpressionStatement","src":"2660:6:0"}]}}]},"id":658,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"2415:8:0","nodeType":"FunctionDefinition","parameters":{"id":633,"nodeType":"ParameterList","parameters":[{"constant":false,"id":630,"mutability":"mutable","name":"a","nameLocation":"2432:1:0","nodeType":"VariableDeclaration","scope":658,"src":"2424:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":629,"name":"address","nodeType":"ElementaryTypeName","src":"2424:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":632,"mutability":"mutable","name":"b","nameLocation":"2443:1:0","nodeType":"VariableDeclaration","scope":658,"src":"2435:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":631,"name":"address","nodeType":"ElementaryTypeName","src":"2435:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2423:22:0"},"returnParameters":{"id":634,"nodeType":"ParameterList","parameters":[],"src":"2455:0:0"},"scope":2124,"src":"2406:277:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":682,"nodeType":"Block","src":"2756:117:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":669,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":667,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":660,"src":"2770:1:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":668,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":662,"src":"2775:1:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"2770:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":681,"nodeType":"IfStatement","src":"2766:101:0","trueBody":{"id":680,"nodeType":"Block","src":"2778:89:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":671,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2815:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":672,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":664,"src":"2824:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":670,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"2797:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":673,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2797:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":674,"nodeType":"EmitStatement","src":"2792:36:0"},{"expression":{"arguments":[{"id":676,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":660,"src":"2851:1:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"id":677,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":662,"src":"2854:1:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_address","typeString":"address"}],"id":675,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":658,"src":"2842:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_address_$_t_address_$returns$__$","typeString":"function (address,address)"}},"id":678,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2842:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":679,"nodeType":"ExpressionStatement","src":"2842:14:0"}]}}]},"id":683,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"2697:8:0","nodeType":"FunctionDefinition","parameters":{"id":665,"nodeType":"ParameterList","parameters":[{"constant":false,"id":660,"mutability":"mutable","name":"a","nameLocation":"2714:1:0","nodeType":"VariableDeclaration","scope":683,"src":"2706:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":659,"name":"address","nodeType":"ElementaryTypeName","src":"2706:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":662,"mutability":"mutable","name":"b","nameLocation":"2725:1:0","nodeType":"VariableDeclaration","scope":683,"src":"2717:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":661,"name":"address","nodeType":"ElementaryTypeName","src":"2717:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":664,"mutability":"mutable","name":"err","nameLocation":"2742:3:0","nodeType":"VariableDeclaration","scope":683,"src":"2728:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":663,"name":"string","nodeType":"ElementaryTypeName","src":"2728:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2705:41:0"},"returnParameters":{"id":666,"nodeType":"ParameterList","parameters":[],"src":"2756:0:0"},"scope":2124,"src":"2688:185:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":712,"nodeType":"Block","src":"2928:228:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"id":692,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":690,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":685,"src":"2942:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":691,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":687,"src":"2947:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"src":"2942:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":711,"nodeType":"IfStatement","src":"2938:212:0","trueBody":{"id":710,"nodeType":"Block","src":"2950:200:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b627974657333325d","id":694,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2973:39:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6605dedc99dd4e0a76d4678a99cc6956499fe2b523ca6525b248ca3582cef3ef","typeString":"literal_string \"Error: a == b not satisfied [bytes32]\""},"value":"Error: a == b not satisfied [bytes32]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6605dedc99dd4e0a76d4678a99cc6956499fe2b523ca6525b248ca3582cef3ef","typeString":"literal_string \"Error: a == b not satisfied [bytes32]\""}],"id":693,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"2969:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":695,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2969:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":696,"nodeType":"EmitStatement","src":"2964:49:0"},{"eventCall":{"arguments":[{"hexValue":"20204578706563746564","id":698,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3050:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},"value":" Expected"},{"id":699,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":687,"src":"3064:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":697,"name":"log_named_bytes32","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":489,"src":"3032:17:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes32_$returns$__$","typeString":"function (string memory,bytes32)"}},"id":700,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3032:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":701,"nodeType":"EmitStatement","src":"3027:39:0"},{"eventCall":{"arguments":[{"hexValue":"2020202041637475616c","id":703,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3103:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},"value":" Actual"},{"id":704,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":685,"src":"3117:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":702,"name":"log_named_bytes32","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":489,"src":"3085:17:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes32_$returns$__$","typeString":"function (string memory,bytes32)"}},"id":705,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3085:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":706,"nodeType":"EmitStatement","src":"3080:39:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":707,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"3133:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":708,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3133:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":709,"nodeType":"ExpressionStatement","src":"3133:6:0"}]}}]},"id":713,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"2888:8:0","nodeType":"FunctionDefinition","parameters":{"id":688,"nodeType":"ParameterList","parameters":[{"constant":false,"id":685,"mutability":"mutable","name":"a","nameLocation":"2905:1:0","nodeType":"VariableDeclaration","scope":713,"src":"2897:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":684,"name":"bytes32","nodeType":"ElementaryTypeName","src":"2897:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":687,"mutability":"mutable","name":"b","nameLocation":"2916:1:0","nodeType":"VariableDeclaration","scope":713,"src":"2908:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":686,"name":"bytes32","nodeType":"ElementaryTypeName","src":"2908:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"src":"2896:22:0"},"returnParameters":{"id":689,"nodeType":"ParameterList","parameters":[],"src":"2928:0:0"},"scope":2124,"src":"2879:277:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":737,"nodeType":"Block","src":"3229:117:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"id":724,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":722,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"3243:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":723,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":717,"src":"3248:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"src":"3243:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":736,"nodeType":"IfStatement","src":"3239:101:0","trueBody":{"id":735,"nodeType":"Block","src":"3251:89:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":726,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3288:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":727,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":719,"src":"3297:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":725,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"3270:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":728,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3270:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":729,"nodeType":"EmitStatement","src":"3265:36:0"},{"expression":{"arguments":[{"id":731,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"3324:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":732,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":717,"src":"3327:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":730,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":713,"src":"3315:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_bytes32_$_t_bytes32_$returns$__$","typeString":"function (bytes32,bytes32)"}},"id":733,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3315:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":734,"nodeType":"ExpressionStatement","src":"3315:14:0"}]}}]},"id":738,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"3170:8:0","nodeType":"FunctionDefinition","parameters":{"id":720,"nodeType":"ParameterList","parameters":[{"constant":false,"id":715,"mutability":"mutable","name":"a","nameLocation":"3187:1:0","nodeType":"VariableDeclaration","scope":738,"src":"3179:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":714,"name":"bytes32","nodeType":"ElementaryTypeName","src":"3179:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":717,"mutability":"mutable","name":"b","nameLocation":"3198:1:0","nodeType":"VariableDeclaration","scope":738,"src":"3190:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":716,"name":"bytes32","nodeType":"ElementaryTypeName","src":"3190:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":719,"mutability":"mutable","name":"err","nameLocation":"3215:3:0","nodeType":"VariableDeclaration","scope":738,"src":"3201:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":718,"name":"string","nodeType":"ElementaryTypeName","src":"3201:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"3178:41:0"},"returnParameters":{"id":721,"nodeType":"ParameterList","parameters":[],"src":"3229:0:0"},"scope":2124,"src":"3161:185:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":750,"nodeType":"Block","src":"3402:31:0","statements":[{"expression":{"arguments":[{"id":746,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":740,"src":"3421:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":747,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":742,"src":"3424:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":745,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":713,"src":"3412:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_bytes32_$_t_bytes32_$returns$__$","typeString":"function (bytes32,bytes32)"}},"id":748,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3412:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":749,"nodeType":"ExpressionStatement","src":"3412:14:0"}]},"id":751,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq32","nameLocation":"3360:10:0","nodeType":"FunctionDefinition","parameters":{"id":743,"nodeType":"ParameterList","parameters":[{"constant":false,"id":740,"mutability":"mutable","name":"a","nameLocation":"3379:1:0","nodeType":"VariableDeclaration","scope":751,"src":"3371:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":739,"name":"bytes32","nodeType":"ElementaryTypeName","src":"3371:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":742,"mutability":"mutable","name":"b","nameLocation":"3390:1:0","nodeType":"VariableDeclaration","scope":751,"src":"3382:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":741,"name":"bytes32","nodeType":"ElementaryTypeName","src":"3382:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"src":"3370:22:0"},"returnParameters":{"id":744,"nodeType":"ParameterList","parameters":[],"src":"3402:0:0"},"scope":2124,"src":"3351:82:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":766,"nodeType":"Block","src":"3508:36:0","statements":[{"expression":{"arguments":[{"id":761,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":753,"src":"3527:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":762,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":755,"src":"3530:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":763,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":757,"src":"3533:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":760,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":738,"src":"3518:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_bytes32_$_t_bytes32_$_t_string_memory_ptr_$returns$__$","typeString":"function (bytes32,bytes32,string memory)"}},"id":764,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3518:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":765,"nodeType":"ExpressionStatement","src":"3518:19:0"}]},"id":767,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq32","nameLocation":"3447:10:0","nodeType":"FunctionDefinition","parameters":{"id":758,"nodeType":"ParameterList","parameters":[{"constant":false,"id":753,"mutability":"mutable","name":"a","nameLocation":"3466:1:0","nodeType":"VariableDeclaration","scope":767,"src":"3458:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":752,"name":"bytes32","nodeType":"ElementaryTypeName","src":"3458:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":755,"mutability":"mutable","name":"b","nameLocation":"3477:1:0","nodeType":"VariableDeclaration","scope":767,"src":"3469:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":754,"name":"bytes32","nodeType":"ElementaryTypeName","src":"3469:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":757,"mutability":"mutable","name":"err","nameLocation":"3494:3:0","nodeType":"VariableDeclaration","scope":767,"src":"3480:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":756,"name":"string","nodeType":"ElementaryTypeName","src":"3480:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"3457:41:0"},"returnParameters":{"id":759,"nodeType":"ParameterList","parameters":[],"src":"3508:0:0"},"scope":2124,"src":"3438:106:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":796,"nodeType":"Block","src":"3591:216:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":776,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":774,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":769,"src":"3605:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":775,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":771,"src":"3610:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"3605:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":795,"nodeType":"IfStatement","src":"3601:200:0","trueBody":{"id":794,"nodeType":"Block","src":"3613:188:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b696e745d","id":778,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3636:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c510d1b16a7b86013fe25431f855bed96290957b4566f7ab53d5bf1855a3a81","typeString":"literal_string \"Error: a == b not satisfied [int]\""},"value":"Error: a == b not satisfied [int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c510d1b16a7b86013fe25431f855bed96290957b4566f7ab53d5bf1855a3a81","typeString":"literal_string \"Error: a == b not satisfied [int]\""}],"id":777,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"3632:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":779,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3632:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":780,"nodeType":"EmitStatement","src":"3627:45:0"},{"eventCall":{"arguments":[{"hexValue":"20204578706563746564","id":782,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3705:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},"value":" Expected"},{"id":783,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":771,"src":"3719:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":781,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"3691:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":784,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3691:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":785,"nodeType":"EmitStatement","src":"3686:35:0"},{"eventCall":{"arguments":[{"hexValue":"2020202041637475616c","id":787,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3754:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},"value":" Actual"},{"id":788,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":769,"src":"3768:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":786,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"3740:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":789,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3740:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":790,"nodeType":"EmitStatement","src":"3735:35:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":791,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"3784:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":792,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3784:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":793,"nodeType":"ExpressionStatement","src":"3784:6:0"}]}}]},"id":797,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"3559:8:0","nodeType":"FunctionDefinition","parameters":{"id":772,"nodeType":"ParameterList","parameters":[{"constant":false,"id":769,"mutability":"mutable","name":"a","nameLocation":"3572:1:0","nodeType":"VariableDeclaration","scope":797,"src":"3568:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":768,"name":"int","nodeType":"ElementaryTypeName","src":"3568:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":771,"mutability":"mutable","name":"b","nameLocation":"3579:1:0","nodeType":"VariableDeclaration","scope":797,"src":"3575:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":770,"name":"int","nodeType":"ElementaryTypeName","src":"3575:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"}],"src":"3567:14:0"},"returnParameters":{"id":773,"nodeType":"ParameterList","parameters":[],"src":"3591:0:0"},"scope":2124,"src":"3550:257:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":821,"nodeType":"Block","src":"3872:116:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":808,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":806,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":799,"src":"3886:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":807,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":801,"src":"3891:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"3886:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":820,"nodeType":"IfStatement","src":"3882:100:0","trueBody":{"id":819,"nodeType":"Block","src":"3894:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":810,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3930:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":811,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":803,"src":"3939:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":809,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"3913:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":812,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3913:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":813,"nodeType":"EmitStatement","src":"3908:35:0"},{"expression":{"arguments":[{"id":815,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":799,"src":"3966:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":816,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":801,"src":"3969:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":814,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":797,"src":"3957:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$returns$__$","typeString":"function (int256,int256)"}},"id":817,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3957:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":818,"nodeType":"ExpressionStatement","src":"3957:14:0"}]}}]},"id":822,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"3821:8:0","nodeType":"FunctionDefinition","parameters":{"id":804,"nodeType":"ParameterList","parameters":[{"constant":false,"id":799,"mutability":"mutable","name":"a","nameLocation":"3834:1:0","nodeType":"VariableDeclaration","scope":822,"src":"3830:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":798,"name":"int","nodeType":"ElementaryTypeName","src":"3830:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":801,"mutability":"mutable","name":"b","nameLocation":"3841:1:0","nodeType":"VariableDeclaration","scope":822,"src":"3837:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":800,"name":"int","nodeType":"ElementaryTypeName","src":"3837:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":803,"mutability":"mutable","name":"err","nameLocation":"3858:3:0","nodeType":"VariableDeclaration","scope":822,"src":"3844:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":802,"name":"string","nodeType":"ElementaryTypeName","src":"3844:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"3829:33:0"},"returnParameters":{"id":805,"nodeType":"ParameterList","parameters":[],"src":"3872:0:0"},"scope":2124,"src":"3812:176:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":851,"nodeType":"Block","src":"4036:219:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":831,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":829,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":824,"src":"4050:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":830,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":826,"src":"4055:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"4050:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":850,"nodeType":"IfStatement","src":"4046:203:0","trueBody":{"id":849,"nodeType":"Block","src":"4058:191:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b75696e745d","id":833,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4081:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3bb05d3ba160a011999668447ff4a7cdd52bf87aeb1d7b9b284ef23b37a2b183","typeString":"literal_string \"Error: a == b not satisfied [uint]\""},"value":"Error: a == b not satisfied [uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3bb05d3ba160a011999668447ff4a7cdd52bf87aeb1d7b9b284ef23b37a2b183","typeString":"literal_string \"Error: a == b not satisfied [uint]\""}],"id":832,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"4077:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":834,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4077:41:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":835,"nodeType":"EmitStatement","src":"4072:46:0"},{"eventCall":{"arguments":[{"hexValue":"20204578706563746564","id":837,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4152:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},"value":" Expected"},{"id":838,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":826,"src":"4166:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":836,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"4137:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":839,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4137:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":840,"nodeType":"EmitStatement","src":"4132:36:0"},{"eventCall":{"arguments":[{"hexValue":"2020202041637475616c","id":842,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4202:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},"value":" Actual"},{"id":843,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":824,"src":"4216:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":841,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"4187:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":844,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4187:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":845,"nodeType":"EmitStatement","src":"4182:36:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":846,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"4232:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":847,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4232:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":848,"nodeType":"ExpressionStatement","src":"4232:6:0"}]}}]},"id":852,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"4002:8:0","nodeType":"FunctionDefinition","parameters":{"id":827,"nodeType":"ParameterList","parameters":[{"constant":false,"id":824,"mutability":"mutable","name":"a","nameLocation":"4016:1:0","nodeType":"VariableDeclaration","scope":852,"src":"4011:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":823,"name":"uint","nodeType":"ElementaryTypeName","src":"4011:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":826,"mutability":"mutable","name":"b","nameLocation":"4024:1:0","nodeType":"VariableDeclaration","scope":852,"src":"4019:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":825,"name":"uint","nodeType":"ElementaryTypeName","src":"4019:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"4010:16:0"},"returnParameters":{"id":828,"nodeType":"ParameterList","parameters":[],"src":"4036:0:0"},"scope":2124,"src":"3993:262:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":876,"nodeType":"Block","src":"4322:116:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":863,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":861,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":854,"src":"4336:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":862,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":856,"src":"4341:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"4336:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":875,"nodeType":"IfStatement","src":"4332:100:0","trueBody":{"id":874,"nodeType":"Block","src":"4344:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":865,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4380:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":866,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":858,"src":"4389:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":864,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"4363:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":867,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4363:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":868,"nodeType":"EmitStatement","src":"4358:35:0"},{"expression":{"arguments":[{"id":870,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":854,"src":"4416:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":871,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":856,"src":"4419:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":869,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":852,"src":"4407:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256)"}},"id":872,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4407:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":873,"nodeType":"ExpressionStatement","src":"4407:14:0"}]}}]},"id":877,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"4269:8:0","nodeType":"FunctionDefinition","parameters":{"id":859,"nodeType":"ParameterList","parameters":[{"constant":false,"id":854,"mutability":"mutable","name":"a","nameLocation":"4283:1:0","nodeType":"VariableDeclaration","scope":877,"src":"4278:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":853,"name":"uint","nodeType":"ElementaryTypeName","src":"4278:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":856,"mutability":"mutable","name":"b","nameLocation":"4291:1:0","nodeType":"VariableDeclaration","scope":877,"src":"4286:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":855,"name":"uint","nodeType":"ElementaryTypeName","src":"4286:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":858,"mutability":"mutable","name":"err","nameLocation":"4308:3:0","nodeType":"VariableDeclaration","scope":877,"src":"4294:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":857,"name":"string","nodeType":"ElementaryTypeName","src":"4294:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"4277:35:0"},"returnParameters":{"id":860,"nodeType":"ParameterList","parameters":[],"src":"4322:0:0"},"scope":2124,"src":"4260:178:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":910,"nodeType":"Block","src":"4506:260:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":888,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":886,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":879,"src":"4520:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":887,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":881,"src":"4525:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"4520:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":909,"nodeType":"IfStatement","src":"4516:244:0","trueBody":{"id":908,"nodeType":"Block","src":"4528:232:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b646563696d616c20696e745d","id":890,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4551:43:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3ee6ef9b326324a79dedc7af5585ef9f689364368b4e76dd3a37559719a19fe6","typeString":"literal_string \"Error: a == b not satisfied [decimal int]\""},"value":"Error: a == b not satisfied [decimal int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3ee6ef9b326324a79dedc7af5585ef9f689364368b4e76dd3a37559719a19fe6","typeString":"literal_string \"Error: a == b not satisfied [decimal int]\""}],"id":889,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"4547:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":891,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4547:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":892,"nodeType":"EmitStatement","src":"4542:53:0"},{"eventCall":{"arguments":[{"hexValue":"20204578706563746564","id":894,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4636:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},"value":" Expected"},{"id":895,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":881,"src":"4650:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":896,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":883,"src":"4653:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":893,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"4614:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":897,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4614:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":898,"nodeType":"EmitStatement","src":"4609:53:0"},{"eventCall":{"arguments":[{"hexValue":"2020202041637475616c","id":900,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4703:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},"value":" Actual"},{"id":901,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":879,"src":"4717:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":902,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":883,"src":"4720:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":899,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"4681:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":903,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4681:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":904,"nodeType":"EmitStatement","src":"4676:53:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":905,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"4743:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":906,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4743:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":907,"nodeType":"ExpressionStatement","src":"4743:6:0"}]}}]},"id":911,"implemented":true,"kind":"function","modifiers":[],"name":"assertEqDecimal","nameLocation":"4452:15:0","nodeType":"FunctionDefinition","parameters":{"id":884,"nodeType":"ParameterList","parameters":[{"constant":false,"id":879,"mutability":"mutable","name":"a","nameLocation":"4472:1:0","nodeType":"VariableDeclaration","scope":911,"src":"4468:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":878,"name":"int","nodeType":"ElementaryTypeName","src":"4468:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":881,"mutability":"mutable","name":"b","nameLocation":"4479:1:0","nodeType":"VariableDeclaration","scope":911,"src":"4475:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":880,"name":"int","nodeType":"ElementaryTypeName","src":"4475:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":883,"mutability":"mutable","name":"decimals","nameLocation":"4487:8:0","nodeType":"VariableDeclaration","scope":911,"src":"4482:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":882,"name":"uint","nodeType":"ElementaryTypeName","src":"4482:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"4467:29:0"},"returnParameters":{"id":885,"nodeType":"ParameterList","parameters":[],"src":"4506:0:0"},"scope":2124,"src":"4443:323:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":938,"nodeType":"Block","src":"4853:133:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":924,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":922,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":913,"src":"4867:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":923,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":915,"src":"4872:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"4867:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":937,"nodeType":"IfStatement","src":"4863:117:0","trueBody":{"id":936,"nodeType":"Block","src":"4875:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":926,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4911:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":927,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":919,"src":"4920:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":925,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"4894:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":928,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4894:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":929,"nodeType":"EmitStatement","src":"4889:35:0"},{"expression":{"arguments":[{"id":931,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":913,"src":"4954:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":932,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":915,"src":"4957:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":933,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":917,"src":"4960:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":930,"name":"assertEqDecimal","nodeType":"Identifier","overloadedDeclarations":[911,939,973,1001],"referencedDeclaration":911,"src":"4938:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (int256,int256,uint256)"}},"id":934,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4938:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":935,"nodeType":"ExpressionStatement","src":"4938:31:0"}]}}]},"id":939,"implemented":true,"kind":"function","modifiers":[],"name":"assertEqDecimal","nameLocation":"4780:15:0","nodeType":"FunctionDefinition","parameters":{"id":920,"nodeType":"ParameterList","parameters":[{"constant":false,"id":913,"mutability":"mutable","name":"a","nameLocation":"4800:1:0","nodeType":"VariableDeclaration","scope":939,"src":"4796:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":912,"name":"int","nodeType":"ElementaryTypeName","src":"4796:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":915,"mutability":"mutable","name":"b","nameLocation":"4807:1:0","nodeType":"VariableDeclaration","scope":939,"src":"4803:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":914,"name":"int","nodeType":"ElementaryTypeName","src":"4803:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":917,"mutability":"mutable","name":"decimals","nameLocation":"4815:8:0","nodeType":"VariableDeclaration","scope":939,"src":"4810:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":916,"name":"uint","nodeType":"ElementaryTypeName","src":"4810:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":919,"mutability":"mutable","name":"err","nameLocation":"4839:3:0","nodeType":"VariableDeclaration","scope":939,"src":"4825:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":918,"name":"string","nodeType":"ElementaryTypeName","src":"4825:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"4795:48:0"},"returnParameters":{"id":921,"nodeType":"ParameterList","parameters":[],"src":"4853:0:0"},"scope":2124,"src":"4771:215:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":972,"nodeType":"Block","src":"5056:263:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":950,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":948,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":941,"src":"5070:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":949,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":943,"src":"5075:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"5070:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":971,"nodeType":"IfStatement","src":"5066:247:0","trueBody":{"id":970,"nodeType":"Block","src":"5078:235:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b646563696d616c2075696e745d","id":952,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5101:44:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_acd59a69b2dc4bcee2d5b2a205a178a5eace192e68808cc4db1cea91cdc48141","typeString":"literal_string \"Error: a == b not satisfied [decimal uint]\""},"value":"Error: a == b not satisfied [decimal uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_acd59a69b2dc4bcee2d5b2a205a178a5eace192e68808cc4db1cea91cdc48141","typeString":"literal_string \"Error: a == b not satisfied [decimal uint]\""}],"id":951,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"5097:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":953,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5097:49:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":954,"nodeType":"EmitStatement","src":"5092:54:0"},{"eventCall":{"arguments":[{"hexValue":"20204578706563746564","id":956,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5188:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},"value":" Expected"},{"id":957,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":943,"src":"5202:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":958,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":945,"src":"5205:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":955,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"5165:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":959,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5165:49:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":960,"nodeType":"EmitStatement","src":"5160:54:0"},{"eventCall":{"arguments":[{"hexValue":"2020202041637475616c","id":962,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5256:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},"value":" Actual"},{"id":963,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":941,"src":"5270:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":964,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":945,"src":"5273:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":961,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"5233:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":965,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5233:49:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":966,"nodeType":"EmitStatement","src":"5228:54:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":967,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"5296:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":968,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5296:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":969,"nodeType":"ExpressionStatement","src":"5296:6:0"}]}}]},"id":973,"implemented":true,"kind":"function","modifiers":[],"name":"assertEqDecimal","nameLocation":"5000:15:0","nodeType":"FunctionDefinition","parameters":{"id":946,"nodeType":"ParameterList","parameters":[{"constant":false,"id":941,"mutability":"mutable","name":"a","nameLocation":"5021:1:0","nodeType":"VariableDeclaration","scope":973,"src":"5016:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":940,"name":"uint","nodeType":"ElementaryTypeName","src":"5016:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":943,"mutability":"mutable","name":"b","nameLocation":"5029:1:0","nodeType":"VariableDeclaration","scope":973,"src":"5024:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":942,"name":"uint","nodeType":"ElementaryTypeName","src":"5024:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":945,"mutability":"mutable","name":"decimals","nameLocation":"5037:8:0","nodeType":"VariableDeclaration","scope":973,"src":"5032:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":944,"name":"uint","nodeType":"ElementaryTypeName","src":"5032:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"5015:31:0"},"returnParameters":{"id":947,"nodeType":"ParameterList","parameters":[],"src":"5056:0:0"},"scope":2124,"src":"4991:328:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1000,"nodeType":"Block","src":"5408:133:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":986,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":984,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":975,"src":"5422:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":985,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":977,"src":"5427:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"5422:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":999,"nodeType":"IfStatement","src":"5418:117:0","trueBody":{"id":998,"nodeType":"Block","src":"5430:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":988,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5466:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":989,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":981,"src":"5475:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":987,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"5449:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":990,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5449:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":991,"nodeType":"EmitStatement","src":"5444:35:0"},{"expression":{"arguments":[{"id":993,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":975,"src":"5509:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":994,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":977,"src":"5512:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":995,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":979,"src":"5515:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":992,"name":"assertEqDecimal","nodeType":"Identifier","overloadedDeclarations":[911,939,973,1001],"referencedDeclaration":973,"src":"5493:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256,uint256)"}},"id":996,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5493:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":997,"nodeType":"ExpressionStatement","src":"5493:31:0"}]}}]},"id":1001,"implemented":true,"kind":"function","modifiers":[],"name":"assertEqDecimal","nameLocation":"5333:15:0","nodeType":"FunctionDefinition","parameters":{"id":982,"nodeType":"ParameterList","parameters":[{"constant":false,"id":975,"mutability":"mutable","name":"a","nameLocation":"5354:1:0","nodeType":"VariableDeclaration","scope":1001,"src":"5349:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":974,"name":"uint","nodeType":"ElementaryTypeName","src":"5349:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":977,"mutability":"mutable","name":"b","nameLocation":"5362:1:0","nodeType":"VariableDeclaration","scope":1001,"src":"5357:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":976,"name":"uint","nodeType":"ElementaryTypeName","src":"5357:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":979,"mutability":"mutable","name":"decimals","nameLocation":"5370:8:0","nodeType":"VariableDeclaration","scope":1001,"src":"5365:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":978,"name":"uint","nodeType":"ElementaryTypeName","src":"5365:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":981,"mutability":"mutable","name":"err","nameLocation":"5394:3:0","nodeType":"VariableDeclaration","scope":1001,"src":"5380:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":980,"name":"string","nodeType":"ElementaryTypeName","src":"5380:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5348:50:0"},"returnParameters":{"id":983,"nodeType":"ParameterList","parameters":[],"src":"5408:0:0"},"scope":2124,"src":"5324:217:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1030,"nodeType":"Block","src":"5590:216:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1010,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1008,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1003,"src":"5604:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<=","rightExpression":{"id":1009,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1005,"src":"5609:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"5604:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1029,"nodeType":"IfStatement","src":"5600:200:0","trueBody":{"id":1028,"nodeType":"Block","src":"5612:188:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203e2062206e6f7420736174697366696564205b75696e745d","id":1012,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5635:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71977b46fbd6a64b4465b93c7a77bcaa06103df599ead9f7e7004b34129c9e3a","typeString":"literal_string \"Error: a > b not satisfied [uint]\""},"value":"Error: a > b not satisfied [uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71977b46fbd6a64b4465b93c7a77bcaa06103df599ead9f7e7004b34129c9e3a","typeString":"literal_string \"Error: a > b not satisfied [uint]\""}],"id":1011,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"5631:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1013,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5631:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1014,"nodeType":"EmitStatement","src":"5626:45:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1016,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5705:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1017,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1003,"src":"5718:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1015,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"5690:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":1018,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5690:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1019,"nodeType":"EmitStatement","src":"5685:35:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1021,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5754:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1022,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1005,"src":"5767:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1020,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"5739:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":1023,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5739:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1024,"nodeType":"EmitStatement","src":"5734:35:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1025,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"5783:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1026,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5783:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1027,"nodeType":"ExpressionStatement","src":"5783:6:0"}]}}]},"id":1031,"implemented":true,"kind":"function","modifiers":[],"name":"assertGt","nameLocation":"5556:8:0","nodeType":"FunctionDefinition","parameters":{"id":1006,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1003,"mutability":"mutable","name":"a","nameLocation":"5570:1:0","nodeType":"VariableDeclaration","scope":1031,"src":"5565:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1002,"name":"uint","nodeType":"ElementaryTypeName","src":"5565:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1005,"mutability":"mutable","name":"b","nameLocation":"5578:1:0","nodeType":"VariableDeclaration","scope":1031,"src":"5573:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1004,"name":"uint","nodeType":"ElementaryTypeName","src":"5573:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"5564:16:0"},"returnParameters":{"id":1007,"nodeType":"ParameterList","parameters":[],"src":"5590:0:0"},"scope":2124,"src":"5547:259:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1055,"nodeType":"Block","src":"5873:116:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1042,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1040,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1033,"src":"5887:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<=","rightExpression":{"id":1041,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1035,"src":"5892:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"5887:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1054,"nodeType":"IfStatement","src":"5883:100:0","trueBody":{"id":1053,"nodeType":"Block","src":"5895:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1044,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5931:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1045,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1037,"src":"5940:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1043,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"5914:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1046,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5914:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1047,"nodeType":"EmitStatement","src":"5909:35:0"},{"expression":{"arguments":[{"id":1049,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1033,"src":"5967:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1050,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1035,"src":"5970:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1048,"name":"assertGt","nodeType":"Identifier","overloadedDeclarations":[1031,1056,1086,1111],"referencedDeclaration":1031,"src":"5958:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256)"}},"id":1051,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5958:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1052,"nodeType":"ExpressionStatement","src":"5958:14:0"}]}}]},"id":1056,"implemented":true,"kind":"function","modifiers":[],"name":"assertGt","nameLocation":"5820:8:0","nodeType":"FunctionDefinition","parameters":{"id":1038,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1033,"mutability":"mutable","name":"a","nameLocation":"5834:1:0","nodeType":"VariableDeclaration","scope":1056,"src":"5829:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1032,"name":"uint","nodeType":"ElementaryTypeName","src":"5829:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1035,"mutability":"mutable","name":"b","nameLocation":"5842:1:0","nodeType":"VariableDeclaration","scope":1056,"src":"5837:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1034,"name":"uint","nodeType":"ElementaryTypeName","src":"5837:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1037,"mutability":"mutable","name":"err","nameLocation":"5859:3:0","nodeType":"VariableDeclaration","scope":1056,"src":"5845:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1036,"name":"string","nodeType":"ElementaryTypeName","src":"5845:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5828:35:0"},"returnParameters":{"id":1039,"nodeType":"ParameterList","parameters":[],"src":"5873:0:0"},"scope":2124,"src":"5811:178:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1085,"nodeType":"Block","src":"6035:213:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1065,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1063,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1058,"src":"6049:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"<=","rightExpression":{"id":1064,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1060,"src":"6054:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"6049:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1084,"nodeType":"IfStatement","src":"6045:197:0","trueBody":{"id":1083,"nodeType":"Block","src":"6057:185:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203e2062206e6f7420736174697366696564205b696e745d","id":1067,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6080:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c6338b3f9677628b4efbdc683490461f2a94469341c3d2ff3d117001fb77d49b","typeString":"literal_string \"Error: a > b not satisfied [int]\""},"value":"Error: a > b not satisfied [int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c6338b3f9677628b4efbdc683490461f2a94469341c3d2ff3d117001fb77d49b","typeString":"literal_string \"Error: a > b not satisfied [int]\""}],"id":1066,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"6076:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1068,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6076:39:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1069,"nodeType":"EmitStatement","src":"6071:44:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1071,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6148:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1072,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1058,"src":"6161:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1070,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"6134:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":1073,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6134:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1074,"nodeType":"EmitStatement","src":"6129:34:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1076,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6196:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1077,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1060,"src":"6209:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1075,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"6182:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":1078,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6182:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1079,"nodeType":"EmitStatement","src":"6177:34:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1080,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"6225:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1081,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6225:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1082,"nodeType":"ExpressionStatement","src":"6225:6:0"}]}}]},"id":1086,"implemented":true,"kind":"function","modifiers":[],"name":"assertGt","nameLocation":"6003:8:0","nodeType":"FunctionDefinition","parameters":{"id":1061,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1058,"mutability":"mutable","name":"a","nameLocation":"6016:1:0","nodeType":"VariableDeclaration","scope":1086,"src":"6012:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1057,"name":"int","nodeType":"ElementaryTypeName","src":"6012:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1060,"mutability":"mutable","name":"b","nameLocation":"6023:1:0","nodeType":"VariableDeclaration","scope":1086,"src":"6019:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1059,"name":"int","nodeType":"ElementaryTypeName","src":"6019:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"}],"src":"6011:14:0"},"returnParameters":{"id":1062,"nodeType":"ParameterList","parameters":[],"src":"6035:0:0"},"scope":2124,"src":"5994:254:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1110,"nodeType":"Block","src":"6313:116:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1097,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1095,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1088,"src":"6327:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"<=","rightExpression":{"id":1096,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1090,"src":"6332:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"6327:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1109,"nodeType":"IfStatement","src":"6323:100:0","trueBody":{"id":1108,"nodeType":"Block","src":"6335:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1099,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6371:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1100,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1092,"src":"6380:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1098,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"6354:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1101,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6354:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1102,"nodeType":"EmitStatement","src":"6349:35:0"},{"expression":{"arguments":[{"id":1104,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1088,"src":"6407:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1105,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1090,"src":"6410:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1103,"name":"assertGt","nodeType":"Identifier","overloadedDeclarations":[1031,1056,1086,1111],"referencedDeclaration":1086,"src":"6398:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$returns$__$","typeString":"function (int256,int256)"}},"id":1106,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6398:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1107,"nodeType":"ExpressionStatement","src":"6398:14:0"}]}}]},"id":1111,"implemented":true,"kind":"function","modifiers":[],"name":"assertGt","nameLocation":"6262:8:0","nodeType":"FunctionDefinition","parameters":{"id":1093,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1088,"mutability":"mutable","name":"a","nameLocation":"6275:1:0","nodeType":"VariableDeclaration","scope":1111,"src":"6271:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1087,"name":"int","nodeType":"ElementaryTypeName","src":"6271:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1090,"mutability":"mutable","name":"b","nameLocation":"6282:1:0","nodeType":"VariableDeclaration","scope":1111,"src":"6278:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1089,"name":"int","nodeType":"ElementaryTypeName","src":"6278:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1092,"mutability":"mutable","name":"err","nameLocation":"6299:3:0","nodeType":"VariableDeclaration","scope":1111,"src":"6285:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1091,"name":"string","nodeType":"ElementaryTypeName","src":"6285:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6270:33:0"},"returnParameters":{"id":1094,"nodeType":"ParameterList","parameters":[],"src":"6313:0:0"},"scope":2124,"src":"6253:176:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1144,"nodeType":"Block","src":"6497:257:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1122,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1120,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1113,"src":"6511:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"<=","rightExpression":{"id":1121,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1115,"src":"6516:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"6511:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1143,"nodeType":"IfStatement","src":"6507:241:0","trueBody":{"id":1142,"nodeType":"Block","src":"6519:229:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203e2062206e6f7420736174697366696564205b646563696d616c20696e745d","id":1124,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6542:42:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_85ee98c18b4560d5bfeeef41e54955cef93f7b8071348c487f1fd81bd1aaf2ad","typeString":"literal_string \"Error: a > b not satisfied [decimal int]\""},"value":"Error: a > b not satisfied [decimal int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_85ee98c18b4560d5bfeeef41e54955cef93f7b8071348c487f1fd81bd1aaf2ad","typeString":"literal_string \"Error: a > b not satisfied [decimal int]\""}],"id":1123,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"6538:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1125,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6538:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1126,"nodeType":"EmitStatement","src":"6533:52:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1128,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6626:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1129,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1113,"src":"6639:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1130,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1117,"src":"6642:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1127,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"6604:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":1131,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6604:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1132,"nodeType":"EmitStatement","src":"6599:52:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1134,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6692:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1135,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1115,"src":"6705:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1136,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1117,"src":"6708:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1133,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"6670:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":1137,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6670:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1138,"nodeType":"EmitStatement","src":"6665:52:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1139,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"6731:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1140,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6731:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1141,"nodeType":"ExpressionStatement","src":"6731:6:0"}]}}]},"id":1145,"implemented":true,"kind":"function","modifiers":[],"name":"assertGtDecimal","nameLocation":"6443:15:0","nodeType":"FunctionDefinition","parameters":{"id":1118,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1113,"mutability":"mutable","name":"a","nameLocation":"6463:1:0","nodeType":"VariableDeclaration","scope":1145,"src":"6459:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1112,"name":"int","nodeType":"ElementaryTypeName","src":"6459:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1115,"mutability":"mutable","name":"b","nameLocation":"6470:1:0","nodeType":"VariableDeclaration","scope":1145,"src":"6466:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1114,"name":"int","nodeType":"ElementaryTypeName","src":"6466:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1117,"mutability":"mutable","name":"decimals","nameLocation":"6478:8:0","nodeType":"VariableDeclaration","scope":1145,"src":"6473:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1116,"name":"uint","nodeType":"ElementaryTypeName","src":"6473:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"6458:29:0"},"returnParameters":{"id":1119,"nodeType":"ParameterList","parameters":[],"src":"6497:0:0"},"scope":2124,"src":"6434:320:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1172,"nodeType":"Block","src":"6841:133:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1158,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1156,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1147,"src":"6855:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"<=","rightExpression":{"id":1157,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1149,"src":"6860:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"6855:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1171,"nodeType":"IfStatement","src":"6851:117:0","trueBody":{"id":1170,"nodeType":"Block","src":"6863:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1160,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6899:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1161,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1153,"src":"6908:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1159,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"6882:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6882:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1163,"nodeType":"EmitStatement","src":"6877:35:0"},{"expression":{"arguments":[{"id":1165,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1147,"src":"6942:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1166,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1149,"src":"6945:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1167,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1151,"src":"6948:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1164,"name":"assertGtDecimal","nodeType":"Identifier","overloadedDeclarations":[1145,1173,1207,1235],"referencedDeclaration":1145,"src":"6926:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (int256,int256,uint256)"}},"id":1168,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6926:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1169,"nodeType":"ExpressionStatement","src":"6926:31:0"}]}}]},"id":1173,"implemented":true,"kind":"function","modifiers":[],"name":"assertGtDecimal","nameLocation":"6768:15:0","nodeType":"FunctionDefinition","parameters":{"id":1154,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1147,"mutability":"mutable","name":"a","nameLocation":"6788:1:0","nodeType":"VariableDeclaration","scope":1173,"src":"6784:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1146,"name":"int","nodeType":"ElementaryTypeName","src":"6784:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1149,"mutability":"mutable","name":"b","nameLocation":"6795:1:0","nodeType":"VariableDeclaration","scope":1173,"src":"6791:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1148,"name":"int","nodeType":"ElementaryTypeName","src":"6791:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1151,"mutability":"mutable","name":"decimals","nameLocation":"6803:8:0","nodeType":"VariableDeclaration","scope":1173,"src":"6798:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1150,"name":"uint","nodeType":"ElementaryTypeName","src":"6798:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1153,"mutability":"mutable","name":"err","nameLocation":"6827:3:0","nodeType":"VariableDeclaration","scope":1173,"src":"6813:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1152,"name":"string","nodeType":"ElementaryTypeName","src":"6813:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6783:48:0"},"returnParameters":{"id":1155,"nodeType":"ParameterList","parameters":[],"src":"6841:0:0"},"scope":2124,"src":"6759:215:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1206,"nodeType":"Block","src":"7044:260:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1184,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1182,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1175,"src":"7058:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<=","rightExpression":{"id":1183,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1177,"src":"7063:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7058:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1205,"nodeType":"IfStatement","src":"7054:244:0","trueBody":{"id":1204,"nodeType":"Block","src":"7066:232:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203e2062206e6f7420736174697366696564205b646563696d616c2075696e745d","id":1186,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7089:43:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2a2cca6a3a53808b9763cfdafa62d083cc161a243845052a9c6e09d6d624c69f","typeString":"literal_string \"Error: a > b not satisfied [decimal uint]\""},"value":"Error: a > b not satisfied [decimal uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2a2cca6a3a53808b9763cfdafa62d083cc161a243845052a9c6e09d6d624c69f","typeString":"literal_string \"Error: a > b not satisfied [decimal uint]\""}],"id":1185,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"7085:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1187,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7085:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1188,"nodeType":"EmitStatement","src":"7080:53:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1190,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7175:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1191,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1175,"src":"7188:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1192,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1179,"src":"7191:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1189,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"7152:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":1193,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7152:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1194,"nodeType":"EmitStatement","src":"7147:53:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1196,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7242:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1197,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1177,"src":"7255:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1198,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1179,"src":"7258:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1195,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"7219:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":1199,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7219:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1200,"nodeType":"EmitStatement","src":"7214:53:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1201,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"7281:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1202,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7281:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1203,"nodeType":"ExpressionStatement","src":"7281:6:0"}]}}]},"id":1207,"implemented":true,"kind":"function","modifiers":[],"name":"assertGtDecimal","nameLocation":"6988:15:0","nodeType":"FunctionDefinition","parameters":{"id":1180,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1175,"mutability":"mutable","name":"a","nameLocation":"7009:1:0","nodeType":"VariableDeclaration","scope":1207,"src":"7004:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1174,"name":"uint","nodeType":"ElementaryTypeName","src":"7004:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1177,"mutability":"mutable","name":"b","nameLocation":"7017:1:0","nodeType":"VariableDeclaration","scope":1207,"src":"7012:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1176,"name":"uint","nodeType":"ElementaryTypeName","src":"7012:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1179,"mutability":"mutable","name":"decimals","nameLocation":"7025:8:0","nodeType":"VariableDeclaration","scope":1207,"src":"7020:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1178,"name":"uint","nodeType":"ElementaryTypeName","src":"7020:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7003:31:0"},"returnParameters":{"id":1181,"nodeType":"ParameterList","parameters":[],"src":"7044:0:0"},"scope":2124,"src":"6979:325:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1234,"nodeType":"Block","src":"7393:133:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1220,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1218,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1209,"src":"7407:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<=","rightExpression":{"id":1219,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1211,"src":"7412:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7407:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1233,"nodeType":"IfStatement","src":"7403:117:0","trueBody":{"id":1232,"nodeType":"Block","src":"7415:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1222,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7451:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1223,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1215,"src":"7460:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1221,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"7434:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1224,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7434:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1225,"nodeType":"EmitStatement","src":"7429:35:0"},{"expression":{"arguments":[{"id":1227,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1209,"src":"7494:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1228,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1211,"src":"7497:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1229,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1213,"src":"7500:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1226,"name":"assertGtDecimal","nodeType":"Identifier","overloadedDeclarations":[1145,1173,1207,1235],"referencedDeclaration":1207,"src":"7478:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256,uint256)"}},"id":1230,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7478:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1231,"nodeType":"ExpressionStatement","src":"7478:31:0"}]}}]},"id":1235,"implemented":true,"kind":"function","modifiers":[],"name":"assertGtDecimal","nameLocation":"7318:15:0","nodeType":"FunctionDefinition","parameters":{"id":1216,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1209,"mutability":"mutable","name":"a","nameLocation":"7339:1:0","nodeType":"VariableDeclaration","scope":1235,"src":"7334:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1208,"name":"uint","nodeType":"ElementaryTypeName","src":"7334:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1211,"mutability":"mutable","name":"b","nameLocation":"7347:1:0","nodeType":"VariableDeclaration","scope":1235,"src":"7342:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1210,"name":"uint","nodeType":"ElementaryTypeName","src":"7342:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1213,"mutability":"mutable","name":"decimals","nameLocation":"7355:8:0","nodeType":"VariableDeclaration","scope":1235,"src":"7350:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1212,"name":"uint","nodeType":"ElementaryTypeName","src":"7350:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1215,"mutability":"mutable","name":"err","nameLocation":"7379:3:0","nodeType":"VariableDeclaration","scope":1235,"src":"7365:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1214,"name":"string","nodeType":"ElementaryTypeName","src":"7365:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"7333:50:0"},"returnParameters":{"id":1217,"nodeType":"ParameterList","parameters":[],"src":"7393:0:0"},"scope":2124,"src":"7309:217:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1264,"nodeType":"Block","src":"7575:216:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1244,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1242,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1237,"src":"7589:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"id":1243,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1239,"src":"7593:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7589:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1263,"nodeType":"IfStatement","src":"7585:200:0","trueBody":{"id":1262,"nodeType":"Block","src":"7596:189:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203e3d2062206e6f7420736174697366696564205b75696e745d","id":1246,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7619:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_ad79593ab7a8c163bd9b5379945ad36a940281a5ef1023478b9c309b02ea375e","typeString":"literal_string \"Error: a >= b not satisfied [uint]\""},"value":"Error: a >= b not satisfied [uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_ad79593ab7a8c163bd9b5379945ad36a940281a5ef1023478b9c309b02ea375e","typeString":"literal_string \"Error: a >= b not satisfied [uint]\""}],"id":1245,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"7615:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1247,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7615:41:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1248,"nodeType":"EmitStatement","src":"7610:46:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1250,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7690:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1251,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1237,"src":"7703:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1249,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"7675:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":1252,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7675:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1253,"nodeType":"EmitStatement","src":"7670:35:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1255,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7739:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1256,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1239,"src":"7752:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1254,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"7724:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":1257,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7724:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1258,"nodeType":"EmitStatement","src":"7719:35:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1259,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"7768:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1260,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7768:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1261,"nodeType":"ExpressionStatement","src":"7768:6:0"}]}}]},"id":1265,"implemented":true,"kind":"function","modifiers":[],"name":"assertGe","nameLocation":"7541:8:0","nodeType":"FunctionDefinition","parameters":{"id":1240,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1237,"mutability":"mutable","name":"a","nameLocation":"7555:1:0","nodeType":"VariableDeclaration","scope":1265,"src":"7550:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1236,"name":"uint","nodeType":"ElementaryTypeName","src":"7550:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1239,"mutability":"mutable","name":"b","nameLocation":"7563:1:0","nodeType":"VariableDeclaration","scope":1265,"src":"7558:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1238,"name":"uint","nodeType":"ElementaryTypeName","src":"7558:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7549:16:0"},"returnParameters":{"id":1241,"nodeType":"ParameterList","parameters":[],"src":"7575:0:0"},"scope":2124,"src":"7532:259:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1289,"nodeType":"Block","src":"7858:115:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1276,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1274,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1267,"src":"7872:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"id":1275,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1269,"src":"7876:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7872:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1288,"nodeType":"IfStatement","src":"7868:99:0","trueBody":{"id":1287,"nodeType":"Block","src":"7879:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1278,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7915:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1279,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1271,"src":"7924:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1277,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"7898:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1280,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7898:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1281,"nodeType":"EmitStatement","src":"7893:35:0"},{"expression":{"arguments":[{"id":1283,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1267,"src":"7951:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1284,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1269,"src":"7954:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1282,"name":"assertGe","nodeType":"Identifier","overloadedDeclarations":[1265,1290,1320,1345],"referencedDeclaration":1265,"src":"7942:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256)"}},"id":1285,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7942:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1286,"nodeType":"ExpressionStatement","src":"7942:14:0"}]}}]},"id":1290,"implemented":true,"kind":"function","modifiers":[],"name":"assertGe","nameLocation":"7805:8:0","nodeType":"FunctionDefinition","parameters":{"id":1272,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1267,"mutability":"mutable","name":"a","nameLocation":"7819:1:0","nodeType":"VariableDeclaration","scope":1290,"src":"7814:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1266,"name":"uint","nodeType":"ElementaryTypeName","src":"7814:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1269,"mutability":"mutable","name":"b","nameLocation":"7827:1:0","nodeType":"VariableDeclaration","scope":1290,"src":"7822:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1268,"name":"uint","nodeType":"ElementaryTypeName","src":"7822:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1271,"mutability":"mutable","name":"err","nameLocation":"7844:3:0","nodeType":"VariableDeclaration","scope":1290,"src":"7830:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1270,"name":"string","nodeType":"ElementaryTypeName","src":"7830:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"7813:35:0"},"returnParameters":{"id":1273,"nodeType":"ParameterList","parameters":[],"src":"7858:0:0"},"scope":2124,"src":"7796:177:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1319,"nodeType":"Block","src":"8019:213:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1299,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1297,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1292,"src":"8033:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"id":1298,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1294,"src":"8037:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"8033:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1318,"nodeType":"IfStatement","src":"8029:197:0","trueBody":{"id":1317,"nodeType":"Block","src":"8040:186:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203e3d2062206e6f7420736174697366696564205b696e745d","id":1301,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8063:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_9dd34d7cd7d190bc9855e4326f563fd4539c0d764699b480d53bfd72aa5807a6","typeString":"literal_string \"Error: a >= b not satisfied [int]\""},"value":"Error: a >= b not satisfied [int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_9dd34d7cd7d190bc9855e4326f563fd4539c0d764699b480d53bfd72aa5807a6","typeString":"literal_string \"Error: a >= b not satisfied [int]\""}],"id":1300,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"8059:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1302,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8059:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1303,"nodeType":"EmitStatement","src":"8054:45:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1305,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8132:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1306,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1292,"src":"8145:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1304,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"8118:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":1307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8118:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1308,"nodeType":"EmitStatement","src":"8113:34:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1310,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8180:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1311,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1294,"src":"8193:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1309,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"8166:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":1312,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8166:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1313,"nodeType":"EmitStatement","src":"8161:34:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1314,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"8209:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1315,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8209:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1316,"nodeType":"ExpressionStatement","src":"8209:6:0"}]}}]},"id":1320,"implemented":true,"kind":"function","modifiers":[],"name":"assertGe","nameLocation":"7987:8:0","nodeType":"FunctionDefinition","parameters":{"id":1295,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1292,"mutability":"mutable","name":"a","nameLocation":"8000:1:0","nodeType":"VariableDeclaration","scope":1320,"src":"7996:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1291,"name":"int","nodeType":"ElementaryTypeName","src":"7996:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1294,"mutability":"mutable","name":"b","nameLocation":"8007:1:0","nodeType":"VariableDeclaration","scope":1320,"src":"8003:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1293,"name":"int","nodeType":"ElementaryTypeName","src":"8003:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"}],"src":"7995:14:0"},"returnParameters":{"id":1296,"nodeType":"ParameterList","parameters":[],"src":"8019:0:0"},"scope":2124,"src":"7978:254:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1344,"nodeType":"Block","src":"8297:115:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1331,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1329,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1322,"src":"8311:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"id":1330,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1324,"src":"8315:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"8311:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1343,"nodeType":"IfStatement","src":"8307:99:0","trueBody":{"id":1342,"nodeType":"Block","src":"8318:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1333,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8354:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1334,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1326,"src":"8363:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1332,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"8337:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1335,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8337:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1336,"nodeType":"EmitStatement","src":"8332:35:0"},{"expression":{"arguments":[{"id":1338,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1322,"src":"8390:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1339,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1324,"src":"8393:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1337,"name":"assertGe","nodeType":"Identifier","overloadedDeclarations":[1265,1290,1320,1345],"referencedDeclaration":1320,"src":"8381:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$returns$__$","typeString":"function (int256,int256)"}},"id":1340,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8381:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1341,"nodeType":"ExpressionStatement","src":"8381:14:0"}]}}]},"id":1345,"implemented":true,"kind":"function","modifiers":[],"name":"assertGe","nameLocation":"8246:8:0","nodeType":"FunctionDefinition","parameters":{"id":1327,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1322,"mutability":"mutable","name":"a","nameLocation":"8259:1:0","nodeType":"VariableDeclaration","scope":1345,"src":"8255:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1321,"name":"int","nodeType":"ElementaryTypeName","src":"8255:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1324,"mutability":"mutable","name":"b","nameLocation":"8266:1:0","nodeType":"VariableDeclaration","scope":1345,"src":"8262:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1323,"name":"int","nodeType":"ElementaryTypeName","src":"8262:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1326,"mutability":"mutable","name":"err","nameLocation":"8283:3:0","nodeType":"VariableDeclaration","scope":1345,"src":"8269:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1325,"name":"string","nodeType":"ElementaryTypeName","src":"8269:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"8254:33:0"},"returnParameters":{"id":1328,"nodeType":"ParameterList","parameters":[],"src":"8297:0:0"},"scope":2124,"src":"8237:175:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1378,"nodeType":"Block","src":"8480:257:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1356,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1354,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1347,"src":"8494:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"id":1355,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1349,"src":"8498:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"8494:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1377,"nodeType":"IfStatement","src":"8490:241:0","trueBody":{"id":1376,"nodeType":"Block","src":"8501:230:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203e3d2062206e6f7420736174697366696564205b646563696d616c20696e745d","id":1358,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8524:43:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0f02f65375ca93c3f3c485b8b2455303d1a8668a2b626cba00789d1c4ebd8736","typeString":"literal_string \"Error: a >= b not satisfied [decimal int]\""},"value":"Error: a >= b not satisfied [decimal int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0f02f65375ca93c3f3c485b8b2455303d1a8668a2b626cba00789d1c4ebd8736","typeString":"literal_string \"Error: a >= b not satisfied [decimal int]\""}],"id":1357,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"8520:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8520:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1360,"nodeType":"EmitStatement","src":"8515:53:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1362,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8609:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1363,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1347,"src":"8622:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1364,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1351,"src":"8625:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1361,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"8587:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":1365,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8587:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1366,"nodeType":"EmitStatement","src":"8582:52:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1368,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8675:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1369,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1349,"src":"8688:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1370,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1351,"src":"8691:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1367,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"8653:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":1371,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8653:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1372,"nodeType":"EmitStatement","src":"8648:52:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1373,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"8714:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1374,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8714:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1375,"nodeType":"ExpressionStatement","src":"8714:6:0"}]}}]},"id":1379,"implemented":true,"kind":"function","modifiers":[],"name":"assertGeDecimal","nameLocation":"8426:15:0","nodeType":"FunctionDefinition","parameters":{"id":1352,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1347,"mutability":"mutable","name":"a","nameLocation":"8446:1:0","nodeType":"VariableDeclaration","scope":1379,"src":"8442:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1346,"name":"int","nodeType":"ElementaryTypeName","src":"8442:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1349,"mutability":"mutable","name":"b","nameLocation":"8453:1:0","nodeType":"VariableDeclaration","scope":1379,"src":"8449:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1348,"name":"int","nodeType":"ElementaryTypeName","src":"8449:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1351,"mutability":"mutable","name":"decimals","nameLocation":"8461:8:0","nodeType":"VariableDeclaration","scope":1379,"src":"8456:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1350,"name":"uint","nodeType":"ElementaryTypeName","src":"8456:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"8441:29:0"},"returnParameters":{"id":1353,"nodeType":"ParameterList","parameters":[],"src":"8480:0:0"},"scope":2124,"src":"8417:320:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1406,"nodeType":"Block","src":"8824:132:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1392,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1390,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1381,"src":"8838:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"id":1391,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1383,"src":"8842:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"8838:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1405,"nodeType":"IfStatement","src":"8834:116:0","trueBody":{"id":1404,"nodeType":"Block","src":"8845:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1394,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1395,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1387,"src":"8890:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1393,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"8864:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1396,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8864:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1397,"nodeType":"EmitStatement","src":"8859:35:0"},{"expression":{"arguments":[{"id":1399,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1381,"src":"8924:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1400,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1383,"src":"8927:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1401,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1385,"src":"8930:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1398,"name":"assertGeDecimal","nodeType":"Identifier","overloadedDeclarations":[1379,1407,1441,1469],"referencedDeclaration":1379,"src":"8908:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (int256,int256,uint256)"}},"id":1402,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8908:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1403,"nodeType":"ExpressionStatement","src":"8908:31:0"}]}}]},"id":1407,"implemented":true,"kind":"function","modifiers":[],"name":"assertGeDecimal","nameLocation":"8751:15:0","nodeType":"FunctionDefinition","parameters":{"id":1388,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1381,"mutability":"mutable","name":"a","nameLocation":"8771:1:0","nodeType":"VariableDeclaration","scope":1407,"src":"8767:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1380,"name":"int","nodeType":"ElementaryTypeName","src":"8767:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1383,"mutability":"mutable","name":"b","nameLocation":"8778:1:0","nodeType":"VariableDeclaration","scope":1407,"src":"8774:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1382,"name":"int","nodeType":"ElementaryTypeName","src":"8774:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1385,"mutability":"mutable","name":"decimals","nameLocation":"8786:8:0","nodeType":"VariableDeclaration","scope":1407,"src":"8781:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1384,"name":"uint","nodeType":"ElementaryTypeName","src":"8781:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1387,"mutability":"mutable","name":"err","nameLocation":"8810:3:0","nodeType":"VariableDeclaration","scope":1407,"src":"8796:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1386,"name":"string","nodeType":"ElementaryTypeName","src":"8796:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"8766:48:0"},"returnParameters":{"id":1389,"nodeType":"ParameterList","parameters":[],"src":"8824:0:0"},"scope":2124,"src":"8742:214:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1440,"nodeType":"Block","src":"9026:260:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1418,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1416,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1409,"src":"9040:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"id":1417,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1411,"src":"9044:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"9040:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1439,"nodeType":"IfStatement","src":"9036:244:0","trueBody":{"id":1438,"nodeType":"Block","src":"9047:233:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203e3d2062206e6f7420736174697366696564205b646563696d616c2075696e745d","id":1420,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"9070:44:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1192304a51ee70969886576ac83224cad7adddc5aab218616c612e9fa634c616","typeString":"literal_string \"Error: a >= b not satisfied [decimal uint]\""},"value":"Error: a >= b not satisfied [decimal uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1192304a51ee70969886576ac83224cad7adddc5aab218616c612e9fa634c616","typeString":"literal_string \"Error: a >= b not satisfied [decimal uint]\""}],"id":1419,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"9066:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1421,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9066:49:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1422,"nodeType":"EmitStatement","src":"9061:54:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1424,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"9157:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1425,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1409,"src":"9170:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1426,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1413,"src":"9173:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1423,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"9134:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":1427,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9134:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1428,"nodeType":"EmitStatement","src":"9129:53:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1430,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"9224:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1431,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1411,"src":"9237:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1432,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1413,"src":"9240:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1429,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"9201:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":1433,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9201:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1434,"nodeType":"EmitStatement","src":"9196:53:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1435,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"9263:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1436,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9263:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1437,"nodeType":"ExpressionStatement","src":"9263:6:0"}]}}]},"id":1441,"implemented":true,"kind":"function","modifiers":[],"name":"assertGeDecimal","nameLocation":"8970:15:0","nodeType":"FunctionDefinition","parameters":{"id":1414,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1409,"mutability":"mutable","name":"a","nameLocation":"8991:1:0","nodeType":"VariableDeclaration","scope":1441,"src":"8986:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1408,"name":"uint","nodeType":"ElementaryTypeName","src":"8986:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1411,"mutability":"mutable","name":"b","nameLocation":"8999:1:0","nodeType":"VariableDeclaration","scope":1441,"src":"8994:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1410,"name":"uint","nodeType":"ElementaryTypeName","src":"8994:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1413,"mutability":"mutable","name":"decimals","nameLocation":"9007:8:0","nodeType":"VariableDeclaration","scope":1441,"src":"9002:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1412,"name":"uint","nodeType":"ElementaryTypeName","src":"9002:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"8985:31:0"},"returnParameters":{"id":1415,"nodeType":"ParameterList","parameters":[],"src":"9026:0:0"},"scope":2124,"src":"8961:325:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1468,"nodeType":"Block","src":"9375:132:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1454,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1452,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1443,"src":"9389:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"id":1453,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1445,"src":"9393:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"9389:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1467,"nodeType":"IfStatement","src":"9385:116:0","trueBody":{"id":1466,"nodeType":"Block","src":"9396:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1456,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"9432:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1457,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1449,"src":"9441:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1455,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"9415:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1458,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9415:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1459,"nodeType":"EmitStatement","src":"9410:35:0"},{"expression":{"arguments":[{"id":1461,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1443,"src":"9475:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1462,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1445,"src":"9478:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1463,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1447,"src":"9481:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1460,"name":"assertGeDecimal","nodeType":"Identifier","overloadedDeclarations":[1379,1407,1441,1469],"referencedDeclaration":1441,"src":"9459:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256,uint256)"}},"id":1464,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9459:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1465,"nodeType":"ExpressionStatement","src":"9459:31:0"}]}}]},"id":1469,"implemented":true,"kind":"function","modifiers":[],"name":"assertGeDecimal","nameLocation":"9300:15:0","nodeType":"FunctionDefinition","parameters":{"id":1450,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1443,"mutability":"mutable","name":"a","nameLocation":"9321:1:0","nodeType":"VariableDeclaration","scope":1469,"src":"9316:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1442,"name":"uint","nodeType":"ElementaryTypeName","src":"9316:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1445,"mutability":"mutable","name":"b","nameLocation":"9329:1:0","nodeType":"VariableDeclaration","scope":1469,"src":"9324:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1444,"name":"uint","nodeType":"ElementaryTypeName","src":"9324:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1447,"mutability":"mutable","name":"decimals","nameLocation":"9337:8:0","nodeType":"VariableDeclaration","scope":1469,"src":"9332:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1446,"name":"uint","nodeType":"ElementaryTypeName","src":"9332:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1449,"mutability":"mutable","name":"err","nameLocation":"9361:3:0","nodeType":"VariableDeclaration","scope":1469,"src":"9347:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1448,"name":"string","nodeType":"ElementaryTypeName","src":"9347:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"9315:50:0"},"returnParameters":{"id":1451,"nodeType":"ParameterList","parameters":[],"src":"9375:0:0"},"scope":2124,"src":"9291:216:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1498,"nodeType":"Block","src":"9556:216:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1478,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1476,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1471,"src":"9570:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">=","rightExpression":{"id":1477,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1473,"src":"9575:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"9570:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1497,"nodeType":"IfStatement","src":"9566:200:0","trueBody":{"id":1496,"nodeType":"Block","src":"9578:188:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203c2062206e6f7420736174697366696564205b75696e745d","id":1480,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"9601:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4a5f85d4936ddbc273c762d0b3a90fefdc47bf4d5496816359b86f70b5c74f9","typeString":"literal_string \"Error: a < b not satisfied [uint]\""},"value":"Error: a < b not satisfied [uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4a5f85d4936ddbc273c762d0b3a90fefdc47bf4d5496816359b86f70b5c74f9","typeString":"literal_string \"Error: a < b not satisfied [uint]\""}],"id":1479,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"9597:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1481,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9597:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1482,"nodeType":"EmitStatement","src":"9592:45:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1484,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"9671:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1485,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1471,"src":"9684:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1483,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"9656:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":1486,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9656:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1487,"nodeType":"EmitStatement","src":"9651:35:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1489,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"9720:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1490,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1473,"src":"9733:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1488,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"9705:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":1491,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9705:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1492,"nodeType":"EmitStatement","src":"9700:35:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1493,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"9749:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1494,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9749:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1495,"nodeType":"ExpressionStatement","src":"9749:6:0"}]}}]},"id":1499,"implemented":true,"kind":"function","modifiers":[],"name":"assertLt","nameLocation":"9522:8:0","nodeType":"FunctionDefinition","parameters":{"id":1474,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1471,"mutability":"mutable","name":"a","nameLocation":"9536:1:0","nodeType":"VariableDeclaration","scope":1499,"src":"9531:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1470,"name":"uint","nodeType":"ElementaryTypeName","src":"9531:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1473,"mutability":"mutable","name":"b","nameLocation":"9544:1:0","nodeType":"VariableDeclaration","scope":1499,"src":"9539:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1472,"name":"uint","nodeType":"ElementaryTypeName","src":"9539:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"9530:16:0"},"returnParameters":{"id":1475,"nodeType":"ParameterList","parameters":[],"src":"9556:0:0"},"scope":2124,"src":"9513:259:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1523,"nodeType":"Block","src":"9839:116:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1510,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1508,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1501,"src":"9853:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">=","rightExpression":{"id":1509,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1503,"src":"9858:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"9853:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1522,"nodeType":"IfStatement","src":"9849:100:0","trueBody":{"id":1521,"nodeType":"Block","src":"9861:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"9897:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1513,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1505,"src":"9906:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1511,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"9880:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1514,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9880:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1515,"nodeType":"EmitStatement","src":"9875:35:0"},{"expression":{"arguments":[{"id":1517,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1501,"src":"9933:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1518,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1503,"src":"9936:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1516,"name":"assertLt","nodeType":"Identifier","overloadedDeclarations":[1499,1524,1554,1579],"referencedDeclaration":1499,"src":"9924:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256)"}},"id":1519,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"9924:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1520,"nodeType":"ExpressionStatement","src":"9924:14:0"}]}}]},"id":1524,"implemented":true,"kind":"function","modifiers":[],"name":"assertLt","nameLocation":"9786:8:0","nodeType":"FunctionDefinition","parameters":{"id":1506,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1501,"mutability":"mutable","name":"a","nameLocation":"9800:1:0","nodeType":"VariableDeclaration","scope":1524,"src":"9795:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1500,"name":"uint","nodeType":"ElementaryTypeName","src":"9795:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1503,"mutability":"mutable","name":"b","nameLocation":"9808:1:0","nodeType":"VariableDeclaration","scope":1524,"src":"9803:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1502,"name":"uint","nodeType":"ElementaryTypeName","src":"9803:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1505,"mutability":"mutable","name":"err","nameLocation":"9825:3:0","nodeType":"VariableDeclaration","scope":1524,"src":"9811:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1504,"name":"string","nodeType":"ElementaryTypeName","src":"9811:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"9794:35:0"},"returnParameters":{"id":1507,"nodeType":"ParameterList","parameters":[],"src":"9839:0:0"},"scope":2124,"src":"9777:178:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1553,"nodeType":"Block","src":"10001:213:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1533,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1531,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1526,"src":"10015:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":">=","rightExpression":{"id":1532,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1528,"src":"10020:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"10015:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1552,"nodeType":"IfStatement","src":"10011:197:0","trueBody":{"id":1551,"nodeType":"Block","src":"10023:185:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203c2062206e6f7420736174697366696564205b696e745d","id":1535,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"10046:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_62edb5e296dde1308ab599c3156f51dcd32b6d82784df4b0c0246d307d4bd055","typeString":"literal_string \"Error: a < b not satisfied [int]\""},"value":"Error: a < b not satisfied [int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_62edb5e296dde1308ab599c3156f51dcd32b6d82784df4b0c0246d307d4bd055","typeString":"literal_string \"Error: a < b not satisfied [int]\""}],"id":1534,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"10042:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1536,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10042:39:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1537,"nodeType":"EmitStatement","src":"10037:44:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1539,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"10114:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1540,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1526,"src":"10127:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1538,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"10100:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":1541,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10100:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1542,"nodeType":"EmitStatement","src":"10095:34:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1544,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"10162:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1545,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1528,"src":"10175:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1543,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"10148:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":1546,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10148:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1547,"nodeType":"EmitStatement","src":"10143:34:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1548,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"10191:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1549,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10191:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1550,"nodeType":"ExpressionStatement","src":"10191:6:0"}]}}]},"id":1554,"implemented":true,"kind":"function","modifiers":[],"name":"assertLt","nameLocation":"9969:8:0","nodeType":"FunctionDefinition","parameters":{"id":1529,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1526,"mutability":"mutable","name":"a","nameLocation":"9982:1:0","nodeType":"VariableDeclaration","scope":1554,"src":"9978:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1525,"name":"int","nodeType":"ElementaryTypeName","src":"9978:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1528,"mutability":"mutable","name":"b","nameLocation":"9989:1:0","nodeType":"VariableDeclaration","scope":1554,"src":"9985:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1527,"name":"int","nodeType":"ElementaryTypeName","src":"9985:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"}],"src":"9977:14:0"},"returnParameters":{"id":1530,"nodeType":"ParameterList","parameters":[],"src":"10001:0:0"},"scope":2124,"src":"9960:254:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1578,"nodeType":"Block","src":"10279:116:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1565,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1563,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1556,"src":"10293:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":">=","rightExpression":{"id":1564,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1558,"src":"10298:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"10293:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1577,"nodeType":"IfStatement","src":"10289:100:0","trueBody":{"id":1576,"nodeType":"Block","src":"10301:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1567,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"10337:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1568,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1560,"src":"10346:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1566,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"10320:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1569,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10320:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1570,"nodeType":"EmitStatement","src":"10315:35:0"},{"expression":{"arguments":[{"id":1572,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1556,"src":"10373:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1573,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1558,"src":"10376:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1571,"name":"assertLt","nodeType":"Identifier","overloadedDeclarations":[1499,1524,1554,1579],"referencedDeclaration":1554,"src":"10364:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$returns$__$","typeString":"function (int256,int256)"}},"id":1574,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10364:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1575,"nodeType":"ExpressionStatement","src":"10364:14:0"}]}}]},"id":1579,"implemented":true,"kind":"function","modifiers":[],"name":"assertLt","nameLocation":"10228:8:0","nodeType":"FunctionDefinition","parameters":{"id":1561,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1556,"mutability":"mutable","name":"a","nameLocation":"10241:1:0","nodeType":"VariableDeclaration","scope":1579,"src":"10237:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1555,"name":"int","nodeType":"ElementaryTypeName","src":"10237:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1558,"mutability":"mutable","name":"b","nameLocation":"10248:1:0","nodeType":"VariableDeclaration","scope":1579,"src":"10244:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1557,"name":"int","nodeType":"ElementaryTypeName","src":"10244:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1560,"mutability":"mutable","name":"err","nameLocation":"10265:3:0","nodeType":"VariableDeclaration","scope":1579,"src":"10251:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1559,"name":"string","nodeType":"ElementaryTypeName","src":"10251:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"10236:33:0"},"returnParameters":{"id":1562,"nodeType":"ParameterList","parameters":[],"src":"10279:0:0"},"scope":2124,"src":"10219:176:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1612,"nodeType":"Block","src":"10463:257:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1590,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1588,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1581,"src":"10477:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":">=","rightExpression":{"id":1589,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1583,"src":"10482:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"10477:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1611,"nodeType":"IfStatement","src":"10473:241:0","trueBody":{"id":1610,"nodeType":"Block","src":"10485:229:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203c2062206e6f7420736174697366696564205b646563696d616c20696e745d","id":1592,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"10508:42:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a598de9e78c706978d3e40be19632446c2f234152ee02226f88acff1b63da79a","typeString":"literal_string \"Error: a < b not satisfied [decimal int]\""},"value":"Error: a < b not satisfied [decimal int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a598de9e78c706978d3e40be19632446c2f234152ee02226f88acff1b63da79a","typeString":"literal_string \"Error: a < b not satisfied [decimal int]\""}],"id":1591,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"10504:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1593,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10504:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1594,"nodeType":"EmitStatement","src":"10499:52:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1596,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"10592:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1597,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1581,"src":"10605:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1598,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1585,"src":"10608:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1595,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"10570:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":1599,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10570:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1600,"nodeType":"EmitStatement","src":"10565:52:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1602,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"10658:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1603,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1583,"src":"10671:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1604,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1585,"src":"10674:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1601,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"10636:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":1605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10636:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1606,"nodeType":"EmitStatement","src":"10631:52:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1607,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"10697:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1608,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10697:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1609,"nodeType":"ExpressionStatement","src":"10697:6:0"}]}}]},"id":1613,"implemented":true,"kind":"function","modifiers":[],"name":"assertLtDecimal","nameLocation":"10409:15:0","nodeType":"FunctionDefinition","parameters":{"id":1586,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1581,"mutability":"mutable","name":"a","nameLocation":"10429:1:0","nodeType":"VariableDeclaration","scope":1613,"src":"10425:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1580,"name":"int","nodeType":"ElementaryTypeName","src":"10425:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1583,"mutability":"mutable","name":"b","nameLocation":"10436:1:0","nodeType":"VariableDeclaration","scope":1613,"src":"10432:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1582,"name":"int","nodeType":"ElementaryTypeName","src":"10432:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1585,"mutability":"mutable","name":"decimals","nameLocation":"10444:8:0","nodeType":"VariableDeclaration","scope":1613,"src":"10439:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1584,"name":"uint","nodeType":"ElementaryTypeName","src":"10439:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"10424:29:0"},"returnParameters":{"id":1587,"nodeType":"ParameterList","parameters":[],"src":"10463:0:0"},"scope":2124,"src":"10400:320:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1640,"nodeType":"Block","src":"10807:133:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1626,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1624,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1615,"src":"10821:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":">=","rightExpression":{"id":1625,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1617,"src":"10826:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"10821:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1639,"nodeType":"IfStatement","src":"10817:117:0","trueBody":{"id":1638,"nodeType":"Block","src":"10829:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1628,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"10865:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1629,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1621,"src":"10874:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1627,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"10848:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1630,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10848:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1631,"nodeType":"EmitStatement","src":"10843:35:0"},{"expression":{"arguments":[{"id":1633,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1615,"src":"10908:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1634,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1617,"src":"10911:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1635,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1619,"src":"10914:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1632,"name":"assertLtDecimal","nodeType":"Identifier","overloadedDeclarations":[1613,1641,1675,1703],"referencedDeclaration":1613,"src":"10892:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (int256,int256,uint256)"}},"id":1636,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"10892:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1637,"nodeType":"ExpressionStatement","src":"10892:31:0"}]}}]},"id":1641,"implemented":true,"kind":"function","modifiers":[],"name":"assertLtDecimal","nameLocation":"10734:15:0","nodeType":"FunctionDefinition","parameters":{"id":1622,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1615,"mutability":"mutable","name":"a","nameLocation":"10754:1:0","nodeType":"VariableDeclaration","scope":1641,"src":"10750:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1614,"name":"int","nodeType":"ElementaryTypeName","src":"10750:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1617,"mutability":"mutable","name":"b","nameLocation":"10761:1:0","nodeType":"VariableDeclaration","scope":1641,"src":"10757:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1616,"name":"int","nodeType":"ElementaryTypeName","src":"10757:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1619,"mutability":"mutable","name":"decimals","nameLocation":"10769:8:0","nodeType":"VariableDeclaration","scope":1641,"src":"10764:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1618,"name":"uint","nodeType":"ElementaryTypeName","src":"10764:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1621,"mutability":"mutable","name":"err","nameLocation":"10793:3:0","nodeType":"VariableDeclaration","scope":1641,"src":"10779:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1620,"name":"string","nodeType":"ElementaryTypeName","src":"10779:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"10749:48:0"},"returnParameters":{"id":1623,"nodeType":"ParameterList","parameters":[],"src":"10807:0:0"},"scope":2124,"src":"10725:215:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1674,"nodeType":"Block","src":"11010:260:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1652,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1650,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1643,"src":"11024:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">=","rightExpression":{"id":1651,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1645,"src":"11029:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"11024:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1673,"nodeType":"IfStatement","src":"11020:244:0","trueBody":{"id":1672,"nodeType":"Block","src":"11032:232:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203c2062206e6f7420736174697366696564205b646563696d616c2075696e745d","id":1654,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"11055:43:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8057606f9e67842ac0149f4a7ffdaca59331aea176cd1419e89b7b4b21bbc6d9","typeString":"literal_string \"Error: a < b not satisfied [decimal uint]\""},"value":"Error: a < b not satisfied [decimal uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8057606f9e67842ac0149f4a7ffdaca59331aea176cd1419e89b7b4b21bbc6d9","typeString":"literal_string \"Error: a < b not satisfied [decimal uint]\""}],"id":1653,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"11051:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1655,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11051:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1656,"nodeType":"EmitStatement","src":"11046:53:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1658,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"11141:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1659,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1643,"src":"11154:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1660,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1647,"src":"11157:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1657,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"11118:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":1661,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11118:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1662,"nodeType":"EmitStatement","src":"11113:53:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1664,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"11208:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1665,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1645,"src":"11221:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1666,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1647,"src":"11224:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1663,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"11185:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":1667,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11185:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1668,"nodeType":"EmitStatement","src":"11180:53:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1669,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"11247:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1670,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11247:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1671,"nodeType":"ExpressionStatement","src":"11247:6:0"}]}}]},"id":1675,"implemented":true,"kind":"function","modifiers":[],"name":"assertLtDecimal","nameLocation":"10954:15:0","nodeType":"FunctionDefinition","parameters":{"id":1648,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1643,"mutability":"mutable","name":"a","nameLocation":"10975:1:0","nodeType":"VariableDeclaration","scope":1675,"src":"10970:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1642,"name":"uint","nodeType":"ElementaryTypeName","src":"10970:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1645,"mutability":"mutable","name":"b","nameLocation":"10983:1:0","nodeType":"VariableDeclaration","scope":1675,"src":"10978:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1644,"name":"uint","nodeType":"ElementaryTypeName","src":"10978:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1647,"mutability":"mutable","name":"decimals","nameLocation":"10991:8:0","nodeType":"VariableDeclaration","scope":1675,"src":"10986:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1646,"name":"uint","nodeType":"ElementaryTypeName","src":"10986:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"10969:31:0"},"returnParameters":{"id":1649,"nodeType":"ParameterList","parameters":[],"src":"11010:0:0"},"scope":2124,"src":"10945:325:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1702,"nodeType":"Block","src":"11359:133:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1688,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1686,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1677,"src":"11373:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">=","rightExpression":{"id":1687,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1679,"src":"11378:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"11373:6:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1701,"nodeType":"IfStatement","src":"11369:117:0","trueBody":{"id":1700,"nodeType":"Block","src":"11381:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1690,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"11417:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1691,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1683,"src":"11426:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1689,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"11400:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1692,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11400:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1693,"nodeType":"EmitStatement","src":"11395:35:0"},{"expression":{"arguments":[{"id":1695,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1677,"src":"11460:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1696,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1679,"src":"11463:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1697,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1681,"src":"11466:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1694,"name":"assertLtDecimal","nodeType":"Identifier","overloadedDeclarations":[1613,1641,1675,1703],"referencedDeclaration":1675,"src":"11444:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256,uint256)"}},"id":1698,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11444:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1699,"nodeType":"ExpressionStatement","src":"11444:31:0"}]}}]},"id":1703,"implemented":true,"kind":"function","modifiers":[],"name":"assertLtDecimal","nameLocation":"11284:15:0","nodeType":"FunctionDefinition","parameters":{"id":1684,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1677,"mutability":"mutable","name":"a","nameLocation":"11305:1:0","nodeType":"VariableDeclaration","scope":1703,"src":"11300:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1676,"name":"uint","nodeType":"ElementaryTypeName","src":"11300:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1679,"mutability":"mutable","name":"b","nameLocation":"11313:1:0","nodeType":"VariableDeclaration","scope":1703,"src":"11308:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1678,"name":"uint","nodeType":"ElementaryTypeName","src":"11308:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1681,"mutability":"mutable","name":"decimals","nameLocation":"11321:8:0","nodeType":"VariableDeclaration","scope":1703,"src":"11316:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1680,"name":"uint","nodeType":"ElementaryTypeName","src":"11316:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1683,"mutability":"mutable","name":"err","nameLocation":"11345:3:0","nodeType":"VariableDeclaration","scope":1703,"src":"11331:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1682,"name":"string","nodeType":"ElementaryTypeName","src":"11331:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"11299:50:0"},"returnParameters":{"id":1685,"nodeType":"ParameterList","parameters":[],"src":"11359:0:0"},"scope":2124,"src":"11275:217:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1732,"nodeType":"Block","src":"11541:216:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1712,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1710,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1705,"src":"11555:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">","rightExpression":{"id":1711,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1707,"src":"11559:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"11555:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1731,"nodeType":"IfStatement","src":"11551:200:0","trueBody":{"id":1730,"nodeType":"Block","src":"11562:189:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203c3d2062206e6f7420736174697366696564205b75696e745d","id":1714,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"11585:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6d5420eec28b94f3fd7dd1c7ce81f45c79bfa9fab37300faf965a8d6272e32ff","typeString":"literal_string \"Error: a <= b not satisfied [uint]\""},"value":"Error: a <= b not satisfied [uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6d5420eec28b94f3fd7dd1c7ce81f45c79bfa9fab37300faf965a8d6272e32ff","typeString":"literal_string \"Error: a <= b not satisfied [uint]\""}],"id":1713,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"11581:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1715,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11581:41:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1716,"nodeType":"EmitStatement","src":"11576:46:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1718,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"11656:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1719,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1705,"src":"11669:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1717,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"11641:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":1720,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11641:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1721,"nodeType":"EmitStatement","src":"11636:35:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1723,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"11705:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1724,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1707,"src":"11718:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1722,"name":"log_named_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"11690:14:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256)"}},"id":1725,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11690:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1726,"nodeType":"EmitStatement","src":"11685:35:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1727,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"11734:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1728,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11734:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1729,"nodeType":"ExpressionStatement","src":"11734:6:0"}]}}]},"id":1733,"implemented":true,"kind":"function","modifiers":[],"name":"assertLe","nameLocation":"11507:8:0","nodeType":"FunctionDefinition","parameters":{"id":1708,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1705,"mutability":"mutable","name":"a","nameLocation":"11521:1:0","nodeType":"VariableDeclaration","scope":1733,"src":"11516:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1704,"name":"uint","nodeType":"ElementaryTypeName","src":"11516:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1707,"mutability":"mutable","name":"b","nameLocation":"11529:1:0","nodeType":"VariableDeclaration","scope":1733,"src":"11524:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1706,"name":"uint","nodeType":"ElementaryTypeName","src":"11524:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"11515:16:0"},"returnParameters":{"id":1709,"nodeType":"ParameterList","parameters":[],"src":"11541:0:0"},"scope":2124,"src":"11498:259:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1757,"nodeType":"Block","src":"11824:115:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1744,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1742,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1735,"src":"11838:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">","rightExpression":{"id":1743,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1737,"src":"11842:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"11838:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1756,"nodeType":"IfStatement","src":"11834:99:0","trueBody":{"id":1755,"nodeType":"Block","src":"11845:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1746,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"11881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1747,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1739,"src":"11890:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1745,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"11864:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1748,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11864:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1749,"nodeType":"EmitStatement","src":"11859:35:0"},{"expression":{"arguments":[{"id":1751,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1735,"src":"11917:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1752,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1737,"src":"11920:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1750,"name":"assertLe","nodeType":"Identifier","overloadedDeclarations":[1733,1758,1788,1813],"referencedDeclaration":1733,"src":"11908:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256)"}},"id":1753,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"11908:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1754,"nodeType":"ExpressionStatement","src":"11908:14:0"}]}}]},"id":1758,"implemented":true,"kind":"function","modifiers":[],"name":"assertLe","nameLocation":"11771:8:0","nodeType":"FunctionDefinition","parameters":{"id":1740,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1735,"mutability":"mutable","name":"a","nameLocation":"11785:1:0","nodeType":"VariableDeclaration","scope":1758,"src":"11780:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1734,"name":"uint","nodeType":"ElementaryTypeName","src":"11780:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1737,"mutability":"mutable","name":"b","nameLocation":"11793:1:0","nodeType":"VariableDeclaration","scope":1758,"src":"11788:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1736,"name":"uint","nodeType":"ElementaryTypeName","src":"11788:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1739,"mutability":"mutable","name":"err","nameLocation":"11810:3:0","nodeType":"VariableDeclaration","scope":1758,"src":"11796:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1738,"name":"string","nodeType":"ElementaryTypeName","src":"11796:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"11779:35:0"},"returnParameters":{"id":1741,"nodeType":"ParameterList","parameters":[],"src":"11824:0:0"},"scope":2124,"src":"11762:177:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1787,"nodeType":"Block","src":"11985:213:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1767,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1765,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1760,"src":"11999:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":">","rightExpression":{"id":1766,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1762,"src":"12003:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"11999:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1786,"nodeType":"IfStatement","src":"11995:197:0","trueBody":{"id":1785,"nodeType":"Block","src":"12006:186:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203c3d2062206e6f7420736174697366696564205b696e745d","id":1769,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"12029:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_558ba41c44b763b352271d6c22f0cb02f5c0c4dbb25ed68172916a4e6a662555","typeString":"literal_string \"Error: a <= b not satisfied [int]\""},"value":"Error: a <= b not satisfied [int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_558ba41c44b763b352271d6c22f0cb02f5c0c4dbb25ed68172916a4e6a662555","typeString":"literal_string \"Error: a <= b not satisfied [int]\""}],"id":1768,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"12025:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1770,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12025:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1771,"nodeType":"EmitStatement","src":"12020:45:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1773,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"12098:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1774,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1760,"src":"12111:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1772,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"12084:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":1775,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12084:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1776,"nodeType":"EmitStatement","src":"12079:34:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1778,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"12146:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1779,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1762,"src":"12159:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1777,"name":"log_named_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":511,"src":"12132:13:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$returns$__$","typeString":"function (string memory,int256)"}},"id":1780,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12132:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1781,"nodeType":"EmitStatement","src":"12127:34:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1782,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"12175:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1783,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12175:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1784,"nodeType":"ExpressionStatement","src":"12175:6:0"}]}}]},"id":1788,"implemented":true,"kind":"function","modifiers":[],"name":"assertLe","nameLocation":"11953:8:0","nodeType":"FunctionDefinition","parameters":{"id":1763,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1760,"mutability":"mutable","name":"a","nameLocation":"11966:1:0","nodeType":"VariableDeclaration","scope":1788,"src":"11962:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1759,"name":"int","nodeType":"ElementaryTypeName","src":"11962:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1762,"mutability":"mutable","name":"b","nameLocation":"11973:1:0","nodeType":"VariableDeclaration","scope":1788,"src":"11969:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1761,"name":"int","nodeType":"ElementaryTypeName","src":"11969:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"}],"src":"11961:14:0"},"returnParameters":{"id":1764,"nodeType":"ParameterList","parameters":[],"src":"11985:0:0"},"scope":2124,"src":"11944:254:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1812,"nodeType":"Block","src":"12263:115:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1799,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1797,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1790,"src":"12277:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":">","rightExpression":{"id":1798,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1792,"src":"12281:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"12277:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1811,"nodeType":"IfStatement","src":"12273:99:0","trueBody":{"id":1810,"nodeType":"Block","src":"12284:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1801,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"12320:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1802,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1794,"src":"12329:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1800,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"12303:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1803,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12303:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1804,"nodeType":"EmitStatement","src":"12298:35:0"},{"expression":{"arguments":[{"id":1806,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1790,"src":"12356:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1807,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1792,"src":"12359:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"}],"id":1805,"name":"assertLe","nodeType":"Identifier","overloadedDeclarations":[1733,1758,1788,1813],"referencedDeclaration":1788,"src":"12347:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$returns$__$","typeString":"function (int256,int256)"}},"id":1808,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12347:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1809,"nodeType":"ExpressionStatement","src":"12347:14:0"}]}}]},"id":1813,"implemented":true,"kind":"function","modifiers":[],"name":"assertLe","nameLocation":"12212:8:0","nodeType":"FunctionDefinition","parameters":{"id":1795,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1790,"mutability":"mutable","name":"a","nameLocation":"12225:1:0","nodeType":"VariableDeclaration","scope":1813,"src":"12221:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1789,"name":"int","nodeType":"ElementaryTypeName","src":"12221:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1792,"mutability":"mutable","name":"b","nameLocation":"12232:1:0","nodeType":"VariableDeclaration","scope":1813,"src":"12228:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1791,"name":"int","nodeType":"ElementaryTypeName","src":"12228:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1794,"mutability":"mutable","name":"err","nameLocation":"12249:3:0","nodeType":"VariableDeclaration","scope":1813,"src":"12235:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1793,"name":"string","nodeType":"ElementaryTypeName","src":"12235:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"12220:33:0"},"returnParameters":{"id":1796,"nodeType":"ParameterList","parameters":[],"src":"12263:0:0"},"scope":2124,"src":"12203:175:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1846,"nodeType":"Block","src":"12446:257:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1824,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1822,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1815,"src":"12460:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":">","rightExpression":{"id":1823,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1817,"src":"12464:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"12460:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1845,"nodeType":"IfStatement","src":"12456:241:0","trueBody":{"id":1844,"nodeType":"Block","src":"12467:230:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203c3d2062206e6f7420736174697366696564205b646563696d616c20696e745d","id":1826,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"12490:43:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a855fbfffc345e8a0ab544e824618dabd995fdc5bda653c7d4869b57deb1d23a","typeString":"literal_string \"Error: a <= b not satisfied [decimal int]\""},"value":"Error: a <= b not satisfied [decimal int]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a855fbfffc345e8a0ab544e824618dabd995fdc5bda653c7d4869b57deb1d23a","typeString":"literal_string \"Error: a <= b not satisfied [decimal int]\""}],"id":1825,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"12486:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1827,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12486:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1828,"nodeType":"EmitStatement","src":"12481:53:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1830,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"12575:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1831,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1815,"src":"12588:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1832,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1819,"src":"12591:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1829,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"12553:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":1833,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12553:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1834,"nodeType":"EmitStatement","src":"12548:52:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1836,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"12641:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1837,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1817,"src":"12654:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1838,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1819,"src":"12657:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1835,"name":"log_named_decimal_int","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":497,"src":"12619:21:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (string memory,int256,uint256)"}},"id":1839,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12619:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1840,"nodeType":"EmitStatement","src":"12614:52:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1841,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"12680:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1842,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12680:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1843,"nodeType":"ExpressionStatement","src":"12680:6:0"}]}}]},"id":1847,"implemented":true,"kind":"function","modifiers":[],"name":"assertLeDecimal","nameLocation":"12392:15:0","nodeType":"FunctionDefinition","parameters":{"id":1820,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1815,"mutability":"mutable","name":"a","nameLocation":"12412:1:0","nodeType":"VariableDeclaration","scope":1847,"src":"12408:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1814,"name":"int","nodeType":"ElementaryTypeName","src":"12408:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1817,"mutability":"mutable","name":"b","nameLocation":"12419:1:0","nodeType":"VariableDeclaration","scope":1847,"src":"12415:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1816,"name":"int","nodeType":"ElementaryTypeName","src":"12415:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1819,"mutability":"mutable","name":"decimals","nameLocation":"12427:8:0","nodeType":"VariableDeclaration","scope":1847,"src":"12422:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1818,"name":"uint","nodeType":"ElementaryTypeName","src":"12422:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"12407:29:0"},"returnParameters":{"id":1821,"nodeType":"ParameterList","parameters":[],"src":"12446:0:0"},"scope":2124,"src":"12383:320:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1874,"nodeType":"Block","src":"12790:132:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_int256","typeString":"int256"},"id":1860,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1858,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1849,"src":"12804:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"nodeType":"BinaryOperation","operator":">","rightExpression":{"id":1859,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1851,"src":"12808:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"src":"12804:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1873,"nodeType":"IfStatement","src":"12800:116:0","trueBody":{"id":1872,"nodeType":"Block","src":"12811:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1862,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"12847:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1863,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1855,"src":"12856:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1861,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"12830:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1864,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12830:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1865,"nodeType":"EmitStatement","src":"12825:35:0"},{"expression":{"arguments":[{"id":1867,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1849,"src":"12890:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1868,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1851,"src":"12893:1:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},{"id":1869,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1853,"src":"12896:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_int256","typeString":"int256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1866,"name":"assertLeDecimal","nodeType":"Identifier","overloadedDeclarations":[1847,1875,1909,1937],"referencedDeclaration":1847,"src":"12874:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_int256_$_t_int256_$_t_uint256_$returns$__$","typeString":"function (int256,int256,uint256)"}},"id":1870,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"12874:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1871,"nodeType":"ExpressionStatement","src":"12874:31:0"}]}}]},"id":1875,"implemented":true,"kind":"function","modifiers":[],"name":"assertLeDecimal","nameLocation":"12717:15:0","nodeType":"FunctionDefinition","parameters":{"id":1856,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1849,"mutability":"mutable","name":"a","nameLocation":"12737:1:0","nodeType":"VariableDeclaration","scope":1875,"src":"12733:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1848,"name":"int","nodeType":"ElementaryTypeName","src":"12733:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1851,"mutability":"mutable","name":"b","nameLocation":"12744:1:0","nodeType":"VariableDeclaration","scope":1875,"src":"12740:5:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":1850,"name":"int","nodeType":"ElementaryTypeName","src":"12740:3:0","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"visibility":"internal"},{"constant":false,"id":1853,"mutability":"mutable","name":"decimals","nameLocation":"12752:8:0","nodeType":"VariableDeclaration","scope":1875,"src":"12747:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1852,"name":"uint","nodeType":"ElementaryTypeName","src":"12747:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1855,"mutability":"mutable","name":"err","nameLocation":"12776:3:0","nodeType":"VariableDeclaration","scope":1875,"src":"12762:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1854,"name":"string","nodeType":"ElementaryTypeName","src":"12762:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"12732:48:0"},"returnParameters":{"id":1857,"nodeType":"ParameterList","parameters":[],"src":"12790:0:0"},"scope":2124,"src":"12708:214:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1908,"nodeType":"Block","src":"12992:260:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1886,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1884,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1877,"src":"13006:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">","rightExpression":{"id":1885,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1879,"src":"13010:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"13006:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1907,"nodeType":"IfStatement","src":"13002:244:0","trueBody":{"id":1906,"nodeType":"Block","src":"13013:233:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203c3d2062206e6f7420736174697366696564205b646563696d616c2075696e745d","id":1888,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"13036:44:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_32bce37771ce1d01bc601c73b51f2296c0d8e2a50c2d19a6ac89c6b917715c51","typeString":"literal_string \"Error: a <= b not satisfied [decimal uint]\""},"value":"Error: a <= b not satisfied [decimal uint]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_32bce37771ce1d01bc601c73b51f2296c0d8e2a50c2d19a6ac89c6b917715c51","typeString":"literal_string \"Error: a <= b not satisfied [decimal uint]\""}],"id":1887,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"13032:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1889,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13032:49:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1890,"nodeType":"EmitStatement","src":"13027:54:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1892,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"13123:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1893,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1877,"src":"13136:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1894,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1881,"src":"13139:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1891,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"13100:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":1895,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13100:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1896,"nodeType":"EmitStatement","src":"13095:53:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1898,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"13190:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1899,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1879,"src":"13203:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1900,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1881,"src":"13206:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1897,"name":"log_named_decimal_uint","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":505,"src":"13167:22:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256,uint256)"}},"id":1901,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13167:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1902,"nodeType":"EmitStatement","src":"13162:53:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1903,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"13229:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1904,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13229:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1905,"nodeType":"ExpressionStatement","src":"13229:6:0"}]}}]},"id":1909,"implemented":true,"kind":"function","modifiers":[],"name":"assertLeDecimal","nameLocation":"12936:15:0","nodeType":"FunctionDefinition","parameters":{"id":1882,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1877,"mutability":"mutable","name":"a","nameLocation":"12957:1:0","nodeType":"VariableDeclaration","scope":1909,"src":"12952:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1876,"name":"uint","nodeType":"ElementaryTypeName","src":"12952:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1879,"mutability":"mutable","name":"b","nameLocation":"12965:1:0","nodeType":"VariableDeclaration","scope":1909,"src":"12960:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1878,"name":"uint","nodeType":"ElementaryTypeName","src":"12960:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1881,"mutability":"mutable","name":"decimals","nameLocation":"12973:8:0","nodeType":"VariableDeclaration","scope":1909,"src":"12968:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1880,"name":"uint","nodeType":"ElementaryTypeName","src":"12968:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"12951:31:0"},"returnParameters":{"id":1883,"nodeType":"ParameterList","parameters":[],"src":"12992:0:0"},"scope":2124,"src":"12927:325:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1936,"nodeType":"Block","src":"13341:132:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":1922,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":1920,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1911,"src":"13355:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">","rightExpression":{"id":1921,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1913,"src":"13359:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"13355:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1935,"nodeType":"IfStatement","src":"13351:116:0","trueBody":{"id":1934,"nodeType":"Block","src":"13362:105:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":1924,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"13398:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":1925,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1917,"src":"13407:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1923,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"13381:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1926,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13381:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1927,"nodeType":"EmitStatement","src":"13376:35:0"},{"expression":{"arguments":[{"id":1929,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1911,"src":"13441:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1930,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1913,"src":"13444:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"id":1931,"name":"decimals","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1915,"src":"13447:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":1928,"name":"assertGeDecimal","nodeType":"Identifier","overloadedDeclarations":[1379,1407,1441,1469],"referencedDeclaration":1441,"src":"13425:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$","typeString":"function (uint256,uint256,uint256)"}},"id":1932,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13425:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1933,"nodeType":"ExpressionStatement","src":"13425:31:0"}]}}]},"id":1937,"implemented":true,"kind":"function","modifiers":[],"name":"assertLeDecimal","nameLocation":"13266:15:0","nodeType":"FunctionDefinition","parameters":{"id":1918,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1911,"mutability":"mutable","name":"a","nameLocation":"13287:1:0","nodeType":"VariableDeclaration","scope":1937,"src":"13282:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1910,"name":"uint","nodeType":"ElementaryTypeName","src":"13282:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1913,"mutability":"mutable","name":"b","nameLocation":"13295:1:0","nodeType":"VariableDeclaration","scope":1937,"src":"13290:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1912,"name":"uint","nodeType":"ElementaryTypeName","src":"13290:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1915,"mutability":"mutable","name":"decimals","nameLocation":"13303:8:0","nodeType":"VariableDeclaration","scope":1937,"src":"13298:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1914,"name":"uint","nodeType":"ElementaryTypeName","src":"13298:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":1917,"mutability":"mutable","name":"err","nameLocation":"13327:3:0","nodeType":"VariableDeclaration","scope":1937,"src":"13313:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1916,"name":"string","nodeType":"ElementaryTypeName","src":"13313:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"13281:50:0"},"returnParameters":{"id":1919,"nodeType":"ParameterList","parameters":[],"src":"13341:0:0"},"scope":2124,"src":"13257:216:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":1976,"nodeType":"Block","src":"13540:281:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"id":1956,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"arguments":[{"id":1947,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1939,"src":"13581:1:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":1945,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"13564:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":1946,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodePacked","nodeType":"MemberAccess","src":"13564:16:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodepacked_pure$__$returns$_t_bytes_memory_ptr_$","typeString":"function () pure returns (bytes memory)"}},"id":1948,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13564:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":1944,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"13554:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":1949,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13554:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"arguments":[{"arguments":[{"id":1953,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1941,"src":"13615:1:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":1951,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"13598:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":1952,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodePacked","nodeType":"MemberAccess","src":"13598:16:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodepacked_pure$__$returns$_t_bytes_memory_ptr_$","typeString":"function () pure returns (bytes memory)"}},"id":1954,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13598:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":1950,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"13588:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":1955,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13588:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"src":"13554:64:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":1975,"nodeType":"IfStatement","src":"13550:265:0","trueBody":{"id":1974,"nodeType":"Block","src":"13620:195:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b737472696e675d","id":1958,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"13643:38:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_58e3ca0e65e73c038df3db6a7cab1bf7de300d13038b802ce0f4435889c48e5e","typeString":"literal_string \"Error: a == b not satisfied [string]\""},"value":"Error: a == b not satisfied [string]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_58e3ca0e65e73c038df3db6a7cab1bf7de300d13038b802ce0f4435889c48e5e","typeString":"literal_string \"Error: a == b not satisfied [string]\""}],"id":1957,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"13639:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":1959,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13639:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1960,"nodeType":"EmitStatement","src":"13634:48:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652061","id":1962,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"13718:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},"value":" Value a"},{"id":1963,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1939,"src":"13731:1:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c592b529b874569f165479a5a4380dedf000796f11e04035f76bfa7310b31d26","typeString":"literal_string \" Value a\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1961,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"13701:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1964,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13701:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1965,"nodeType":"EmitStatement","src":"13696:37:0"},{"eventCall":{"arguments":[{"hexValue":"202056616c75652062","id":1967,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"13769:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},"value":" Value b"},{"id":1968,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1941,"src":"13782:1:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e4b1d025132960c3fb1a582cf2366864dc416744d1b9770aa69fe3749623ebc3","typeString":"literal_string \" Value b\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1966,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"13752:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":1969,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13752:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1970,"nodeType":"EmitStatement","src":"13747:37:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":1971,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"13798:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":1972,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13798:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":1973,"nodeType":"ExpressionStatement","src":"13798:6:0"}]}}]},"id":1977,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"13488:8:0","nodeType":"FunctionDefinition","parameters":{"id":1942,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1939,"mutability":"mutable","name":"a","nameLocation":"13511:1:0","nodeType":"VariableDeclaration","scope":1977,"src":"13497:15:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1938,"name":"string","nodeType":"ElementaryTypeName","src":"13497:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":1941,"mutability":"mutable","name":"b","nameLocation":"13528:1:0","nodeType":"VariableDeclaration","scope":1977,"src":"13514:15:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1940,"name":"string","nodeType":"ElementaryTypeName","src":"13514:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"13496:34:0"},"returnParameters":{"id":1943,"nodeType":"ParameterList","parameters":[],"src":"13540:0:0"},"scope":2124,"src":"13479:342:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":2011,"nodeType":"Block","src":"13906:174:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"id":1998,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"arguments":[{"id":1989,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1979,"src":"13947:1:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":1987,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"13930:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":1988,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodePacked","nodeType":"MemberAccess","src":"13930:16:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodepacked_pure$__$returns$_t_bytes_memory_ptr_$","typeString":"function () pure returns (bytes memory)"}},"id":1990,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13930:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":1986,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"13920:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":1991,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13920:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"arguments":[{"arguments":[{"id":1995,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1981,"src":"13981:1:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":1993,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"13964:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":1994,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodePacked","nodeType":"MemberAccess","src":"13964:16:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodepacked_pure$__$returns$_t_bytes_memory_ptr_$","typeString":"function () pure returns (bytes memory)"}},"id":1996,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13964:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":1992,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"13954:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":1997,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"13954:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"src":"13920:64:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":2010,"nodeType":"IfStatement","src":"13916:158:0","trueBody":{"id":2009,"nodeType":"Block","src":"13986:88:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":2000,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"14022:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":2001,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1983,"src":"14031:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":1999,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"14005:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":2002,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14005:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":2003,"nodeType":"EmitStatement","src":"14000:35:0"},{"expression":{"arguments":[{"id":2005,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1979,"src":"14058:1:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":2006,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":1981,"src":"14061:1:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":2004,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":1977,"src":"14049:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":2007,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14049:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":2008,"nodeType":"ExpressionStatement","src":"14049:14:0"}]}}]},"id":2012,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq","nameLocation":"13835:8:0","nodeType":"FunctionDefinition","parameters":{"id":1984,"nodeType":"ParameterList","parameters":[{"constant":false,"id":1979,"mutability":"mutable","name":"a","nameLocation":"13858:1:0","nodeType":"VariableDeclaration","scope":2012,"src":"13844:15:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1978,"name":"string","nodeType":"ElementaryTypeName","src":"13844:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":1981,"mutability":"mutable","name":"b","nameLocation":"13875:1:0","nodeType":"VariableDeclaration","scope":2012,"src":"13861:15:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1980,"name":"string","nodeType":"ElementaryTypeName","src":"13861:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":1983,"mutability":"mutable","name":"err","nameLocation":"13892:3:0","nodeType":"VariableDeclaration","scope":2012,"src":"13878:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":1982,"name":"string","nodeType":"ElementaryTypeName","src":"13878:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"13843:53:0"},"returnParameters":{"id":1985,"nodeType":"ParameterList","parameters":[],"src":"13906:0:0"},"scope":2124,"src":"13826:254:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":2063,"nodeType":"Block","src":"14168:263:0","statements":[{"expression":{"id":2023,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":2021,"name":"ok","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2019,"src":"14178:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"74727565","id":2022,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"14183:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"true"},"src":"14178:9:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":2024,"nodeType":"ExpressionStatement","src":"14178:9:0"},{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":2029,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":2025,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2014,"src":"14201:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":2026,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"14201:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"expression":{"id":2027,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2016,"src":"14213:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":2028,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"14213:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"14201:20:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"falseBody":{"id":2061,"nodeType":"Block","src":"14390:35:0","statements":[{"expression":{"id":2059,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":2057,"name":"ok","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2019,"src":"14404:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"66616c7365","id":2058,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"14409:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"},"src":"14404:10:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":2060,"nodeType":"ExpressionStatement","src":"14404:10:0"}]},"id":2062,"nodeType":"IfStatement","src":"14197:228:0","trueBody":{"id":2056,"nodeType":"Block","src":"14223:161:0","statements":[{"body":{"id":2054,"nodeType":"Block","src":"14273:101:0","statements":[{"condition":{"commonType":{"typeIdentifier":"t_bytes1","typeString":"bytes1"},"id":2047,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"baseExpression":{"id":2041,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2014,"src":"14295:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":2043,"indexExpression":{"id":2042,"name":"i","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2031,"src":"14297:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"14295:4:0","typeDescriptions":{"typeIdentifier":"t_bytes1","typeString":"bytes1"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"baseExpression":{"id":2044,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2016,"src":"14303:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":2046,"indexExpression":{"id":2045,"name":"i","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2031,"src":"14305:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"14303:4:0","typeDescriptions":{"typeIdentifier":"t_bytes1","typeString":"bytes1"}},"src":"14295:12:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":2053,"nodeType":"IfStatement","src":"14291:69:0","trueBody":{"id":2052,"nodeType":"Block","src":"14309:51:0","statements":[{"expression":{"id":2050,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":2048,"name":"ok","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2019,"src":"14331:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"66616c7365","id":2049,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"14336:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"},"src":"14331:10:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":2051,"nodeType":"ExpressionStatement","src":"14331:10:0"}]}}]},"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":2037,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":2034,"name":"i","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2031,"src":"14254:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<","rightExpression":{"expression":{"id":2035,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2014,"src":"14258:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":2036,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"14258:8:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"14254:12:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":2055,"initializationExpression":{"assignments":[2031],"declarations":[{"constant":false,"id":2031,"mutability":"mutable","name":"i","nameLocation":"14247:1:0","nodeType":"VariableDeclaration","scope":2055,"src":"14242:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":2030,"name":"uint","nodeType":"ElementaryTypeName","src":"14242:4:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":2033,"initialValue":{"hexValue":"30","id":2032,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"14251:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"nodeType":"VariableDeclarationStatement","src":"14242:10:0"},"loopExpression":{"expression":{"id":2039,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"14268:3:0","subExpression":{"id":2038,"name":"i","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2031,"src":"14268:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":2040,"nodeType":"ExpressionStatement","src":"14268:3:0"},"nodeType":"ForStatement","src":"14237:137:0"}]}}]},"id":2064,"implemented":true,"kind":"function","modifiers":[],"name":"checkEq0","nameLocation":"14095:8:0","nodeType":"FunctionDefinition","parameters":{"id":2017,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2014,"mutability":"mutable","name":"a","nameLocation":"14117:1:0","nodeType":"VariableDeclaration","scope":2064,"src":"14104:14:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":2013,"name":"bytes","nodeType":"ElementaryTypeName","src":"14104:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"},{"constant":false,"id":2016,"mutability":"mutable","name":"b","nameLocation":"14133:1:0","nodeType":"VariableDeclaration","scope":2064,"src":"14120:14:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":2015,"name":"bytes","nodeType":"ElementaryTypeName","src":"14120:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"14103:32:0"},"returnParameters":{"id":2020,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2019,"mutability":"mutable","name":"ok","nameLocation":"14164:2:0","nodeType":"VariableDeclaration","scope":2064,"src":"14159:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":2018,"name":"bool","nodeType":"ElementaryTypeName","src":"14159:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"14158:9:0"},"scope":2124,"src":"14086:345:0","stateMutability":"pure","virtual":false,"visibility":"internal"},{"body":{"id":2095,"nodeType":"Block","src":"14496:231:0","statements":[{"condition":{"id":2075,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"!","prefix":true,"src":"14510:15:0","subExpression":{"arguments":[{"id":2072,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2066,"src":"14520:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},{"id":2073,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2068,"src":"14523:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":2071,"name":"checkEq0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2064,"src":"14511:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$_t_bytes_memory_ptr_$returns$_t_bool_$","typeString":"function (bytes memory,bytes memory) pure returns (bool)"}},"id":2074,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14511:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":2094,"nodeType":"IfStatement","src":"14506:215:0","trueBody":{"id":2093,"nodeType":"Block","src":"14527:194:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f723a2061203d3d2062206e6f7420736174697366696564205b62797465735d","id":2077,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"14550:37:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_9bb7b728691fe2872efdd27bd07c4a95b3586c3b7ec3afa731a7c21a76e39cfc","typeString":"literal_string \"Error: a == b not satisfied [bytes]\""},"value":"Error: a == b not satisfied [bytes]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_9bb7b728691fe2872efdd27bd07c4a95b3586c3b7ec3afa731a7c21a76e39cfc","typeString":"literal_string \"Error: a == b not satisfied [bytes]\""}],"id":2076,"name":"log","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":449,"src":"14546:3:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory)"}},"id":2078,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14546:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":2079,"nodeType":"EmitStatement","src":"14541:47:0"},{"eventCall":{"arguments":[{"hexValue":"20204578706563746564","id":2081,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"14623:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},"value":" Expected"},{"id":2082,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2066,"src":"14637:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42fa07d7c51ce5de92a0fc65dbf7e7800814fd01c258dc50e84d5be59184bf0b","typeString":"literal_string \" Expected\""},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":2080,"name":"log_named_bytes","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":523,"src":"14607:15:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (string memory,bytes memory)"}},"id":2083,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14607:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":2084,"nodeType":"EmitStatement","src":"14602:37:0"},{"eventCall":{"arguments":[{"hexValue":"2020202041637475616c","id":2086,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"14674:12:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},"value":" Actual"},{"id":2087,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2068,"src":"14688:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_d7896f3f645b3ba89da46bf231a5df16e525e587a84bc9b284dfb39958fb219b","typeString":"literal_string \" Actual\""},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":2085,"name":"log_named_bytes","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":523,"src":"14658:15:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (string memory,bytes memory)"}},"id":2088,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14658:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":2089,"nodeType":"EmitStatement","src":"14653:37:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":2090,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"14704:4:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":2091,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14704:6:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":2092,"nodeType":"ExpressionStatement","src":"14704:6:0"}]}}]},"id":2096,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq0","nameLocation":"14445:9:0","nodeType":"FunctionDefinition","parameters":{"id":2069,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2066,"mutability":"mutable","name":"a","nameLocation":"14468:1:0","nodeType":"VariableDeclaration","scope":2096,"src":"14455:14:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":2065,"name":"bytes","nodeType":"ElementaryTypeName","src":"14455:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"},{"constant":false,"id":2068,"mutability":"mutable","name":"b","nameLocation":"14484:1:0","nodeType":"VariableDeclaration","scope":2096,"src":"14471:14:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":2067,"name":"bytes","nodeType":"ElementaryTypeName","src":"14471:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"14454:32:0"},"returnParameters":{"id":2070,"nodeType":"ParameterList","parameters":[],"src":"14496:0:0"},"scope":2124,"src":"14436:291:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":2122,"nodeType":"Block","src":"14811:126:0","statements":[{"condition":{"id":2109,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"!","prefix":true,"src":"14825:15:0","subExpression":{"arguments":[{"id":2106,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2098,"src":"14835:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},{"id":2107,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2100,"src":"14838:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":2105,"name":"checkEq0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2064,"src":"14826:8:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$_t_bytes_memory_ptr_$returns$_t_bool_$","typeString":"function (bytes memory,bytes memory) pure returns (bool)"}},"id":2108,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14826:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":2121,"nodeType":"IfStatement","src":"14821:110:0","trueBody":{"id":2120,"nodeType":"Block","src":"14842:89:0","statements":[{"eventCall":{"arguments":[{"hexValue":"4572726f72","id":2111,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"14878:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},"value":"Error"},{"id":2112,"name":"err","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2102,"src":"14887:3:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_e342daa49723ff3485f4ff5f755a17b8bc9c3c33bbd312ceee37c94eebfe45c1","typeString":"literal_string \"Error\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":2110,"name":"log_named_string","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":529,"src":"14861:16:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":2113,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14861:30:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":2114,"nodeType":"EmitStatement","src":"14856:35:0"},{"expression":{"arguments":[{"id":2116,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2098,"src":"14915:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},{"id":2117,"name":"b","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2100,"src":"14918:1:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":2115,"name":"assertEq0","nodeType":"Identifier","overloadedDeclarations":[2096,2123],"referencedDeclaration":2096,"src":"14905:9:0","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_bytes_memory_ptr_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory,bytes memory)"}},"id":2118,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"14905:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":2119,"nodeType":"ExpressionStatement","src":"14905:15:0"}]}}]},"id":2123,"implemented":true,"kind":"function","modifiers":[],"name":"assertEq0","nameLocation":"14741:9:0","nodeType":"FunctionDefinition","parameters":{"id":2103,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2098,"mutability":"mutable","name":"a","nameLocation":"14764:1:0","nodeType":"VariableDeclaration","scope":2123,"src":"14751:14:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":2097,"name":"bytes","nodeType":"ElementaryTypeName","src":"14751:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"},{"constant":false,"id":2100,"mutability":"mutable","name":"b","nameLocation":"14780:1:0","nodeType":"VariableDeclaration","scope":2123,"src":"14767:14:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":2099,"name":"bytes","nodeType":"ElementaryTypeName","src":"14767:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"},{"constant":false,"id":2102,"mutability":"mutable","name":"err","nameLocation":"14797:3:0","nodeType":"VariableDeclaration","scope":2123,"src":"14783:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":2101,"name":"string","nodeType":"ElementaryTypeName","src":"14783:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"14750:51:0"},"returnParameters":{"id":2104,"nodeType":"ParameterList","parameters":[],"src":"14811:0:0"},"scope":2124,"src":"14732:205:0","stateMutability":"nonpayable","virtual":false,"visibility":"internal"}],"scope":2125,"src":"716:14223:0","usedErrors":[]}],"src":"689:14251:0"},"id":0},"lib/openzeppelin-contracts/contracts/access/Ownable.sol":{"ast":{"absolutePath":"lib/openzeppelin-contracts/contracts/access/Ownable.sol","exportedSymbols":{"Context":[2146],"Ownable":[443]},"id":444,"license":"MIT","nodeType":"SourceUnit","nodes":[{"id":341,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"33:23:1"},{"absolutePath":"lib/openzeppelin-contracts/contracts/utils/Context.sol","file":"../utils/Context.sol","id":342,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":444,"sourceUnit":2147,"src":"58:30:1","symbolAliases":[],"unitAlias":""},{"abstract":true,"baseContracts":[{"baseName":{"id":344,"name":"Context","nodeType":"IdentifierPath","referencedDeclaration":2146,"src":"614:7:1"},"id":345,"nodeType":"InheritanceSpecifier","src":"614:7:1"}],"contractDependencies":[],"contractKind":"contract","documentation":{"id":343,"nodeType":"StructuredDocumentation","src":"90:494:1","text":" @dev Contract module which provides a basic access control mechanism, where\n there is an account (an owner) that can be granted exclusive access to\n specific functions.\n By default, the owner account will be the one that deploys the contract. This\n can later be changed with {transferOwnership}.\n This module is used through inheritance. It will make available the modifier\n `onlyOwner`, which can be applied to your functions to restrict their use to\n the owner."},"fullyImplemented":true,"id":443,"linearizedBaseContracts":[443,2146],"name":"Ownable","nameLocation":"603:7:1","nodeType":"ContractDefinition","nodes":[{"constant":false,"id":347,"mutability":"mutable","name":"_owner","nameLocation":"644:6:1","nodeType":"VariableDeclaration","scope":443,"src":"628:22:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":346,"name":"address","nodeType":"ElementaryTypeName","src":"628:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"private"},{"anonymous":false,"id":353,"name":"OwnershipTransferred","nameLocation":"663:20:1","nodeType":"EventDefinition","parameters":{"id":352,"nodeType":"ParameterList","parameters":[{"constant":false,"id":349,"indexed":true,"mutability":"mutable","name":"previousOwner","nameLocation":"700:13:1","nodeType":"VariableDeclaration","scope":353,"src":"684:29:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":348,"name":"address","nodeType":"ElementaryTypeName","src":"684:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":351,"indexed":true,"mutability":"mutable","name":"newOwner","nameLocation":"731:8:1","nodeType":"VariableDeclaration","scope":353,"src":"715:24:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":350,"name":"address","nodeType":"ElementaryTypeName","src":"715:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"683:57:1"},"src":"657:84:1"},{"body":{"id":362,"nodeType":"Block","src":"857:40:1","statements":[{"expression":{"arguments":[{"arguments":[],"expression":{"argumentTypes":[],"id":358,"name":"_msgSender","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2136,"src":"877:10:1","typeDescriptions":{"typeIdentifier":"t_function_internal_view$__$returns$_t_address_$","typeString":"function () view returns (address)"}},"id":359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"877:12:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":357,"name":"_setOwner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":442,"src":"867:9:1","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_address_$returns$__$","typeString":"function (address)"}},"id":360,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"867:23:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":361,"nodeType":"ExpressionStatement","src":"867:23:1"}]},"documentation":{"id":354,"nodeType":"StructuredDocumentation","src":"747:91:1","text":" @dev Initializes the contract setting the deployer as the initial owner."},"id":363,"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","nodeType":"FunctionDefinition","parameters":{"id":355,"nodeType":"ParameterList","parameters":[],"src":"854:2:1"},"returnParameters":{"id":356,"nodeType":"ParameterList","parameters":[],"src":"857:0:1"},"scope":443,"src":"843:54:1","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"body":{"id":371,"nodeType":"Block","src":"1028:30:1","statements":[{"expression":{"id":369,"name":"_owner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":347,"src":"1045:6:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"functionReturnParameters":368,"id":370,"nodeType":"Return","src":"1038:13:1"}]},"documentation":{"id":364,"nodeType":"StructuredDocumentation","src":"903:65:1","text":" @dev Returns the address of the current owner."},"functionSelector":"8da5cb5b","id":372,"implemented":true,"kind":"function","modifiers":[],"name":"owner","nameLocation":"982:5:1","nodeType":"FunctionDefinition","parameters":{"id":365,"nodeType":"ParameterList","parameters":[],"src":"987:2:1"},"returnParameters":{"id":368,"nodeType":"ParameterList","parameters":[{"constant":false,"id":367,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":372,"src":"1019:7:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":366,"name":"address","nodeType":"ElementaryTypeName","src":"1019:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1018:9:1"},"scope":443,"src":"973:85:1","stateMutability":"view","virtual":true,"visibility":"public"},{"body":{"id":385,"nodeType":"Block","src":"1167:96:1","statements":[{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":380,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"id":376,"name":"owner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":372,"src":"1185:5:1","typeDescriptions":{"typeIdentifier":"t_function_internal_view$__$returns$_t_address_$","typeString":"function () view returns (address)"}},"id":377,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1185:7:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[],"expression":{"argumentTypes":[],"id":378,"name":"_msgSender","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2136,"src":"1196:10:1","typeDescriptions":{"typeIdentifier":"t_function_internal_view$__$returns$_t_address_$","typeString":"function () view returns (address)"}},"id":379,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1196:12:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1185:23:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572","id":381,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1210:34:1","typeDescriptions":{"typeIdentifier":"t_stringliteral_9924ebdf1add33d25d4ef888e16131f0a5687b0580a36c21b5c301a6c462effe","typeString":"literal_string \"Ownable: caller is not the owner\""},"value":"Ownable: caller is not the owner"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_9924ebdf1add33d25d4ef888e16131f0a5687b0580a36c21b5c301a6c462effe","typeString":"literal_string \"Ownable: caller is not the owner\""}],"id":375,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"1177:7:1","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":382,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1177:68:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":383,"nodeType":"ExpressionStatement","src":"1177:68:1"},{"id":384,"nodeType":"PlaceholderStatement","src":"1255:1:1"}]},"documentation":{"id":373,"nodeType":"StructuredDocumentation","src":"1064:77:1","text":" @dev Throws if called by any account other than the owner."},"id":386,"name":"onlyOwner","nameLocation":"1155:9:1","nodeType":"ModifierDefinition","parameters":{"id":374,"nodeType":"ParameterList","parameters":[],"src":"1164:2:1"},"src":"1146:117:1","virtual":false,"visibility":"internal"},{"body":{"id":399,"nodeType":"Block","src":"1659:38:1","statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"30","id":395,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1687:1:1","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"}],"id":394,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1679:7:1","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":393,"name":"address","nodeType":"ElementaryTypeName","src":"1679:7:1","typeDescriptions":{}}},"id":396,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1679:10:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":392,"name":"_setOwner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":442,"src":"1669:9:1","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_address_$returns$__$","typeString":"function (address)"}},"id":397,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1669:21:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":398,"nodeType":"ExpressionStatement","src":"1669:21:1"}]},"documentation":{"id":387,"nodeType":"StructuredDocumentation","src":"1269:331:1","text":" @dev Leaves the contract without owner. It will not be possible to call\n `onlyOwner` functions anymore. Can only be called by the current owner.\n NOTE: Renouncing ownership will leave the contract without an owner,\n thereby removing any functionality that is only available to the owner."},"functionSelector":"715018a6","id":400,"implemented":true,"kind":"function","modifiers":[{"id":390,"kind":"modifierInvocation","modifierName":{"id":389,"name":"onlyOwner","nodeType":"IdentifierPath","referencedDeclaration":386,"src":"1649:9:1"},"nodeType":"ModifierInvocation","src":"1649:9:1"}],"name":"renounceOwnership","nameLocation":"1614:17:1","nodeType":"FunctionDefinition","parameters":{"id":388,"nodeType":"ParameterList","parameters":[],"src":"1631:2:1"},"returnParameters":{"id":391,"nodeType":"ParameterList","parameters":[],"src":"1659:0:1"},"scope":443,"src":"1605:92:1","stateMutability":"nonpayable","virtual":true,"visibility":"public"},{"body":{"id":422,"nodeType":"Block","src":"1916:119:1","statements":[{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":414,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":409,"name":"newOwner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":403,"src":"1934:8:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"arguments":[{"hexValue":"30","id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1954:1:1","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"}],"id":411,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1946:7:1","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":410,"name":"address","nodeType":"ElementaryTypeName","src":"1946:7:1","typeDescriptions":{}}},"id":413,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1946:10:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1934:22:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373","id":415,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1958:40:1","typeDescriptions":{"typeIdentifier":"t_stringliteral_245f15ff17f551913a7a18385165551503906a406f905ac1c2437281a7cd0cfe","typeString":"literal_string \"Ownable: new owner is the zero address\""},"value":"Ownable: new owner is the zero address"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_245f15ff17f551913a7a18385165551503906a406f905ac1c2437281a7cd0cfe","typeString":"literal_string \"Ownable: new owner is the zero address\""}],"id":408,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"1926:7:1","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":416,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1926:73:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":417,"nodeType":"ExpressionStatement","src":"1926:73:1"},{"expression":{"arguments":[{"id":419,"name":"newOwner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":403,"src":"2019:8:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":418,"name":"_setOwner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":442,"src":"2009:9:1","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_address_$returns$__$","typeString":"function (address)"}},"id":420,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2009:19:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":421,"nodeType":"ExpressionStatement","src":"2009:19:1"}]},"documentation":{"id":401,"nodeType":"StructuredDocumentation","src":"1703:138:1","text":" @dev Transfers ownership of the contract to a new account (`newOwner`).\n Can only be called by the current owner."},"functionSelector":"f2fde38b","id":423,"implemented":true,"kind":"function","modifiers":[{"id":406,"kind":"modifierInvocation","modifierName":{"id":405,"name":"onlyOwner","nodeType":"IdentifierPath","referencedDeclaration":386,"src":"1906:9:1"},"nodeType":"ModifierInvocation","src":"1906:9:1"}],"name":"transferOwnership","nameLocation":"1855:17:1","nodeType":"FunctionDefinition","parameters":{"id":404,"nodeType":"ParameterList","parameters":[{"constant":false,"id":403,"mutability":"mutable","name":"newOwner","nameLocation":"1881:8:1","nodeType":"VariableDeclaration","scope":423,"src":"1873:16:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":402,"name":"address","nodeType":"ElementaryTypeName","src":"1873:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1872:18:1"},"returnParameters":{"id":407,"nodeType":"ParameterList","parameters":[],"src":"1916:0:1"},"scope":443,"src":"1846:189:1","stateMutability":"nonpayable","virtual":true,"visibility":"public"},{"body":{"id":441,"nodeType":"Block","src":"2086:124:1","statements":[{"assignments":[429],"declarations":[{"constant":false,"id":429,"mutability":"mutable","name":"oldOwner","nameLocation":"2104:8:1","nodeType":"VariableDeclaration","scope":441,"src":"2096:16:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":428,"name":"address","nodeType":"ElementaryTypeName","src":"2096:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":431,"initialValue":{"id":430,"name":"_owner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":347,"src":"2115:6:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"2096:25:1"},{"expression":{"id":434,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":432,"name":"_owner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":347,"src":"2131:6:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":433,"name":"newOwner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":425,"src":"2140:8:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"2131:17:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":435,"nodeType":"ExpressionStatement","src":"2131:17:1"},{"eventCall":{"arguments":[{"id":437,"name":"oldOwner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":429,"src":"2184:8:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"id":438,"name":"newOwner","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":425,"src":"2194:8:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_address","typeString":"address"}],"id":436,"name":"OwnershipTransferred","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":353,"src":"2163:20:1","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_address_$_t_address_$returns$__$","typeString":"function (address,address)"}},"id":439,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2163:40:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":440,"nodeType":"EmitStatement","src":"2158:45:1"}]},"id":442,"implemented":true,"kind":"function","modifiers":[],"name":"_setOwner","nameLocation":"2050:9:1","nodeType":"FunctionDefinition","parameters":{"id":426,"nodeType":"ParameterList","parameters":[{"constant":false,"id":425,"mutability":"mutable","name":"newOwner","nameLocation":"2068:8:1","nodeType":"VariableDeclaration","scope":442,"src":"2060:16:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":424,"name":"address","nodeType":"ElementaryTypeName","src":"2060:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2059:18:1"},"returnParameters":{"id":427,"nodeType":"ParameterList","parameters":[],"src":"2086:0:1"},"scope":443,"src":"2041:169:1","stateMutability":"nonpayable","virtual":false,"visibility":"private"}],"scope":444,"src":"585:1627:1","usedErrors":[]}],"src":"33:2180:1"},"id":1},"lib/openzeppelin-contracts/contracts/utils/Context.sol":{"ast":{"absolutePath":"lib/openzeppelin-contracts/contracts/utils/Context.sol","exportedSymbols":{"Context":[2146]},"id":2147,"license":"MIT","nodeType":"SourceUnit","nodes":[{"id":2126,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"33:23:2"},{"abstract":true,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":{"id":2127,"nodeType":"StructuredDocumentation","src":"58:496:2","text":" @dev Provides information about the current execution context, including the\n sender of the transaction and its data. While these are generally available\n via msg.sender and msg.data, they should not be accessed in such a direct\n manner, since when dealing with meta-transactions the account sending and\n paying for execution may not be the actual sender (as far as an application\n is concerned).\n This contract is only required for intermediate, library-like contracts."},"fullyImplemented":true,"id":2146,"linearizedBaseContracts":[2146],"name":"Context","nameLocation":"573:7:2","nodeType":"ContractDefinition","nodes":[{"body":{"id":2135,"nodeType":"Block","src":"649:34:2","statements":[{"expression":{"expression":{"id":2132,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"666:3:2","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":2133,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"666:10:2","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"functionReturnParameters":2131,"id":2134,"nodeType":"Return","src":"659:17:2"}]},"id":2136,"implemented":true,"kind":"function","modifiers":[],"name":"_msgSender","nameLocation":"596:10:2","nodeType":"FunctionDefinition","parameters":{"id":2128,"nodeType":"ParameterList","parameters":[],"src":"606:2:2"},"returnParameters":{"id":2131,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2130,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":2136,"src":"640:7:2","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":2129,"name":"address","nodeType":"ElementaryTypeName","src":"640:7:2","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"639:9:2"},"scope":2146,"src":"587:96:2","stateMutability":"view","virtual":true,"visibility":"internal"},{"body":{"id":2144,"nodeType":"Block","src":"756:32:2","statements":[{"expression":{"expression":{"id":2141,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"773:3:2","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":2142,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"773:8:2","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"functionReturnParameters":2140,"id":2143,"nodeType":"Return","src":"766:15:2"}]},"id":2145,"implemented":true,"kind":"function","modifiers":[],"name":"_msgData","nameLocation":"698:8:2","nodeType":"FunctionDefinition","parameters":{"id":2137,"nodeType":"ParameterList","parameters":[],"src":"706:2:2"},"returnParameters":{"id":2140,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2139,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":2145,"src":"740:14:2","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":2138,"name":"bytes","nodeType":"ElementaryTypeName","src":"740:5:2","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"739:16:2"},"scope":2146,"src":"689:99:2","stateMutability":"view","virtual":true,"visibility":"internal"}],"scope":2147,"src":"555:235:2","usedErrors":[]}],"src":"33:758:2"},"id":2},"src/Greeter.sol":{"ast":{"absolutePath":"src/Greeter.sol","exportedSymbols":{"Context":[2146],"Errors":[9],"Greeter":[60],"Ownable":[443]},"id":61,"license":"Unlicense","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"38:23:3"},{"absolutePath":"lib/openzeppelin-contracts/contracts/access/Ownable.sol","file":"@openzeppelin/contracts/access/Ownable.sol","id":2,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":61,"sourceUnit":444,"src":"63:52:3","symbolAliases":[],"unitAlias":""},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"library","fullyImplemented":true,"id":9,"linearizedBaseContracts":[9],"name":"Errors","nameLocation":"125:6:3","nodeType":"ContractDefinition","nodes":[{"constant":true,"id":5,"mutability":"constant","name":"InvalidBlockNumber","nameLocation":"154:18:3","nodeType":"VariableDeclaration","scope":9,"src":"138:72:3","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":3,"name":"string","nodeType":"ElementaryTypeName","src":"138:6:3","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"value":{"hexValue":"696e76616c696420626c6f636b206e756d6265722c20706c656173652077616974","id":4,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"175:35:3","typeDescriptions":{"typeIdentifier":"t_stringliteral_d1c23f7d2f1d89d9db6fc85cd1c3a6147ee20afc139f9af42aa882f91bb3961a","typeString":"literal_string \"invalid block number, please wait\""},"value":"invalid block number, please wait"},"visibility":"internal"},{"constant":true,"id":8,"mutability":"constant","name":"CannotGm","nameLocation":"232:8:3","nodeType":"VariableDeclaration","scope":9,"src":"216:49:3","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":6,"name":"string","nodeType":"ElementaryTypeName","src":"216:6:3","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"value":{"hexValue":"63616e6e6f74206772656574207769746820676d","id":7,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"243:22:3","typeDescriptions":{"typeIdentifier":"t_stringliteral_ebb1895604b03c59880a03a6a0f18a4ef93dcd282873d14836ac4de66b883c95","typeString":"literal_string \"cannot greet with gm\""},"value":"cannot greet with gm"},"visibility":"internal"}],"scope":61,"src":"117:151:3","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":10,"name":"Ownable","nodeType":"IdentifierPath","referencedDeclaration":443,"src":"290:7:3"},"id":11,"nodeType":"InheritanceSpecifier","src":"290:7:3"}],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":60,"linearizedBaseContracts":[60,443,2146],"name":"Greeter","nameLocation":"279:7:3","nodeType":"ContractDefinition","nodes":[{"constant":false,"functionSelector":"ef690cc0","id":13,"mutability":"mutable","name":"greeting","nameLocation":"318:8:3","nodeType":"VariableDeclaration","scope":60,"src":"304:22:3","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_storage","typeString":"string"},"typeName":{"id":12,"name":"string","nodeType":"ElementaryTypeName","src":"304:6:3","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"public"},{"body":{"id":33,"nodeType":"Block","src":"364:100:3","statements":[{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":24,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":22,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":19,"name":"block","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-4,"src":"382:5:3","typeDescriptions":{"typeIdentifier":"t_magic_block","typeString":"block"}},"id":20,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"number","nodeType":"MemberAccess","src":"382:12:3","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"%","rightExpression":{"hexValue":"3130","id":21,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"397:2:3","typeDescriptions":{"typeIdentifier":"t_rational_10_by_1","typeString":"int_const 10"},"value":"10"},"src":"382:17:3","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"30","id":23,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"403:1:3","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"src":"382:22:3","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"expression":{"id":25,"name":"Errors","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"406:6:3","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Errors_$9_$","typeString":"type(library Errors)"}},"id":26,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"InvalidBlockNumber","nodeType":"MemberAccess","referencedDeclaration":5,"src":"406:25:3","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":18,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"374:7:3","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":27,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"374:58:3","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":28,"nodeType":"ExpressionStatement","src":"374:58:3"},{"expression":{"id":31,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":29,"name":"greeting","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":13,"src":"442:8:3","typeDescriptions":{"typeIdentifier":"t_string_storage","typeString":"string storage ref"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"676d","id":30,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"453:4:3","typeDescriptions":{"typeIdentifier":"t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270","typeString":"literal_string \"gm\""},"value":"gm"},"src":"442:15:3","typeDescriptions":{"typeIdentifier":"t_string_storage","typeString":"string storage ref"}},"id":32,"nodeType":"ExpressionStatement","src":"442:15:3"}]},"functionSelector":"c0129d43","id":34,"implemented":true,"kind":"function","modifiers":[{"id":16,"kind":"modifierInvocation","modifierName":{"id":15,"name":"onlyOwner","nodeType":"IdentifierPath","referencedDeclaration":386,"src":"347:9:3"},"nodeType":"ModifierInvocation","src":"347:9:3"}],"name":"gm","nameLocation":"342:2:3","nodeType":"FunctionDefinition","parameters":{"id":14,"nodeType":"ParameterList","parameters":[],"src":"344:2:3"},"returnParameters":{"id":17,"nodeType":"ParameterList","parameters":[],"src":"364:0:3"},"scope":60,"src":"333:131:3","stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"body":{"id":58,"nodeType":"Block","src":"517:130:3","statements":[{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"id":49,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"arguments":[{"id":43,"name":"_greeting","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":36,"src":"562:9:3","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":41,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"545:3:3","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":42,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodePacked","nodeType":"MemberAccess","src":"545:16:3","typeDescriptions":{"typeIdentifier":"t_function_abiencodepacked_pure$__$returns$_t_bytes_memory_ptr_$","typeString":"function () pure returns (bytes memory)"}},"id":44,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"545:27:3","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":40,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"535:9:3","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":45,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"535:38:3","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"arguments":[{"hexValue":"676d","id":47,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"587:4:3","typeDescriptions":{"typeIdentifier":"t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270","typeString":"literal_string \"gm\""},"value":"gm"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270","typeString":"literal_string \"gm\""}],"id":46,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"577:9:3","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":48,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"577:15:3","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"src":"535:57:3","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"expression":{"id":50,"name":"Errors","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"594:6:3","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Errors_$9_$","typeString":"type(library Errors)"}},"id":51,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"CannotGm","nodeType":"MemberAccess","referencedDeclaration":8,"src":"594:15:3","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":39,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"527:7:3","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":52,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"527:83:3","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":53,"nodeType":"ExpressionStatement","src":"527:83:3"},{"expression":{"id":56,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":54,"name":"greeting","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":13,"src":"620:8:3","typeDescriptions":{"typeIdentifier":"t_string_storage","typeString":"string storage ref"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":55,"name":"_greeting","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":36,"src":"631:9:3","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},"src":"620:20:3","typeDescriptions":{"typeIdentifier":"t_string_storage","typeString":"string storage ref"}},"id":57,"nodeType":"ExpressionStatement","src":"620:20:3"}]},"functionSelector":"ead710c4","id":59,"implemented":true,"kind":"function","modifiers":[],"name":"greet","nameLocation":"479:5:3","nodeType":"FunctionDefinition","parameters":{"id":37,"nodeType":"ParameterList","parameters":[{"constant":false,"id":36,"mutability":"mutable","name":"_greeting","nameLocation":"499:9:3","nodeType":"VariableDeclaration","scope":59,"src":"485:23:3","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":35,"name":"string","nodeType":"ElementaryTypeName","src":"485:6:3","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"484:25:3"},"returnParameters":{"id":38,"nodeType":"ParameterList","parameters":[],"src":"517:0:3"},"scope":60,"src":"470:177:3","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":61,"src":"270:379:3","usedErrors":[]}],"src":"38:612:3"},"id":3},"src/test/Greeter.t.sol":{"ast":{"absolutePath":"src/test/Greeter.t.sol","exportedSymbols":{"Context":[2146],"DSTest":[2124],"Errors":[9],"Gm":[207],"Greet":[129],"Greeter":[60],"GreeterTest":[309],"Hevm":[339],"Ownable":[443],"User":[249]},"id":208,"license":"Unlicense","nodeType":"SourceUnit","nodes":[{"id":62,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"38:23:4"},{"absolutePath":"src/test/utils/GreeterTest.sol","file":"./utils/GreeterTest.sol","id":63,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":208,"sourceUnit":310,"src":"63:33:4","symbolAliases":[],"unitAlias":""},{"absolutePath":"src/Greeter.sol","file":"../Greeter.sol","id":65,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":208,"sourceUnit":61,"src":"97:40:4","symbolAliases":[{"foreign":{"id":64,"name":"Errors","nodeType":"Identifier","overloadedDeclarations":[],"src":"106:6:4","typeDescriptions":{}},"nameLocation":"-1:-1:-1"}],"unitAlias":""},{"abstract":false,"baseContracts":[{"baseName":{"id":66,"name":"GreeterTest","nodeType":"IdentifierPath","referencedDeclaration":309,"src":"157:11:4"},"id":67,"nodeType":"InheritanceSpecifier","src":"157:11:4"}],"contractDependencies":[60,249],"contractKind":"contract","fullyImplemented":true,"id":129,"linearizedBaseContracts":[129,309,2124],"name":"Greet","nameLocation":"148:5:4","nodeType":"ContractDefinition","nodes":[{"body":{"id":91,"nodeType":"Block","src":"206:140:4","statements":[{"clauses":[{"block":{"id":77,"nodeType":"Block","src":"238:11:4","statements":[{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":74,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"240:4:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":75,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"240:6:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":76,"nodeType":"ExpressionStatement","src":"240:6:4"}]},"errorName":"","id":78,"nodeType":"TryCatchClause","src":"238:11:4"},{"block":{"id":88,"nodeType":"Block","src":"283:57:4","statements":[{"expression":{"arguments":[{"id":83,"name":"error","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":80,"src":"306:5:4","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"expression":{"id":84,"name":"Errors","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"313:6:4","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Errors_$9_$","typeString":"type(library Errors)"}},"id":85,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"CannotGm","nodeType":"MemberAccess","referencedDeclaration":8,"src":"313:15:4","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":82,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":1977,"src":"297:8:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":86,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"297:32:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":87,"nodeType":"ExpressionStatement","src":"297:32:4"}]},"errorName":"Error","id":89,"nodeType":"TryCatchClause","parameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"error","nameLocation":"276:5:4","nodeType":"VariableDeclaration","scope":89,"src":"262:19:4","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":79,"name":"string","nodeType":"ElementaryTypeName","src":"262:6:4","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"261:21:4"},"src":"250:90:4"}],"externalCall":{"arguments":[{"hexValue":"676d","id":72,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"232:4:4","typeDescriptions":{"typeIdentifier":"t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270","typeString":"literal_string \"gm\""},"value":"gm"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270","typeString":"literal_string \"gm\""}],"expression":{"id":70,"name":"alice","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":263,"src":"220:5:4","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"id":71,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"greet","nodeType":"MemberAccess","referencedDeclaration":239,"src":"220:11:4","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":73,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"220:17:4","tryCall":true,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":90,"nodeType":"TryStatement","src":"216:124:4"}]},"functionSelector":"5306d34d","id":92,"implemented":true,"kind":"function","modifiers":[],"name":"testCannotGm","nameLocation":"184:12:4","nodeType":"FunctionDefinition","parameters":{"id":68,"nodeType":"ParameterList","parameters":[],"src":"196:2:4"},"returnParameters":{"id":69,"nodeType":"ParameterList","parameters":[],"src":"206:0:4"},"scope":129,"src":"175:171:4","stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"body":{"id":108,"nodeType":"Block","src":"389:78:4","statements":[{"expression":{"arguments":[{"hexValue":"6869","id":98,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"411:4:4","typeDescriptions":{"typeIdentifier":"t_stringliteral_7624778dedc75f8b322b9fa1632a610d40b85e106c7d9bf0e743a9ce291b9c6f","typeString":"literal_string \"hi\""},"value":"hi"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_7624778dedc75f8b322b9fa1632a610d40b85e106c7d9bf0e743a9ce291b9c6f","typeString":"literal_string \"hi\""}],"expression":{"id":95,"name":"alice","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":263,"src":"399:5:4","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"id":97,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"greet","nodeType":"MemberAccess","referencedDeclaration":239,"src":"399:11:4","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":99,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"399:17:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":100,"nodeType":"ExpressionStatement","src":"399:17:4"},{"expression":{"arguments":[{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":102,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":260,"src":"435:7:4","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"id":103,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"greeting","nodeType":"MemberAccess","referencedDeclaration":13,"src":"435:16:4","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_string_memory_ptr_$","typeString":"function () view external returns (string memory)"}},"id":104,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"435:18:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"6869","id":105,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"455:4:4","typeDescriptions":{"typeIdentifier":"t_stringliteral_7624778dedc75f8b322b9fa1632a610d40b85e106c7d9bf0e743a9ce291b9c6f","typeString":"literal_string \"hi\""},"value":"hi"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_7624778dedc75f8b322b9fa1632a610d40b85e106c7d9bf0e743a9ce291b9c6f","typeString":"literal_string \"hi\""}],"id":101,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":1977,"src":"426:8:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":106,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"426:34:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":107,"nodeType":"ExpressionStatement","src":"426:34:4"}]},"functionSelector":"e0747015","id":109,"implemented":true,"kind":"function","modifiers":[],"name":"testCanSetGreeting","nameLocation":"361:18:4","nodeType":"FunctionDefinition","parameters":{"id":93,"nodeType":"ParameterList","parameters":[],"src":"379:2:4"},"returnParameters":{"id":94,"nodeType":"ParameterList","parameters":[],"src":"389:0:4"},"scope":129,"src":"352:115:4","stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"body":{"id":127,"nodeType":"Block","src":"538:86:4","statements":[{"expression":{"arguments":[{"id":117,"name":"greeting","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":111,"src":"560:8:4","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":114,"name":"alice","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":263,"src":"548:5:4","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"id":116,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"greet","nodeType":"MemberAccess","referencedDeclaration":239,"src":"548:11:4","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":118,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"548:21:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":119,"nodeType":"ExpressionStatement","src":"548:21:4"},{"expression":{"arguments":[{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":121,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":260,"src":"588:7:4","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"id":122,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"greeting","nodeType":"MemberAccess","referencedDeclaration":13,"src":"588:16:4","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_string_memory_ptr_$","typeString":"function () view external returns (string memory)"}},"id":123,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"588:18:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":124,"name":"greeting","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":111,"src":"608:8:4","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":120,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":1977,"src":"579:8:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":125,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"579:38:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":126,"nodeType":"ExpressionStatement","src":"579:38:4"}]},"functionSelector":"6721f718","id":128,"implemented":true,"kind":"function","modifiers":[],"name":"testWorksForAllGreetings","nameLocation":"482:24:4","nodeType":"FunctionDefinition","parameters":{"id":112,"nodeType":"ParameterList","parameters":[{"constant":false,"id":111,"mutability":"mutable","name":"greeting","nameLocation":"521:8:4","nodeType":"VariableDeclaration","scope":128,"src":"507:22:4","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":110,"name":"string","nodeType":"ElementaryTypeName","src":"507:6:4","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"506:24:4"},"returnParameters":{"id":113,"nodeType":"ParameterList","parameters":[],"src":"538:0:4"},"scope":129,"src":"473:151:4","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":208,"src":"139:488:4","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":130,"name":"GreeterTest","nodeType":"IdentifierPath","referencedDeclaration":309,"src":"644:11:4"},"id":131,"nodeType":"InheritanceSpecifier","src":"644:11:4"}],"contractDependencies":[60,249],"contractKind":"contract","fullyImplemented":true,"id":207,"linearizedBaseContracts":[207,309,2124],"name":"Gm","nameLocation":"638:2:4","nodeType":"ContractDefinition","nodes":[{"body":{"id":152,"nodeType":"Block","src":"707:94:4","statements":[{"expression":{"arguments":[{"hexValue":"3130","id":137,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"727:2:4","typeDescriptions":{"typeIdentifier":"t_rational_10_by_1","typeString":"int_const 10"},"value":"10"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_10_by_1","typeString":"int_const 10"}],"expression":{"id":134,"name":"hevm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":257,"src":"717:4:4","typeDescriptions":{"typeIdentifier":"t_contract$_Hevm_$339","typeString":"contract Hevm"}},"id":136,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"roll","nodeType":"MemberAccess","referencedDeclaration":321,"src":"717:9:4","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_uint256_$returns$__$","typeString":"function (uint256) external"}},"id":138,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"717:13:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":139,"nodeType":"ExpressionStatement","src":"717:13:4"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":140,"name":"alice","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":263,"src":"740:5:4","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"id":142,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"gm","nodeType":"MemberAccess","referencedDeclaration":248,"src":"740:8:4","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":143,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"740:10:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":144,"nodeType":"ExpressionStatement","src":"740:10:4"},{"expression":{"arguments":[{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":146,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":260,"src":"769:7:4","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"id":147,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"greeting","nodeType":"MemberAccess","referencedDeclaration":13,"src":"769:16:4","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_string_memory_ptr_$","typeString":"function () view external returns (string memory)"}},"id":148,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"769:18:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"676d","id":149,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"789:4:4","typeDescriptions":{"typeIdentifier":"t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270","typeString":"literal_string \"gm\""},"value":"gm"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_71b78290913af2addd8fcbe5766de306af2c8afbc466ca891e207f73638c7270","typeString":"literal_string \"gm\""}],"id":145,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":1977,"src":"760:8:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":150,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"760:34:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":151,"nodeType":"ExpressionStatement","src":"760:34:4"}]},"functionSelector":"2a11c35d","id":153,"implemented":true,"kind":"function","modifiers":[],"name":"testOwnerCanGmOnGoodBlocks","nameLocation":"671:26:4","nodeType":"FunctionDefinition","parameters":{"id":132,"nodeType":"ParameterList","parameters":[],"src":"697:2:4"},"returnParameters":{"id":133,"nodeType":"ParameterList","parameters":[],"src":"707:0:4"},"scope":207,"src":"662:139:4","stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"body":{"id":182,"nodeType":"Block","src":"854:166:4","statements":[{"expression":{"arguments":[{"hexValue":"3131","id":159,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"874:2:4","typeDescriptions":{"typeIdentifier":"t_rational_11_by_1","typeString":"int_const 11"},"value":"11"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_11_by_1","typeString":"int_const 11"}],"expression":{"id":156,"name":"hevm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":257,"src":"864:4:4","typeDescriptions":{"typeIdentifier":"t_contract$_Hevm_$339","typeString":"contract Hevm"}},"id":158,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"roll","nodeType":"MemberAccess","referencedDeclaration":321,"src":"864:9:4","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_uint256_$returns$__$","typeString":"function (uint256) external"}},"id":160,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"864:13:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":161,"nodeType":"ExpressionStatement","src":"864:13:4"},{"clauses":[{"block":{"id":168,"nodeType":"Block","src":"902:11:4","statements":[{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":165,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"904:4:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":166,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"904:6:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":167,"nodeType":"ExpressionStatement","src":"904:6:4"}]},"errorName":"","id":169,"nodeType":"TryCatchClause","src":"902:11:4"},{"block":{"id":179,"nodeType":"Block","src":"947:67:4","statements":[{"expression":{"arguments":[{"id":174,"name":"error","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":171,"src":"970:5:4","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"expression":{"id":175,"name":"Errors","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"977:6:4","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Errors_$9_$","typeString":"type(library Errors)"}},"id":176,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"InvalidBlockNumber","nodeType":"MemberAccess","referencedDeclaration":5,"src":"977:25:4","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"id":173,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":1977,"src":"961:8:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":177,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"961:42:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":178,"nodeType":"ExpressionStatement","src":"961:42:4"}]},"errorName":"Error","id":180,"nodeType":"TryCatchClause","parameters":{"id":172,"nodeType":"ParameterList","parameters":[{"constant":false,"id":171,"mutability":"mutable","name":"error","nameLocation":"940:5:4","nodeType":"VariableDeclaration","scope":180,"src":"926:19:4","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":170,"name":"string","nodeType":"ElementaryTypeName","src":"926:6:4","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"925:21:4"},"src":"914:100:4"}],"externalCall":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":162,"name":"alice","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":263,"src":"891:5:4","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"id":163,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"gm","nodeType":"MemberAccess","referencedDeclaration":248,"src":"891:8:4","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":164,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"891:10:4","tryCall":true,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":181,"nodeType":"TryStatement","src":"887:127:4"}]},"functionSelector":"a474cdb0","id":183,"implemented":true,"kind":"function","modifiers":[],"name":"testOwnerCannotGmOnBadBlocks","nameLocation":"816:28:4","nodeType":"FunctionDefinition","parameters":{"id":154,"nodeType":"ParameterList","parameters":[],"src":"844:2:4"},"returnParameters":{"id":155,"nodeType":"ParameterList","parameters":[],"src":"854:0:4"},"scope":207,"src":"807:213:4","stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"body":{"id":205,"nodeType":"Block","src":"1065:150:4","statements":[{"clauses":[{"block":{"id":192,"nodeType":"Block","src":"1088:11:4","statements":[{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":189,"name":"fail","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":569,"src":"1090:4:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":190,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1090:6:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":191,"nodeType":"ExpressionStatement","src":"1090:6:4"}]},"errorName":"","id":193,"nodeType":"TryCatchClause","src":"1088:11:4"},{"block":{"id":202,"nodeType":"Block","src":"1133:76:4","statements":[{"expression":{"arguments":[{"id":198,"name":"error","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":195,"src":"1156:5:4","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572","id":199,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1163:34:4","typeDescriptions":{"typeIdentifier":"t_stringliteral_9924ebdf1add33d25d4ef888e16131f0a5687b0580a36c21b5c301a6c462effe","typeString":"literal_string \"Ownable: caller is not the owner\""},"value":"Ownable: caller is not the owner"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_9924ebdf1add33d25d4ef888e16131f0a5687b0580a36c21b5c301a6c462effe","typeString":"literal_string \"Ownable: caller is not the owner\""}],"id":197,"name":"assertEq","nodeType":"Identifier","overloadedDeclarations":[658,683,713,738,797,822,852,877,1977,2012],"referencedDeclaration":1977,"src":"1147:8:4","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory)"}},"id":200,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1147:51:4","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":201,"nodeType":"ExpressionStatement","src":"1147:51:4"}]},"errorName":"Error","id":203,"nodeType":"TryCatchClause","parameters":{"id":196,"nodeType":"ParameterList","parameters":[{"constant":false,"id":195,"mutability":"mutable","name":"error","nameLocation":"1126:5:4","nodeType":"VariableDeclaration","scope":203,"src":"1112:19:4","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":194,"name":"string","nodeType":"ElementaryTypeName","src":"1112:6:4","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1111:21:4"},"src":"1100:109:4"}],"externalCall":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":186,"name":"bob","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":266,"src":"1079:3:4","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"id":187,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"gm","nodeType":"MemberAccess","referencedDeclaration":248,"src":"1079:6:4","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":188,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1079:8:4","tryCall":true,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":204,"nodeType":"TryStatement","src":"1075:134:4"}]},"functionSelector":"8dc5d380","id":206,"implemented":true,"kind":"function","modifiers":[],"name":"testNonOwnerCannotGm","nameLocation":"1035:20:4","nodeType":"FunctionDefinition","parameters":{"id":184,"nodeType":"ParameterList","parameters":[],"src":"1055:2:4"},"returnParameters":{"id":185,"nodeType":"ParameterList","parameters":[],"src":"1065:0:4"},"scope":207,"src":"1026:189:4","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":208,"src":"629:588:4","usedErrors":[]}],"src":"38:1181:4"},"id":4},"src/test/utils/GreeterTest.sol":{"ast":{"absolutePath":"src/test/utils/GreeterTest.sol","exportedSymbols":{"Context":[2146],"DSTest":[2124],"Errors":[9],"Greeter":[60],"GreeterTest":[309],"Hevm":[339],"Ownable":[443],"User":[249]},"id":310,"license":"Unlicense","nodeType":"SourceUnit","nodes":[{"id":209,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"38:23:5"},{"absolutePath":"lib/ds-test/src/test.sol","file":"ds-test/test.sol","id":210,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":310,"sourceUnit":2125,"src":"62:26:5","symbolAliases":[],"unitAlias":""},{"absolutePath":"src/Greeter.sol","file":"../../Greeter.sol","id":211,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":310,"sourceUnit":61,"src":"90:27:5","symbolAliases":[],"unitAlias":""},{"absolutePath":"src/test/utils/Hevm.sol","file":"./Hevm.sol","id":212,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":310,"sourceUnit":340,"src":"118:20:5","symbolAliases":[],"unitAlias":""},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":249,"linearizedBaseContracts":[249],"name":"User","nameLocation":"149:4:5","nodeType":"ContractDefinition","nodes":[{"constant":false,"id":215,"mutability":"mutable","name":"greeter","nameLocation":"177:7:5","nodeType":"VariableDeclaration","scope":249,"src":"160:24:5","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"},"typeName":{"id":214,"nodeType":"UserDefinedTypeName","pathNode":{"id":213,"name":"Greeter","nodeType":"IdentifierPath","referencedDeclaration":60,"src":"160:7:5"},"referencedDeclaration":60,"src":"160:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"visibility":"internal"},{"body":{"id":226,"nodeType":"Block","src":"221:44:5","statements":[{"expression":{"id":224,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":220,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"231:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"id":222,"name":"_greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":217,"src":"249:8:5","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":221,"name":"Greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":60,"src":"241:7:5","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Greeter_$60_$","typeString":"type(contract Greeter)"}},"id":223,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"241:17:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"src":"231:27:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"id":225,"nodeType":"ExpressionStatement","src":"231:27:5"}]},"id":227,"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","nodeType":"FunctionDefinition","parameters":{"id":218,"nodeType":"ParameterList","parameters":[{"constant":false,"id":217,"mutability":"mutable","name":"_greeter","nameLocation":"211:8:5","nodeType":"VariableDeclaration","scope":227,"src":"203:16:5","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":216,"name":"address","nodeType":"ElementaryTypeName","src":"203:7:5","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"202:18:5"},"returnParameters":{"id":219,"nodeType":"ParameterList","parameters":[],"src":"221:0:5"},"scope":249,"src":"191:74:5","stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"body":{"id":238,"nodeType":"Block","src":"317:40:5","statements":[{"expression":{"arguments":[{"id":235,"name":"greeting","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":229,"src":"341:8:5","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":232,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"327:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"id":234,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"greet","nodeType":"MemberAccess","referencedDeclaration":59,"src":"327:13:5","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":236,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"327:23:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":237,"nodeType":"ExpressionStatement","src":"327:23:5"}]},"functionSelector":"ead710c4","id":239,"implemented":true,"kind":"function","modifiers":[],"name":"greet","nameLocation":"280:5:5","nodeType":"FunctionDefinition","parameters":{"id":230,"nodeType":"ParameterList","parameters":[{"constant":false,"id":229,"mutability":"mutable","name":"greeting","nameLocation":"300:8:5","nodeType":"VariableDeclaration","scope":239,"src":"286:22:5","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":228,"name":"string","nodeType":"ElementaryTypeName","src":"286:6:5","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"285:24:5"},"returnParameters":{"id":231,"nodeType":"ParameterList","parameters":[],"src":"317:0:5"},"scope":249,"src":"271:86:5","stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"body":{"id":247,"nodeType":"Block","src":"384:29:5","statements":[{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":242,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"394:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"id":244,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"gm","nodeType":"MemberAccess","referencedDeclaration":34,"src":"394:10:5","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":245,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"394:12:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":246,"nodeType":"ExpressionStatement","src":"394:12:5"}]},"functionSelector":"c0129d43","id":248,"implemented":true,"kind":"function","modifiers":[],"name":"gm","nameLocation":"372:2:5","nodeType":"FunctionDefinition","parameters":{"id":240,"nodeType":"ParameterList","parameters":[],"src":"374:2:5"},"returnParameters":{"id":241,"nodeType":"ParameterList","parameters":[],"src":"384:0:5"},"scope":249,"src":"363:50:5","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":310,"src":"140:275:5","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":250,"name":"DSTest","nodeType":"IdentifierPath","referencedDeclaration":2124,"src":"441:6:5"},"id":251,"nodeType":"InheritanceSpecifier","src":"441:6:5"}],"contractDependencies":[60,249],"contractKind":"contract","fullyImplemented":true,"id":309,"linearizedBaseContracts":[309,2124],"name":"GreeterTest","nameLocation":"426:11:5","nodeType":"ContractDefinition","nodes":[{"constant":true,"id":257,"mutability":"constant","name":"hevm","nameLocation":"477:4:5","nodeType":"VariableDeclaration","scope":309,"src":"454:48:5","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Hevm_$339","typeString":"contract Hevm"},"typeName":{"id":253,"nodeType":"UserDefinedTypeName","pathNode":{"id":252,"name":"Hevm","nodeType":"IdentifierPath","referencedDeclaration":339,"src":"454:4:5"},"referencedDeclaration":339,"src":"454:4:5","typeDescriptions":{"typeIdentifier":"t_contract$_Hevm_$339","typeString":"contract Hevm"}},"value":{"arguments":[{"id":255,"name":"HEVM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":551,"src":"489:12:5","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":254,"name":"Hevm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":339,"src":"484:4:5","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Hevm_$339_$","typeString":"type(contract Hevm)"}},"id":256,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"484:18:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Hevm_$339","typeString":"contract Hevm"}},"visibility":"internal"},{"constant":false,"id":260,"mutability":"mutable","name":"greeter","nameLocation":"543:7:5","nodeType":"VariableDeclaration","scope":309,"src":"526:24:5","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"},"typeName":{"id":259,"nodeType":"UserDefinedTypeName","pathNode":{"id":258,"name":"Greeter","nodeType":"IdentifierPath","referencedDeclaration":60,"src":"526:7:5"},"referencedDeclaration":60,"src":"526:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"visibility":"internal"},{"constant":false,"id":263,"mutability":"mutable","name":"alice","nameLocation":"584:5:5","nodeType":"VariableDeclaration","scope":309,"src":"570:19:5","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"},"typeName":{"id":262,"nodeType":"UserDefinedTypeName","pathNode":{"id":261,"name":"User","nodeType":"IdentifierPath","referencedDeclaration":249,"src":"570:4:5"},"referencedDeclaration":249,"src":"570:4:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"visibility":"internal"},{"constant":false,"id":266,"mutability":"mutable","name":"bob","nameLocation":"609:3:5","nodeType":"VariableDeclaration","scope":309,"src":"595:17:5","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"},"typeName":{"id":265,"nodeType":"UserDefinedTypeName","pathNode":{"id":264,"name":"User","nodeType":"IdentifierPath","referencedDeclaration":249,"src":"595:4:5"},"referencedDeclaration":249,"src":"595:4:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"visibility":"internal"},{"body":{"id":307,"nodeType":"Block","src":"651:177:5","statements":[{"expression":{"id":274,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":269,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":260,"src":"661:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[],"expression":{"argumentTypes":[],"id":272,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"671:11:5","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$__$returns$_t_contract$_Greeter_$60_$","typeString":"function () returns (contract Greeter)"},"typeName":{"id":271,"nodeType":"UserDefinedTypeName","pathNode":{"id":270,"name":"Greeter","nodeType":"IdentifierPath","referencedDeclaration":60,"src":"675:7:5"},"referencedDeclaration":60,"src":"675:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}}},"id":273,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"671:13:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"src":"661:23:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"id":275,"nodeType":"ExpressionStatement","src":"661:23:5"},{"expression":{"id":285,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":276,"name":"alice","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":263,"src":"694:5:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"arguments":[{"id":282,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":260,"src":"719:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}],"id":281,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"711:7:5","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":280,"name":"address","nodeType":"ElementaryTypeName","src":"711:7:5","typeDescriptions":{}}},"id":283,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"711:16:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":279,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"702:8:5","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_address_$returns$_t_contract$_User_$249_$","typeString":"function (address) returns (contract User)"},"typeName":{"id":278,"nodeType":"UserDefinedTypeName","pathNode":{"id":277,"name":"User","nodeType":"IdentifierPath","referencedDeclaration":249,"src":"706:4:5"},"referencedDeclaration":249,"src":"706:4:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}}},"id":284,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"702:26:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"src":"694:34:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"id":286,"nodeType":"ExpressionStatement","src":"694:34:5"},{"expression":{"id":296,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":287,"name":"bob","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":266,"src":"738:3:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"arguments":[{"id":293,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":260,"src":"761:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}],"id":292,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"753:7:5","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":291,"name":"address","nodeType":"ElementaryTypeName","src":"753:7:5","typeDescriptions":{}}},"id":294,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"753:16:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":290,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"744:8:5","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_address_$returns$_t_contract$_User_$249_$","typeString":"function (address) returns (contract User)"},"typeName":{"id":289,"nodeType":"UserDefinedTypeName","pathNode":{"id":288,"name":"User","nodeType":"IdentifierPath","referencedDeclaration":249,"src":"748:4:5"},"referencedDeclaration":249,"src":"748:4:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}}},"id":295,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"744:26:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"src":"738:32:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}},"id":297,"nodeType":"ExpressionStatement","src":"738:32:5"},{"expression":{"arguments":[{"arguments":[{"id":303,"name":"alice","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":263,"src":"814:5:5","typeDescriptions":{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_User_$249","typeString":"contract User"}],"id":302,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"806:7:5","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":301,"name":"address","nodeType":"ElementaryTypeName","src":"806:7:5","typeDescriptions":{}}},"id":304,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"806:14:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":298,"name":"greeter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":260,"src":"780:7:5","typeDescriptions":{"typeIdentifier":"t_contract$_Greeter_$60","typeString":"contract Greeter"}},"id":300,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"transferOwnership","nodeType":"MemberAccess","referencedDeclaration":423,"src":"780:25:5","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":305,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"780:41:5","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":306,"nodeType":"ExpressionStatement","src":"780:41:5"}]},"functionSelector":"0a9254e4","id":308,"implemented":true,"kind":"function","modifiers":[],"name":"setUp","nameLocation":"628:5:5","nodeType":"FunctionDefinition","parameters":{"id":267,"nodeType":"ParameterList","parameters":[],"src":"633:2:5"},"returnParameters":{"id":268,"nodeType":"ParameterList","parameters":[],"src":"651:0:5"},"scope":309,"src":"619:209:5","stateMutability":"nonpayable","virtual":true,"visibility":"public"}],"scope":310,"src":"417:413:5","usedErrors":[]}],"src":"38:793:5"},"id":5},"src/test/utils/Hevm.sol":{"ast":{"absolutePath":"src/test/utils/Hevm.sol","exportedSymbols":{"Hevm":[339]},"id":340,"license":"Unlicense","nodeType":"SourceUnit","nodes":[{"id":311,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"38:23:6"},{"abstract":true,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":false,"id":339,"linearizedBaseContracts":[339],"name":"Hevm","nameLocation":"81:4:6","nodeType":"ContractDefinition","nodes":[{"functionSelector":"e5d6bf02","id":316,"implemented":false,"kind":"function","modifiers":[],"name":"warp","nameLocation":"138:4:6","nodeType":"FunctionDefinition","parameters":{"id":314,"nodeType":"ParameterList","parameters":[{"constant":false,"id":313,"mutability":"mutable","name":"x","nameLocation":"148:1:6","nodeType":"VariableDeclaration","scope":316,"src":"143:6:6","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":312,"name":"uint","nodeType":"ElementaryTypeName","src":"143:4:6","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"142:8:6"},"returnParameters":{"id":315,"nodeType":"ParameterList","parameters":[],"src":"165:0:6"},"scope":339,"src":"129:37:6","stateMutability":"nonpayable","virtual":true,"visibility":"public"},{"functionSelector":"1f7b4f30","id":321,"implemented":false,"kind":"function","modifiers":[],"name":"roll","nameLocation":"214:4:6","nodeType":"FunctionDefinition","parameters":{"id":319,"nodeType":"ParameterList","parameters":[{"constant":false,"id":318,"mutability":"mutable","name":"x","nameLocation":"224:1:6","nodeType":"VariableDeclaration","scope":321,"src":"219:6:6","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":317,"name":"uint","nodeType":"ElementaryTypeName","src":"219:4:6","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"218:8:6"},"returnParameters":{"id":320,"nodeType":"ParameterList","parameters":[],"src":"241:0:6"},"scope":339,"src":"205:37:6","stateMutability":"nonpayable","virtual":true,"visibility":"public"},{"functionSelector":"70ca10bb","id":330,"implemented":false,"kind":"function","modifiers":[],"name":"store","nameLocation":"302:5:6","nodeType":"FunctionDefinition","parameters":{"id":328,"nodeType":"ParameterList","parameters":[{"constant":false,"id":323,"mutability":"mutable","name":"c","nameLocation":"316:1:6","nodeType":"VariableDeclaration","scope":330,"src":"308:9:6","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":322,"name":"address","nodeType":"ElementaryTypeName","src":"308:7:6","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":325,"mutability":"mutable","name":"loc","nameLocation":"327:3:6","nodeType":"VariableDeclaration","scope":330,"src":"319:11:6","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":324,"name":"bytes32","nodeType":"ElementaryTypeName","src":"319:7:6","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":327,"mutability":"mutable","name":"val","nameLocation":"340:3:6","nodeType":"VariableDeclaration","scope":330,"src":"332:11:6","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":326,"name":"bytes32","nodeType":"ElementaryTypeName","src":"332:7:6","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"src":"307:37:6"},"returnParameters":{"id":329,"nodeType":"ParameterList","parameters":[],"src":"359:0:6"},"scope":339,"src":"293:67:6","stateMutability":"nonpayable","virtual":true,"visibility":"public"},{"functionSelector":"89160467","id":338,"implemented":false,"kind":"function","modifiers":[],"name":"ffi","nameLocation":"374:3:6","nodeType":"FunctionDefinition","parameters":{"id":334,"nodeType":"ParameterList","parameters":[{"constant":false,"id":333,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":338,"src":"378:17:6","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_array$_t_string_calldata_ptr_$dyn_calldata_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":331,"name":"string","nodeType":"ElementaryTypeName","src":"378:6:6","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":332,"nodeType":"ArrayTypeName","src":"378:8:6","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"377:19:6"},"returnParameters":{"id":337,"nodeType":"ParameterList","parameters":[{"constant":false,"id":336,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":338,"src":"423:12:6","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":335,"name":"bytes","nodeType":"ElementaryTypeName","src":"423:5:6","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"422:14:6"},"scope":339,"src":"365:72:6","stateMutability":"nonpayable","virtual":true,"visibility":"external"}],"scope":340,"src":"63:376:6","usedErrors":[]}],"src":"38:402:6"},"id":6}}} diff --git a/testdata/README.md b/testdata/README.md new file mode 100644 index 000000000000..d2be86ecfc57 --- /dev/null +++ b/testdata/README.md @@ -0,0 +1,11 @@ +## Foundry Tests + +A test suite that tests different aspects of Foundry. + +### Structure + +- [`core`](core): Tests for fundamental aspects of Foundry +- [`logs`](logs): Tests for Foundry logging capabilities +- [`cheats`](cheats): Tests for Foundry cheatcodes +- [`fuzz`](fuzz): Tests for the Foundry fuzzer +- [`fuzz`](fuzz): Tests for Foundry tracer diff --git a/testdata/cheats/Addr.t.sol b/testdata/cheats/Addr.t.sol new file mode 100644 index 000000000000..d9b7384b4564 --- /dev/null +++ b/testdata/cheats/Addr.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract AddrTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testFailPrivKeyZero() public { + cheats.addr(0); + } + + function testAddr() public { + uint pk = 77814517325470205911140941194401928579557062014761831930645393041380819009408; + address expected = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; + + assertEq(cheats.addr(pk), expected, "expected address did not match"); + } +} diff --git a/testdata/cheats/Assume.t.sol b/testdata/cheats/Assume.t.sol new file mode 100644 index 000000000000..5375c11a0cfd --- /dev/null +++ b/testdata/cheats/Assume.t.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract AssumeTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testAssume(uint8 x) public { + cheats.assume(x < 2 ** 7); + assertTrue(x < 2 ** 7, "did not discard inputs"); + } +} diff --git a/testdata/cheats/Cheats.sol b/testdata/cheats/Cheats.sol new file mode 100644 index 000000000000..58370292d875 --- /dev/null +++ b/testdata/cheats/Cheats.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +interface Cheats { + // Set block.timestamp (newTimestamp) + function warp(uint256) external; + // Set block.height (newHeight) + function roll(uint256) external; + // Set block.basefee (newBasefee) + function fee(uint256) external; + // Loads a storage slot from an address (who, slot) + function load(address,bytes32) external returns (bytes32); + // Stores a value to an address' storage slot, (who, slot, value) + function store(address,bytes32,bytes32) external; + // Signs data, (privateKey, digest) => (v, r, s) + function sign(uint256,bytes32) external returns (uint8,bytes32,bytes32); + // Gets address for a given private key, (privateKey) => (address) + function addr(uint256) external returns (address); + // Performs a foreign function call via terminal, (stringInputs) => (result) + function ffi(string[] calldata) external returns (bytes memory); + // Sets the *next* call's msg.sender to be the input address + function prank(address) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called + function startPrank(address) external; + // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input + function prank(address,address) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input + function startPrank(address,address) external; + // Resets subsequent calls' msg.sender to be `address(this)` + function stopPrank() external; + // Sets an address' balance, (who, newBalance) + function deal(address, uint256) external; + // Sets an address' code, (who, newCode) + function etch(address, bytes calldata) external; + // Expects an error on next call + function expectRevert() external; + function expectRevert(bytes calldata) external; + function expectRevert(bytes4) external; + // Record all storage reads and writes + function record() external; + // Gets all accessed reads and write slot from a recording session, for a given address + function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes); + // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + // Call this function, then emit an event, then call a function. Internally after the call, we check if + // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) + function expectEmit(bool,bool,bool,bool) external; + // Mocks a call to an address, returning specified data. + // Calldata can either be strict or a partial match, e.g. if you only + // pass a Solidity selector to the expected calldata, then the entire Solidity + // function will be mocked. + function mockCall(address,bytes calldata,bytes calldata) external; + // Clears all mocked calls + function clearMockedCalls() external; + // Expect a call to an address with the specified calldata. + // Calldata can either be strict or a partial match + function expectCall(address,bytes calldata) external; + // Gets the code from an artifact file. Takes in the relative path to the json file + function getCode(string calldata) external returns (bytes memory); + // Labels an address in call traces + function label(address, string calldata) external; + // If the condition is false, discard this run's fuzz inputs and generate new ones + function assume(bool) external; +} diff --git a/testdata/cheats/Deal.t.sol b/testdata/cheats/Deal.t.sol new file mode 100644 index 000000000000..5c7288514c7e --- /dev/null +++ b/testdata/cheats/Deal.t.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract DealTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testDeal(uint256 amount) public { + address target = address(1); + assertEq(target.balance, 0, "initial balance incorrect"); + + // Give half the amount + cheats.deal(target, amount / 2); + assertEq(target.balance, amount / 2, "half balance is incorrect"); + + // Give the entire amount to check that deal is not additive + cheats.deal(target, amount); + assertEq(target.balance, amount, "deal did not overwrite balance"); + } +} diff --git a/testdata/cheats/Etch.t.sol b/testdata/cheats/Etch.t.sol new file mode 100644 index 000000000000..eae197e289e6 --- /dev/null +++ b/testdata/cheats/Etch.t.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract EtchTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testEtch() public { + address target = address(10); + bytes memory code = hex"1010"; + cheats.etch(target, code); + assertEq(string(code), string(target.code)); + } +} diff --git a/testdata/cheats/ExpectCall.t.sol b/testdata/cheats/ExpectCall.t.sol new file mode 100644 index 000000000000..4e9023abe945 --- /dev/null +++ b/testdata/cheats/ExpectCall.t.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract Contract { + function numberA() public pure returns (uint256) { + return 1; + } + + function numberB() public pure returns (uint256) { + return 2; + } + + function add(uint256 a, uint256 b) public pure returns (uint256) { + return a + b; + } +} + +contract NestedContract { + Contract private inner; + + constructor(Contract _inner) { + inner = _inner; + } + + function sum() public view returns (uint256) { + return inner.numberA() + inner.numberB(); + } + + function hello() public pure returns (string memory) { + return "hi"; + } +} + +contract ExpectCallTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testExpectCallWithData() public { + Contract target = new Contract(); + cheats.expectCall( + address(target), + abi.encodeWithSelector(target.add.selector, 1, 2) + ); + target.add(1, 2); + } + + function testFailExpectCallWithData() public { + Contract target = new Contract(); + cheats.expectCall( + address(target), + abi.encodeWithSelector(target.add.selector, 1, 2) + ); + target.add(3, 3); + } + + function testExpectInnerCall() public { + Contract inner = new Contract(); + NestedContract target = new NestedContract(inner); + + cheats.expectCall( + address(inner), + abi.encodeWithSelector(inner.numberB.selector) + ); + target.sum(); + } + + function testFailExpectInnerCall() public { + Contract inner = new Contract(); + NestedContract target = new NestedContract(inner); + + cheats.expectCall( + address(inner), + abi.encodeWithSelector(inner.numberB.selector) + ); + + // this function does not call inner + target.hello(); + } + + function testExpectSelectorCall() public { + Contract target = new Contract(); + cheats.expectCall( + address(target), + abi.encodeWithSelector(target.add.selector) + ); + target.add(5, 5); + } + + function testFailExpectSelectorCall() public { + Contract target = new Contract(); + cheats.expectCall( + address(target), + abi.encodeWithSelector(target.add.selector) + ); + } + + function testFailExpectCallWithMoreParameters() public { + Contract target = new Contract(); + cheats.expectCall( + address(target), + abi.encodeWithSelector(target.add.selector, 3, 3, 3) + ); + target.add(3, 3); + } +} diff --git a/testdata/cheats/ExpectEmit.t.sol b/testdata/cheats/ExpectEmit.t.sol new file mode 100644 index 000000000000..7a2d78cc0f6f --- /dev/null +++ b/testdata/cheats/ExpectEmit.t.sol @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract Emitter { + event Something( + uint256 indexed topic1, + uint256 indexed topic2, + uint256 indexed topic3, + uint256 data + ); + + function emitEvent( + uint256 topic1, + uint256 topic2, + uint256 topic3, + uint256 data + ) public { + emit Something(topic1, topic2, topic3, data); + } + + function emitMultiple( + uint256[2] memory topic1, + uint256[2] memory topic2, + uint256[2] memory topic3, + uint256[2] memory data + ) public { + emit Something(topic1[0], topic2[0], topic3[0], data[0]); + emit Something(topic1[1], topic2[1], topic3[1], data[1]); + } + + function emitNested( + Emitter inner, + uint256 topic1, + uint256 topic2, + uint256 topic3, + uint256 data + ) public { + inner.emitEvent(topic1, topic2, topic3, data); + } +} + +contract ExpectEmitTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + Emitter emitter; + + event Something( + uint256 indexed topic1, + uint256 indexed topic2, + uint256 indexed topic3, + uint256 data + ); + + function setUp() public { + emitter = new Emitter(); + } + + function testFailExpectEmitDanglingNoReference() public { + cheats.expectEmit(false, false, false, false); + } + + function testFailExpectEmitDanglingWithReference() public { + cheats.expectEmit(false, false, false, false); + emit Something(1, 2, 3, 4); + } + + /// The topics that are not checked are altered to be incorrect + /// compared to the reference. + function testExpectEmit( + bool checkTopic1, + bool checkTopic2, + bool checkTopic3, + bool checkData, + uint128 topic1, + uint128 topic2, + uint128 topic3, + uint128 data + ) public { + uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) : uint256(topic1) + 1; + uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) : uint256(topic2) + 1; + uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) : uint256(topic3) + 1; + uint256 transformedData = checkData ? uint256(data) : uint256(data) + 1; + + cheats.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + + emit Something(topic1, topic2, topic3, data); + emitter.emitEvent(transformedTopic1, transformedTopic2, transformedTopic3, transformedData); + } + + /// The topics that are checked are altered to be incorrect + /// compared to the reference. + function testFailExpectEmit( + bool checkTopic1, + bool checkTopic2, + bool checkTopic3, + bool checkData, + uint128 topic1, + uint128 topic2, + uint128 topic3, + uint128 data + ) public { + cheats.assume(checkTopic1 || checkTopic2 || checkTopic3 || checkData); + + uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) + 1 : uint256(topic1); + uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) + 1 : uint256(topic2); + uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) + 1 : uint256(topic3); + uint256 transformedData = checkData ? uint256(data) + 1 : uint256(data); + + cheats.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + + emit Something(topic1, topic2, topic3, data); + emitter.emitEvent(transformedTopic1, transformedTopic2, transformedTopic3, transformedData); + } + + /// The topics that are checked are altered to be incorrect + /// compared to the reference. + function testExpectEmitNested( + bool checkTopic1, + bool checkTopic2, + bool checkTopic3, + bool checkData, + uint128 topic1, + uint128 topic2, + uint128 topic3, + uint128 data + ) public { + Emitter inner = new Emitter(); + + uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) : uint256(topic1) + 1; + uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) : uint256(topic2) + 1; + uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) : uint256(topic3) + 1; + uint256 transformedData = checkData ? uint256(data) : uint256(data) + 1; + + cheats.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + + emit Something(topic1, topic2, topic3, data); + emitter.emitNested(inner, transformedTopic1, transformedTopic2, transformedTopic3, transformedData); + } + + /// The topics that are checked are altered to be incorrect + /// compared to the reference. + function testFailExpectEmitNested( + bool checkTopic1, + bool checkTopic2, + bool checkTopic3, + bool checkData, + uint128 topic1, + uint128 topic2, + uint128 topic3, + uint128 data + ) public { + cheats.assume(checkTopic1 || checkTopic2 || checkTopic3 || checkData); + Emitter inner = new Emitter(); + + uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) + 1 : uint256(topic1); + uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) + 1 : uint256(topic2); + uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) + 1 : uint256(topic3); + uint256 transformedData = checkData ? uint256(data) + 1 : uint256(data); + + cheats.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + + emit Something(topic1, topic2, topic3, data); + emitter.emitNested(inner, transformedTopic1, transformedTopic2, transformedTopic3, transformedData); + } + + function testExpectEmitMultiple() public { + cheats.expectEmit(true, true, true, true); + emit Something(1, 2, 3, 4); + cheats.expectEmit(true, true, true, true); + emit Something(5, 6, 7, 8); + + emitter.emitMultiple( + [uint256(1), uint256(5)], + [uint256(2), uint256(6)], + [uint256(3), uint256(7)], + [uint256(4), uint256(8)] + ); + } +} diff --git a/testdata/cheats/ExpectRevert.t.sol b/testdata/cheats/ExpectRevert.t.sol new file mode 100644 index 000000000000..f73fe79b436b --- /dev/null +++ b/testdata/cheats/ExpectRevert.t.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract Reverter { + error CustomError(); + + function revertWithMessage(string memory message) public pure { + require(false, message); + } + + function doNotRevert() public pure {} + + function panic() public pure returns (uint256) { + return uint256(100) - uint256(101); + } + + function revertWithCustomError() public pure { + revert CustomError(); + } + + function nestedRevert(Reverter inner, string memory message) public pure { + inner.revertWithMessage(message); + } + + function callThenRevert(Dummy dummy, string memory message) public pure { + dummy.callMe(); + require(false, message); + } + + function revertWithoutReason() public pure { + revert(); + } +} + +contract ConstructorReverter { + constructor(string memory message) { + require(false, message); + } +} + +contract Dummy { + function callMe() public pure returns (string memory) { + return "thanks for calling"; + } +} + +contract ExpectRevertTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testExpectRevertString() public { + Reverter reverter = new Reverter(); + cheats.expectRevert("revert"); + reverter.revertWithMessage("revert"); + } + + function testExpectRevertConstructor() public { + cheats.expectRevert("constructor revert"); + new ConstructorReverter("constructor revert"); + } + + function testExpectRevertBuiltin() public { + Reverter reverter = new Reverter(); + cheats.expectRevert(abi.encodeWithSignature("Panic(uint256)", 0x11)); + reverter.panic(); + } + + function testExpectRevertCustomError() public { + Reverter reverter = new Reverter(); + cheats.expectRevert(abi.encodePacked(Reverter.CustomError.selector)); + reverter.revertWithCustomError(); + } + + function testExpectRevertNested() public { + Reverter reverter = new Reverter(); + Reverter inner = new Reverter(); + cheats.expectRevert("nested revert"); + reverter.nestedRevert(inner, "nested revert"); + } + + function testExpectRevertCallsThenReverts() public { + Reverter reverter = new Reverter(); + Dummy dummy = new Dummy(); + cheats.expectRevert("called a function and then reverted"); + reverter.callThenRevert(dummy, "called a function and then reverted"); + } + + function testFailExpectRevertErrorDoesNotMatch() public { + Reverter reverter = new Reverter(); + cheats.expectRevert("should revert with this message"); + reverter.revertWithMessage("but reverts with this message"); + } + + function testFailExpectRevertDidNotRevert() public { + Reverter reverter = new Reverter(); + cheats.expectRevert("does not revert, but we think it should"); + reverter.doNotRevert(); + } + + function testExpectRevertNoReason() public { + Reverter reverter = new Reverter(); + cheats.expectRevert(bytes("")); + reverter.revertWithoutReason(); + cheats.expectRevert(); + reverter.revertWithoutReason(); + } + + function testFailExpectRevertDangling() public { + cheats.expectRevert("dangling"); + } +} diff --git a/testdata/cheats/Fee.t.sol b/testdata/cheats/Fee.t.sol new file mode 100644 index 000000000000..e0365603db45 --- /dev/null +++ b/testdata/cheats/Fee.t.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract FeeTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testFee() public { + cheats.fee(10); + assertEq(block.basefee, 10, "fee failed"); + } + + function testFeeFuzzed(uint256 fee) public { + cheats.fee(fee); + assertEq(block.basefee, fee, "fee failed"); + } +} diff --git a/testdata/cheats/Ffi.t.sol b/testdata/cheats/Ffi.t.sol new file mode 100644 index 000000000000..a87d10591960 --- /dev/null +++ b/testdata/cheats/Ffi.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract FfiTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testFfi() public { + string[] memory inputs = new string[](3); + inputs[0] = "echo"; + inputs[1] = "-n"; + inputs[2] = "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000966666920776f726b730000000000000000000000000000000000000000000000"; + + bytes memory res = cheats.ffi(inputs); + (string memory output) = abi.decode(res, (string)); + assertEq(output, "ffi works", "ffi failed"); + } +} diff --git a/testdata/cheats/GetCode.t.sol b/testdata/cheats/GetCode.t.sol new file mode 100644 index 000000000000..c7bf7ea33859 --- /dev/null +++ b/testdata/cheats/GetCode.t.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract GetCodeTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testGetCode() public { + bytes memory fullPath = cheats.getCode("../testdata/fixtures/GetCode/WorkingContract.json"); + //bytes memory fileOnly = cheats.getCode("WorkingContract.sol"); + //bytes memory fileAndContractName = cheats.getCode("WorkingContract.sol:WorkingContract"); + + string memory expected = string(bytes(hex"6080604052348015600f57600080fd5b50607c8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b6034602a81565b60405190815260200160405180910390f3fea26469706673582212206740fcc626175d58a151da7fbfca1775ea4d3ababf7f3168347dab89488f6a4264736f6c634300080a0033")); + assertEq( + string(fullPath), + expected, + "code for full path was incorrect" + ); + // TODO: Disabled until we figure out a way to get these variants of the + // cheatcode working during automated tests + //assertEq( + // string(fileOnly), + // expected, + // "code for file name only was incorrect" + //); + //assertEq( + // string(fileAndContractName), + // expected, + // "code for full path was incorrect" + //); + } + + function testFailGetUnlinked() public { + cheats.getCode("UnlinkedContract.sol"); + } +} diff --git a/testdata/cheats/Label.t.sol b/testdata/cheats/Label.t.sol new file mode 100644 index 000000000000..d0a8786c0521 --- /dev/null +++ b/testdata/cheats/Label.t.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract LabelTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testLabel() public { + cheats.label(address(1), "Sir Address the 1st"); + } +} diff --git a/testdata/cheats/Load.t.sol b/testdata/cheats/Load.t.sol new file mode 100644 index 000000000000..8fede8dd50f6 --- /dev/null +++ b/testdata/cheats/Load.t.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract Storage { + uint256 slot0 = 10; +} + +contract LoadTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + uint256 slot0 = 20; + Storage store; + + function setUp() public { + store = new Storage(); + } + + function testLoadOwnStorage() public { + uint slot; + assembly { + slot := slot0.slot + } + uint val = uint(cheats.load(address(this), bytes32(slot))); + assertEq(val, 20, "load failed"); + } + + function testLoadOtherStorage() public { + uint val = uint(cheats.load(address(store), bytes32(0))); + assertEq(val, 10, "load failed"); + } +} diff --git a/testdata/cheats/MockCall.t.sol b/testdata/cheats/MockCall.t.sol new file mode 100644 index 000000000000..11e659e058e4 --- /dev/null +++ b/testdata/cheats/MockCall.t.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract Mock { + function numberA() public pure returns (uint256) { + return 1; + } + + function numberB() public pure returns (uint256) { + return 2; + } + + function add(uint256 a, uint256 b) public pure returns (uint256) { + return a + b; + } +} + +contract NestedMock { + Mock private inner; + + constructor(Mock _inner) { + inner = _inner; + } + + function sum() public view returns (uint256) { + return inner.numberA() + inner.numberB(); + } +} + +contract MockCallTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testMockGetters() public { + Mock target = new Mock(); + + // pre-mock + assertEq(target.numberA(), 1); + assertEq(target.numberB(), 2); + + cheats.mockCall( + address(target), + abi.encodeWithSelector(target.numberB.selector), + abi.encode(10) + ); + + // post-mock + assertEq(target.numberA(), 1); + assertEq(target.numberB(), 10); + } + + function testMockNested() public { + Mock inner = new Mock(); + NestedMock target = new NestedMock(inner); + + // pre-mock + assertEq(target.sum(), 3); + + cheats.mockCall( + address(inner), + abi.encodeWithSelector(inner.numberB.selector), + abi.encode(9) + ); + + // post-mock + assertEq(target.sum(), 10); + } + + function testMockSelector() public { + Mock target = new Mock(); + assertEq(target.add(5, 5), 10); + + cheats.mockCall( + address(target), + abi.encodeWithSelector(target.add.selector), + abi.encode(11) + ); + + assertEq(target.add(5, 5), 11); + } + + function testMockCalldata() public { + Mock target = new Mock(); + assertEq(target.add(5, 5), 10); + assertEq(target.add(6, 4), 10); + + cheats.mockCall( + address(target), + abi.encodeWithSelector(target.add.selector, 5, 5), + abi.encode(11) + ); + + assertEq(target.add(5, 5), 11); + assertEq(target.add(6, 4), 10); + } + + function testClearMockedCalls() public { + Mock target = new Mock(); + + cheats.mockCall( + address(target), + abi.encodeWithSelector(target.numberB.selector), + abi.encode(10) + ); + + assertEq(target.numberA(), 1); + assertEq(target.numberB(), 10); + + cheats.clearMockedCalls(); + + assertEq(target.numberA(), 1); + assertEq(target.numberB(), 2); + } +} diff --git a/testdata/cheats/Prank.t.sol b/testdata/cheats/Prank.t.sol new file mode 100644 index 000000000000..567ef8fff6c7 --- /dev/null +++ b/testdata/cheats/Prank.t.sol @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract Victim { + function assertCallerAndOrigin( + address expectedSender, + string memory senderMessage, + address expectedOrigin, + string memory originMessage + ) public view { + require(msg.sender == expectedSender, senderMessage); + require(tx.origin == expectedOrigin, originMessage); + } +} + +contract ConstructorVictim is Victim { + constructor( + address expectedSender, + string memory senderMessage, + address expectedOrigin, + string memory originMessage + ) { + require(msg.sender == expectedSender, senderMessage); + require(tx.origin == expectedOrigin, originMessage); + } +} + +contract NestedVictim { + Victim innerVictim; + + constructor(Victim victim) { + innerVictim = victim; + } + + function assertCallerAndOrigin( + address expectedSender, + string memory senderMessage, + address expectedOrigin, + string memory originMessage + ) public view { + require(msg.sender == expectedSender, senderMessage); + require(tx.origin == expectedOrigin, originMessage); + innerVictim.assertCallerAndOrigin( + address(this), + "msg.sender was incorrectly set for nested victim", + expectedOrigin, + "tx.origin was incorrectly set for nested victim" + ); + } +} + +contract NestedPranker { + Cheats constant cheats = Cheats( + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))) + ); + + address newSender; + address newOrigin; + address oldOrigin; + + constructor( + address _newSender, + address _newOrigin + ) { + newSender = _newSender; + newOrigin = _newOrigin; + oldOrigin = tx.origin; + } + + function incompletePrank() public { + cheats.startPrank(newSender, newOrigin); + } + + function completePrank(NestedVictim victim) public { + victim.assertCallerAndOrigin( + newSender, + "msg.sender was not set in nested prank", + newOrigin, + "tx.origin was not set in nested prank" + ); + cheats.stopPrank(); + + // Ensure we cleaned up correctly + victim.assertCallerAndOrigin( + address(this), + "msg.sender was not cleaned up in nested prank", + oldOrigin, + "tx.origin was not cleaned up in nested prank" + ); + } +} + +contract PrankTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testPrankSender(address sender) public { + // Perform the prank + Victim victim = new Victim(); + cheats.prank(sender); + victim.assertCallerAndOrigin( + sender, + "msg.sender was not set during prank", + tx.origin, + "tx.origin invariant failed" + ); + + // Ensure we cleaned up correctly + victim.assertCallerAndOrigin( + address(this), + "msg.sender was not cleaned up", + tx.origin, + "tx.origin invariant failed" + ); + } + + function testPrankOrigin(address sender, address origin) public { + address oldOrigin = tx.origin; + + // Perform the prank + Victim victim = new Victim(); + cheats.prank(sender, origin); + victim.assertCallerAndOrigin( + sender, + "msg.sender was not set during prank", + origin, + "tx.origin was not set during prank" + ); + + // Ensure we cleaned up correctly + victim.assertCallerAndOrigin( + address(this), + "msg.sender was not cleaned up", + oldOrigin, + "tx.origin was not cleaned up" + ); + } + + function testPrankConstructorSender(address sender) public { + cheats.prank(sender); + ConstructorVictim victim = new ConstructorVictim( + sender, + "msg.sender was not set during prank", + tx.origin, + "tx.origin invariant failed" + ); + + // Ensure we cleaned up correctly + victim.assertCallerAndOrigin( + address(this), + "msg.sender was not cleaned up", + tx.origin, + "tx.origin invariant failed" + ); + } + + function testPrankConstructorOrigin(address sender, address origin) public { + // Perform the prank + cheats.prank(sender, origin); + ConstructorVictim victim = new ConstructorVictim( + sender, + "msg.sender was not set during prank", + origin, + "tx.origin was not set during prank" + ); + + // Ensure we cleaned up correctly + victim.assertCallerAndOrigin( + address(this), + "msg.sender was not cleaned up", + tx.origin, + "tx.origin was not cleaned up" + ); + } + + function testPrankStartStop(address sender, address origin) public { + address oldOrigin = tx.origin; + + // Perform the prank + Victim victim = new Victim(); + cheats.startPrank(sender, origin); + victim.assertCallerAndOrigin( + sender, + "msg.sender was not set during prank", + origin, + "tx.origin was not set during prank" + ); + victim.assertCallerAndOrigin( + sender, + "msg.sender was not set during prank (call 2)", + origin, + "tx.origin was not set during prank (call 2)" + ); + cheats.stopPrank(); + + // Ensure we cleaned up correctly + victim.assertCallerAndOrigin( + address(this), + "msg.sender was not cleaned up", + oldOrigin, + "tx.origin was not cleaned up" + ); + } + + function testPrankStartStopConstructor(address sender, address origin) public { + // Perform the prank + cheats.startPrank(sender, origin); + ConstructorVictim victim = new ConstructorVictim( + sender, + "msg.sender was not set during prank", + origin, + "tx.origin was not set during prank" + ); + new ConstructorVictim( + sender, + "msg.sender was not set during prank (call 2)", + origin, + "tx.origin was not set during prank (call 2)" + ); + cheats.stopPrank(); + + // Ensure we cleaned up correctly + victim.assertCallerAndOrigin( + address(this), + "msg.sender was not cleaned up", + tx.origin, + "tx.origin was not cleaned up" + ); + } + + /// This test checks that depth is working correctly with respect + /// to the `startPrank` and `stopPrank` cheatcodes. + /// + /// The nested pranker calls `startPrank` but does not call + /// `stopPrank` at first. + /// + /// Then, we call our victim from the main test: this call + /// should NOT have altered `msg.sender` or `tx.origin`. + /// + /// Then, the nested pranker will complete their prank: this call + /// SHOULD have altered `msg.sender` and `tx.origin`. + /// + /// Each call to the victim calls yet another victim. The expected + /// behavior for this call is that `tx.origin` is altered when + /// the nested pranker calls, otherwise not. In both cases, + /// `msg.sender` should be the address of the first victim. + /// + /// Success case: + /// + /// ┌────┐ ┌───────┐ ┌──────┐ ┌──────┐ ┌────────────┐ + /// │Test│ │Pranker│ │Cheats│ │Victim│ │Inner Victim│ + /// └─┬──┘ └───┬───┘ └──┬───┘ └──┬───┘ └─────┬──────┘ + /// │ │ │ │ │ + /// │incompletePrank()│ │ │ │ + /// │────────────────>│ │ │ │ + /// │ │ │ │ │ + /// │ │startPrank()│ │ │ + /// │ │───────────>│ │ │ + /// │ │ │ │ │ + /// │ should not be pranked│ │ │ + /// │──────────────────────────────────────>│ │ + /// │ │ │ │ │ + /// │ │ │ │ should not be pranked │ + /// │ │ │ │────────────────────────>│ + /// │ │ │ │ │ + /// │ completePrank() │ │ │ │ + /// │────────────────>│ │ │ │ + /// │ │ │ │ │ + /// │ │ should be pranked │ │ + /// │ │────────────────────>│ │ + /// │ │ │ │ │ + /// │ │ │ │only tx.origin is pranked│ + /// │ │ │ │────────────────────────>│ + /// │ │ │ │ │ + /// │ │stopPrank() │ │ │ + /// │ │───────────>│ │ │ + /// │ │ │ │ │ + /// │ │should not be pranked│ │ + /// │ │────────────────────>│ │ + /// │ │ │ │ │ + /// │ │ │ │ should not be pranked │ + /// │ │ │ │────────────────────────>│ + /// ┌─┴──┐ ┌───┴───┐ ┌──┴───┐ ┌──┴───┐ ┌─────┴──────┐ + /// │Test│ │Pranker│ │Cheats│ │Victim│ │Inner Victim│ + /// └────┘ └───────┘ └──────┘ └──────┘ └────────────┘ + /// If this behavior is incorrectly implemented then the victim + /// will be pranked the first time it is called. + function testPrankComplex(address sender, address origin) public { + address oldOrigin = tx.origin; + + NestedPranker pranker = new NestedPranker(sender, origin); + Victim innerVictim = new Victim(); + NestedVictim victim = new NestedVictim(innerVictim); + + pranker.incompletePrank(); + victim.assertCallerAndOrigin( + address(this), + "msg.sender was altered at an incorrect depth", + oldOrigin, + "tx.origin was altered at an incorrect depth" + ); + + pranker.completePrank(victim); + } +} diff --git a/testdata/cheats/Record.t.sol b/testdata/cheats/Record.t.sol new file mode 100644 index 000000000000..ea201a20593a --- /dev/null +++ b/testdata/cheats/Record.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract RecordAccess { + function record() public returns (NestedRecordAccess) { + assembly { + sstore(1, add(sload(1), 1)) + } + + NestedRecordAccess inner = new NestedRecordAccess(); + inner.record(); + + return inner; + } +} + +contract NestedRecordAccess { + function record() public { + assembly { + sstore(2, add(sload(2), 1)) + } + } +} + +contract RecordTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testRecordAccess() public { + RecordAccess target = new RecordAccess(); + + // Start recording + cheats.record(); + NestedRecordAccess inner = target.record(); + + // Verify Records + (bytes32[] memory reads, bytes32[] memory writes) = cheats.accesses(address(target)); + (bytes32[] memory innerReads, bytes32[] memory innerWrites) = cheats.accesses(address(inner)); + + assertEq(reads.length, 2, "number of reads is incorrect"); + assertEq(reads[0], bytes32(uint256(1)), "key for read 0 is incorrect"); + assertEq(reads[1], bytes32(uint256(1)), "key for read 1 is incorrect"); + + assertEq(writes.length, 1, "number of writes is incorrect"); + assertEq(writes[0], bytes32(uint256(1)), "key for write is incorrect"); + + assertEq(innerReads.length, 2, "number of nested reads is incorrect"); + assertEq(innerReads[0], bytes32(uint256(2)), "key for nested read 0 is incorrect"); + assertEq(innerReads[1], bytes32(uint256(2)), "key for nested read 1 is incorrect"); + + assertEq(innerWrites.length, 1, "number of nested writes is incorrect"); + assertEq(innerWrites[0], bytes32(uint256(2)), "key for nested write is incorrect"); + } +} diff --git a/testdata/cheats/Roll.t.sol b/testdata/cheats/Roll.t.sol new file mode 100644 index 000000000000..1cb210ee550a --- /dev/null +++ b/testdata/cheats/Roll.t.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract RollTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testRoll() public { + cheats.roll(10); + assertEq(block.number, 10, "roll failed"); + } + + function testRollFuzzed(uint128 jump) public { + uint pre = block.number; + cheats.roll(block.number + jump); + assertEq(block.number, pre + jump, "roll failed"); + } + + function testRollHash() public { + assertEq(blockhash(block.number), keccak256(abi.encodePacked(block.number)), "initial block hash is incorrect"); + + cheats.roll(5); + bytes32 hash = blockhash(5); + assertTrue(blockhash(5) != 0x0, "new block hash is incorrect"); + + cheats.roll(10); + assertTrue(blockhash(5) != blockhash(10), "block hash collision"); + + cheats.roll(5); + assertEq(blockhash(5), hash, "block 5 changed hash"); + } +} diff --git a/testdata/cheats/Setup.t.sol b/testdata/cheats/Setup.t.sol new file mode 100644 index 000000000000..c30581a41f0d --- /dev/null +++ b/testdata/cheats/Setup.t.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract CheatsSetupTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function setUp() public { + cheats.warp(10); + cheats.roll(100); + cheats.fee(1000); + } + + function testCheatEnvironment() public { + assertEq(block.timestamp, 10, "block timestamp was not persisted from setup"); + assertEq(block.number, 100, "block number was not persisted from setup"); + assertEq(block.basefee, 1000, "basefee was not persisted from setup"); + } +} diff --git a/testdata/cheats/Sign.t.sol b/testdata/cheats/Sign.t.sol new file mode 100644 index 000000000000..4dc195409ad8 --- /dev/null +++ b/testdata/cheats/Sign.t.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract SignTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testSignDigest(uint248 pk, bytes32 digest) public { + cheats.assume(pk != 0); + + (uint8 v, bytes32 r, bytes32 s) = cheats.sign(pk, digest); + address expected = cheats.addr(pk); + address actual = ecrecover(digest, v, r, s); + + assertEq(actual, expected, "digest signer did not match"); + } + + function testSignMessage(uint248 pk, bytes memory message) public { + testSignDigest(pk, keccak256(message)); + } +} diff --git a/testdata/cheats/Store.t.sol b/testdata/cheats/Store.t.sol new file mode 100644 index 000000000000..64d6e7d400f2 --- /dev/null +++ b/testdata/cheats/Store.t.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract Storage { + uint public slot0 = 10; + uint public slot1 = 20; +} + +contract StoreTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + Storage store; + + function setUp() public { + store = new Storage(); + } + + function testStore() public { + assertEq(store.slot0(), 10, "initial value for slot 0 is incorrect"); + assertEq(store.slot1(), 20, "initial value for slot 1 is incorrect"); + + cheats.store(address(store), bytes32(0), bytes32(uint(1))); + assertEq(store.slot0(), 1, "store failed"); + assertEq(store.slot1(), 20, "store failed"); + } + + function testStoreFuzzed(uint256 slot0, uint256 slot1) public { + assertEq(store.slot0(), 10, "initial value for slot 0 is incorrect"); + assertEq(store.slot1(), 20, "initial value for slot 1 is incorrect"); + + cheats.store(address(store), bytes32(0), bytes32(slot0)); + cheats.store(address(store), bytes32(uint(1)), bytes32(slot1)); + assertEq(store.slot0(), slot0, "store failed"); + assertEq(store.slot1(), slot1, "store failed"); + } +} diff --git a/testdata/cheats/Warp.t.sol b/testdata/cheats/Warp.t.sol new file mode 100644 index 000000000000..c4465b961ced --- /dev/null +++ b/testdata/cheats/Warp.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "./Cheats.sol"; + +contract WarpTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testWarp() public { + cheats.warp(10); + assertEq(block.timestamp, 10, "warp failed"); + } + + function testWarpFuzzed(uint128 jump) public { + uint pre = block.timestamp; + cheats.warp(block.timestamp + jump); + assertEq(block.timestamp, pre + jump, "warp failed"); + } +} diff --git a/testdata/core/Abstract.t.sol b/testdata/core/Abstract.t.sol new file mode 100644 index 000000000000..0ac0411e30f7 --- /dev/null +++ b/testdata/core/Abstract.t.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +contract TestFixture { + function something() public pure returns (string memory) { + return "something"; + } +} + +abstract contract AbstractTestBase { + TestFixture fixture; + + function testSomething() public { + fixture.something(); + } +} + +contract AbstractTest is AbstractTestBase { + function setUp() public { + fixture = new TestFixture(); + } +} diff --git a/testdata/core/DSStyle.t.sol b/testdata/core/DSStyle.t.sol new file mode 100644 index 000000000000..93d8b1f0ddbe --- /dev/null +++ b/testdata/core/DSStyle.t.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; + +contract DSStyleTest is DSTest { + function testFailingAssertions() public { + emit log_string("assertionOne"); + assertEq(uint(1), uint(2)); + emit log_string("assertionTwo"); + assertEq(uint(3), uint(4)); + emit log_string("done"); + } +} diff --git a/testdata/core/DappToolsParity.t.sol b/testdata/core/DappToolsParity.t.sol new file mode 100644 index 000000000000..53dfa7281369 --- /dev/null +++ b/testdata/core/DappToolsParity.t.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; + +contract DSStyleTest is DSTest { + function chainId() internal view returns (uint256 id) { + assembly { + id := chainid() + } + } + + function testAddresses() public { + assertEq(msg.sender, 0x00a329c0648769A73afAc7F9381E08FB43dBEA72, "sender account is incorrect"); + assertEq(tx.origin, 0x00a329c0648769A73afAc7F9381E08FB43dBEA72, "origin account is incorrect"); + assertEq(address(this), 0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84, "test contract address is incorrect"); + } + + function testEnvironment() public { + assertEq(chainId(), 99, "chain id is incorrect"); + assertEq(block.number, 0); + assertEq( + blockhash(block.number), + keccak256(abi.encodePacked(block.number)), + "blockhash is incorrect" + ); + assertEq(block.coinbase, 0x0000000000000000000000000000000000000000, "coinbase is incorrect"); + assertEq(block.timestamp, 0, "timestamp is incorrect"); + assertEq(block.difficulty, 0, "difficulty is incorrect"); + } +} diff --git a/testdata/core/FailingSetup.t.sol b/testdata/core/FailingSetup.t.sol new file mode 100644 index 000000000000..80bc9bfb5ede --- /dev/null +++ b/testdata/core/FailingSetup.t.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; + +contract FailingSetupTest is DSTest { + event Test(uint256 n); + + function setUp() public { + emit Test(42); + require(false, "setup failed predictably"); + } + + function testFailShouldBeMarkedAsFailedBecauseOfSetup() public { + emit log("setup did not fail"); + } +} diff --git a/testdata/core/LibraryLinking.t.sol b/testdata/core/LibraryLinking.t.sol new file mode 100644 index 000000000000..ec1b423fd949 --- /dev/null +++ b/testdata/core/LibraryLinking.t.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; + +library Lib { + function plus100(uint256 a) public pure returns (uint256) { + return a + 100; + } +} + +library NestedLib { + function nestedPlus100Plus1(uint256 a) public pure returns (uint256) { + return Lib.plus100(a) + 1; + } +} + +contract LibraryConsumer { + function consume(uint256 a) public pure returns (uint256) { + return Lib.plus100(a); + } + + function consumeNested(uint256 a) public pure returns (uint256) { + return NestedLib.nestedPlus100Plus1(a); + } +} + +contract LibraryLinkingTest is DSTest { + LibraryConsumer consumer; + + function setUp() public { + consumer = new LibraryConsumer(); + } + + function testDirect() public { + assertEq(consumer.consume(1), 101, "library call failed"); + } + + function testNested() public { + assertEq(consumer.consumeNested(1), 102, "nested library call failed"); + } +} diff --git a/testdata/core/PaymentFailure.t.sol b/testdata/core/PaymentFailure.t.sol new file mode 100644 index 000000000000..6a13c13ee7ac --- /dev/null +++ b/testdata/core/PaymentFailure.t.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "../cheats/Cheats.sol"; + +contract Payable { + function pay() payable public {} +} + +contract PaymentFailureTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + function testCantPay() public { + Payable target = new Payable(); + cheats.prank(address(1)); + target.pay{value: 1}(); + } +} diff --git a/testdata/core/Reverting.t.sol b/testdata/core/Reverting.t.sol new file mode 100644 index 000000000000..5d826ba643fc --- /dev/null +++ b/testdata/core/Reverting.t.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +contract RevertingTest { + function testFailRevert() public pure { + require(false, "should revert here"); + } +} diff --git a/testdata/core/SetupConsistency.t.sol b/testdata/core/SetupConsistency.t.sol new file mode 100644 index 000000000000..1fda35377e95 --- /dev/null +++ b/testdata/core/SetupConsistency.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; + +contract SetupConsistencyCheck is DSTest { + uint256 two; + uint256 four; + uint256 result; + + function setUp() public { + two = 2; + four = 4; + result = 0; + } + + function testAdd() public { + assertEq(result, 0); + result = two + four; + assertEq(result, 6); + } + + function testMultiply() public { + assertEq(result, 0); + result = two * four; + assertEq(result, 8); + } +} diff --git a/testdata/fixtures/GetCode/UnlinkedContract.sol b/testdata/fixtures/GetCode/UnlinkedContract.sol new file mode 100644 index 000000000000..d6b673c34ca5 --- /dev/null +++ b/testdata/fixtures/GetCode/UnlinkedContract.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +library SmolLibrary { + function add(uint256 a, uint256 b) public pure returns (uint256 c) { + c = a + b; + } +} + +contract UnlinkedContract { + function complicated(uint256 a, uint256 b, uint256 c) public pure returns (uint256 d) { + d = SmolLibrary.add(SmolLibrary.add(a, b), c); + } +} diff --git a/testdata/fixtures/GetCode/WorkingContract.json b/testdata/fixtures/GetCode/WorkingContract.json new file mode 100644 index 000000000000..1127effbe713 --- /dev/null +++ b/testdata/fixtures/GetCode/WorkingContract.json @@ -0,0 +1,27 @@ +{ + "abi": [ + { + "inputs": [], + "name": "secret", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": { + "object": "0x6080604052348015600f57600080fd5b50607c8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b6034602a81565b60405190815260200160405180910390f3fea26469706673582212206740fcc626175d58a151da7fbfca1775ea4d3ababf7f3168347dab89488f6a4264736f6c634300080a0033", + "sourceMap": "64:69:28:-:0;;;;;;;;;;;;;;;;;;;", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b6034602a81565b60405190815260200160405180910390f3fea26469706673582212206740fcc626175d58a151da7fbfca1775ea4d3ababf7f3168347dab89488f6a4264736f6c634300080a0033", + "sourceMap": "64:69:28:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95:35;;128:2;95:35;;;;;160:25:35;;;148:2;133:18;95:35:28;;;;;;", + "linkReferences": {} + } +} diff --git a/testdata/fixtures/GetCode/WorkingContract.sol b/testdata/fixtures/GetCode/WorkingContract.sol new file mode 100644 index 000000000000..1f3147e39452 --- /dev/null +++ b/testdata/fixtures/GetCode/WorkingContract.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +contract WorkingContract { + uint256 constant public secret = 42; +} diff --git a/utils/testdata/interfaceTest.sol b/testdata/fixtures/SolidityGeneration/GeneratedNamedInterface.sol similarity index 100% rename from utils/testdata/interfaceTest.sol rename to testdata/fixtures/SolidityGeneration/GeneratedNamedInterface.sol diff --git a/utils/testdata/interfaceTestNoName.sol b/testdata/fixtures/SolidityGeneration/GeneratedUnnamedInterface.sol similarity index 100% rename from utils/testdata/interfaceTestNoName.sol rename to testdata/fixtures/SolidityGeneration/GeneratedUnnamedInterface.sol diff --git a/utils/testdata/interfaceTestABI.json b/testdata/fixtures/SolidityGeneration/InterfaceABI.json similarity index 100% rename from utils/testdata/interfaceTestABI.json rename to testdata/fixtures/SolidityGeneration/InterfaceABI.json diff --git a/testdata/fuzz/Fuzz.t.sol b/testdata/fuzz/Fuzz.t.sol new file mode 100644 index 000000000000..31c2df9c0a75 --- /dev/null +++ b/testdata/fuzz/Fuzz.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; + +contract FuzzTest is DSTest { + constructor() { + emit log("constructor"); + } + + function setUp() public { + emit log("setUp"); + } + + function testFailFuzz(uint8 x) public { + emit log("testFailFuzz"); + require(x == 5, "should revert"); + } + + function testSuccessfulFuzz(uint128 a, uint128 b) public { + emit log("testSuccessfulFuzz"); + assertEq(uint256(a) + uint256(b), uint256(a) + uint256(b)); + } +} diff --git a/evm-adapters/testdata/TestNumbers.sol b/testdata/fuzz/FuzzNumbers.t.sol similarity index 81% rename from evm-adapters/testdata/TestNumbers.sol rename to testdata/fuzz/FuzzNumbers.t.sol index 6be8929dab73..ec5d15922e6e 100644 --- a/evm-adapters/testdata/TestNumbers.sol +++ b/testdata/fuzz/FuzzNumbers.t.sol @@ -1,8 +1,10 @@ -pragma solidity ^0.8.0; +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; -import "./DsTest.sol"; +import "ds-test/test.sol"; -contract TestNumbers is DSTest { +// See https://github.com/gakonst/foundry/pull/735 for context +contract FuzzNumbersTest is DSTest { function testPositive(uint256) public { assertTrue(true); } diff --git a/evm-adapters/testdata/DsTest.sol b/testdata/lib/ds-test/src/test.sol similarity index 99% rename from evm-adapters/testdata/DsTest.sol rename to testdata/lib/ds-test/src/test.sol index 192c903b7fc6..96d3c1543453 100644 --- a/evm-adapters/testdata/DsTest.sol +++ b/testdata/lib/ds-test/src/test.sol @@ -1,4 +1,3 @@ -// Taken from: https://github.com/dapphub/ds-test/blob/0a5da56b0d65960e6a994d2ec8245e6edd38c248/src/test.sol // SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify diff --git a/forge/testdata/DebugLogsTest.sol b/testdata/logs/DebugLogs.t.sol similarity index 59% rename from forge/testdata/DebugLogsTest.sol rename to testdata/logs/DebugLogs.t.sol index 665934dba3f6..923141033642 100644 --- a/forge/testdata/DebugLogsTest.sol +++ b/testdata/logs/DebugLogs.t.sol @@ -1,39 +1,39 @@ -pragma solidity 0.8.0; +pragma solidity >=0.8.0; -import "../../evm-adapters/testdata/DsTest.sol"; +import "ds-test/test.sol"; contract DebugLogsTest is DSTest { - constructor() public { - emit log("constructor"); + constructor() { + emit log_uint(0); } function setUp() public { - emit log("setUp"); + emit log_uint(1); } function test1() public { - emit log("one"); + emit log_uint(2); } function test2() public { - emit log("two"); + emit log_uint(3); } function testFailWithRevert() public { Fails fails = new Fails(); - emit log("three"); + emit log_uint(4); fails.failure(); } function testFailWithRequire() public { - emit log("four"); + emit log_uint(5); require(false); } } contract Fails is DSTest { function failure() public { - emit log("failure"); + emit log_uint(100); revert(); } -} \ No newline at end of file +} diff --git a/testdata/logs/HardhatLogs.t.sol b/testdata/logs/HardhatLogs.t.sol new file mode 100644 index 000000000000..771b76a69c84 --- /dev/null +++ b/testdata/logs/HardhatLogs.t.sol @@ -0,0 +1,1553 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.0; + +contract HardhatLogsTest { + constructor() { + console.log("constructor"); + } + + function testInts() public view { + console.log(0); + console.log(1); + console.log(2); + console.log(3); + } + + function testStrings() public view { + console.log("testStrings"); + } + + function testMisc() public view { + console.log("testMisc", address(1)); + console.log("testMisc", 42); + } +} + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } +} diff --git a/testdata/trace/ConflictingSignatures.t.sol b/testdata/trace/ConflictingSignatures.t.sol new file mode 100644 index 000000000000..10faa73f085f --- /dev/null +++ b/testdata/trace/ConflictingSignatures.t.sol @@ -0,0 +1,41 @@ +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "../cheats/Cheats.sol"; + +contract ReturnsNothing { + function func() public pure {} +} + +contract ReturnsString { + function func() public pure returns (string memory) { + return "string"; + } +} + +contract ReturnsUint { + function func() public pure returns (uint256) { + return 1; + } +} + +contract ConflictingSignaturesTest is DSTest { + ReturnsNothing retsNothing; + ReturnsString retsString; + ReturnsUint retsUint; + + function setUp() public { + retsNothing = new ReturnsNothing(); + retsString = new ReturnsString(); + retsUint = new ReturnsUint(); + } + + /// Tests that traces are decoded properly when multiple + /// functions have the same 4byte signature, but different + /// return values. + function testTraceWithConflictingSignatures() public { + retsNothing.func(); + retsString.func(); + retsUint.func(); + } +} diff --git a/testdata/trace/Trace.t.sol b/testdata/trace/Trace.t.sol new file mode 100644 index 000000000000..9737297207fe --- /dev/null +++ b/testdata/trace/Trace.t.sol @@ -0,0 +1,101 @@ +pragma solidity >=0.8.0; + +import "ds-test/test.sol"; +import "../cheats/Cheats.sol"; + +contract RecursiveCall { + TraceTest factory; + + event Depth(uint256 depth); + event ChildDepth(uint256 childDepth); + event CreatedChild(uint256 childDepth); + + constructor(address _factory) { + factory = TraceTest(_factory); + } + + function recurseCall(uint256 neededDepth, uint256 depth) public returns (uint256) { + if (depth == neededDepth) { + this.negativeNum(); + return neededDepth; + } + + uint256 childDepth = this.recurseCall(neededDepth, depth + 1); + emit ChildDepth(childDepth); + + this.someCall(); + emit Depth(depth); + + return depth; + } + + function recurseCreate(uint256 neededDepth, uint256 depth) public returns (uint256) { + if (depth == neededDepth) { + return neededDepth; + } + + RecursiveCall child = factory.create(); + emit CreatedChild(depth + 1); + + uint256 childDepth = child.recurseCreate(neededDepth, depth + 1); + emit ChildDepth(childDepth); + emit Depth(depth); + + return depth; + } + + function someCall() public pure {} + + function negativeNum() public pure returns (int256) { + return -1000000000; + } +} + +contract TraceTest is DSTest { + Cheats constant cheats = Cheats(HEVM_ADDRESS); + + uint256 nodeId = 0; + RecursiveCall first; + + function setUp() public { + first = this.create(); + } + + function create() public returns (RecursiveCall) { + RecursiveCall node = new RecursiveCall(address(this)); + cheats.label( + address(node), + string(abi.encodePacked("Node ", uintToString(nodeId++))) + ); + + return node; + } + + function testRecurseCall() public { + first.recurseCall(8, 0); + } + + function testRecurseCreate() public { + first.recurseCreate(8, 0); + } +} + +function uintToString(uint256 value) pure returns (string memory) { + // Taken from OpenZeppelin + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); +} diff --git a/ui/Cargo.toml b/ui/Cargo.toml index af7268b7a3e1..54c2f7feafea 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -1,15 +1,12 @@ [package] name = "ui" -version = "0.1.0" +version = "0.2.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -# TUI for debug crossterm = "0.22.1" -tui = { version = "0.16.0", default-features = false, features = ["crossterm"] } -evm-adapters = {path = "../evm-adapters", features = ["sputnik"] } +tui = { version = "0.16.0", default-features = false, features = ["crossterm"] } eyre = "0.6.5" hex = "0.4.3" -ethers = { git = "https://github.com/gakonst/ethers-rs" } \ No newline at end of file +ethers = { git = "https://github.com/gakonst/ethers-rs" } +forge = { path = "../forge" } diff --git a/ui/src/lib.rs b/ui/src/lib.rs index ddd6a3c08151..3ced736c64c3 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -1,11 +1,3 @@ -use ethers::abi::Abi; -use std::{ - cmp::{max, min}, - collections::{BTreeMap, VecDeque}, - time::{Duration, Instant}, -}; -use tui::text::Text; - use crossterm::{ event::{ self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEvent, MouseEvent, @@ -14,36 +6,36 @@ use crossterm::{ execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; -use ethers::solc::artifacts::ContractBytecodeSome; +use ethers::{solc::artifacts::ContractBytecodeSome, types::Address}; +use eyre::Result; +use forge::debug::DebugStep; use std::{ - io::{self}, + cmp::{max, min}, + collections::{BTreeMap, VecDeque}, + io, sync::mpsc, thread, + time::{Duration, Instant}, }; - -use evm_adapters::sputnik::cheatcodes::debugger::DebugStep; -use eyre::Result; use tui::{ backend::{Backend, CrosstermBackend}, layout::{Alignment, Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, terminal::Frame, - text::{Span, Spans}, + text::{Span, Spans, Text}, widgets::{Block, Borders, Paragraph, Wrap}, Terminal, }; -use ethers::types::Address; - -/// Trait for starting the ui +/// Trait for starting the UI pub trait Ui { - /// Start the agent that will now take over. + /// Start the agent that will now take over fn start(self) -> Result; } -/// Used to indicate why the Ui stopped +/// Used to indicate why the UI stopped pub enum TUIExitReason { - /// 'q' exit + /// Exit using CharExit, } @@ -54,7 +46,7 @@ pub struct Tui { key_buffer: String, /// current step in the debug steps current_step: usize, - identified_contracts: BTreeMap, + identified_contracts: BTreeMap, known_contracts: BTreeMap, source_code: BTreeMap, } @@ -65,7 +57,7 @@ impl Tui { pub fn new( debug_arena: Vec<(Address, Vec, bool)>, current_step: usize, - identified_contracts: BTreeMap, + identified_contracts: BTreeMap, known_contracts: BTreeMap, source_code: BTreeMap, ) -> Result { @@ -104,7 +96,7 @@ impl Tui { fn draw_layout( f: &mut Frame, address: Address, - identified_contracts: &BTreeMap, + identified_contracts: &BTreeMap, known_contracts: &BTreeMap, source_code: &BTreeMap, debug_steps: &[DebugStep], @@ -176,7 +168,7 @@ impl Tui { let block_controls = Block::default(); let text_output = Text::from(Span::styled( - "[q]: Quit | [k/j]: prev/next op | [a/s]: prev/next jump | [c/C]: prev/next call | [g/G]: start/end", + "[q]: quit | [k/j]: prev/next op | [a/s]: prev/next jump | [c/C]: prev/next call | [g/G]: start/end", Style::default().add_modifier(Modifier::DIM) )); let paragraph = Paragraph::new(text_output) @@ -190,7 +182,7 @@ impl Tui { fn draw_src( f: &mut Frame, address: Address, - identified_contracts: &BTreeMap, + identified_contracts: &BTreeMap, known_contracts: &BTreeMap, source_code: &BTreeMap, ic: usize, @@ -198,13 +190,13 @@ impl Tui { area: Rect, ) { let block_source_code = Block::default() - .title(format!("Contract construction: {}", creation)) + .title(if creation { "Contract creation" } else { "Contract call" }) .borders(Borders::ALL); let mut text_output: Text = Text::from(""); if let Some(contract_name) = identified_contracts.get(&address) { - if let Some(known) = known_contracts.get(&contract_name.0) { + if let Some(known) = known_contracts.get(contract_name) { // grab either the creation source map or runtime sourcemap if let Some(sourcemap) = if creation { known.bytecode.source_map() @@ -499,7 +491,7 @@ impl Tui { ) { let block_source_code = Block::default() .title(format!( - " Address: {}, pc: {}, call's gas used: {} ", + "Address: {} | PC: {} | Gas used in call: {}", address, if let Some(step) = debug_steps.get(current_step) { step.pc.to_string() @@ -555,17 +547,17 @@ impl Tui { // Format line number let line_number_format = if line_number == current_step { let step: &DebugStep = &debug_steps[line_number]; - format!("{:0>max_pc_len$x} ▶", step.pc, max_pc_len = max_pc_len) + format!("{:0>max_pc_len$x}|▶", step.pc, max_pc_len = max_pc_len) } else if line_number < debug_steps.len() { let step: &DebugStep = &debug_steps[line_number]; - format!("{:0>max_pc_len$x}: ", step.pc, max_pc_len = max_pc_len) + format!("{:0>max_pc_len$x}| ", step.pc, max_pc_len = max_pc_len) } else { "END CALL".to_string() }; if let Some(op) = opcode_list.get(line_number) { text_output.push(Spans::from(Span::styled( - format!("{} {}", line_number_format, op), + format!("{}{}", line_number_format, op), Style::default().fg(Color::White).bg(bg_color), ))); } else { @@ -592,28 +584,47 @@ impl Tui { current_step: usize, area: Rect, ) { - let stack_space = - Block::default().title(format!(" Stack: {} ", current_step)).borders(Borders::ALL); let stack = &debug_steps[current_step].stack; + let stack_space = + Block::default().title(format!("Stack: {}", stack.len())).borders(Borders::ALL); let min_len = usize::max(format!("{}", stack.len()).len(), 2); let text: Vec = stack .iter() + .rev() .enumerate() .map(|(i, stack_item)| { - Spans::from(Span::styled( - format!("{: = (0..32) + .into_iter() + .rev() + .map(|i| stack_item.byte(i)) + .map(|byte| { + Span::styled( + format!("{:02x} ", byte), + if byte == 0 { + Style::default().fg(Color::Gray).add_modifier(Modifier::DIM) + } else { + Style::default().fg(Color::White) + }, + ) + }) + .collect(); + + let mut spans = vec![Span::styled( + format!("{:0min_len$}| ", i, min_len = min_len), Style::default().fg(Color::White), - )) + )]; + spans.extend(words); + spans.push(Span::raw("\n")); + + Spans::from(spans) }) .collect(); + let paragraph = Paragraph::new(text).block(stack_space).wrap(Wrap { trim: true }); f.render_widget(paragraph, area); } - // cargo r --manifest-path ../foundry/Cargo.toml --bin forge run ./src/test/Locke.t.sol -t - // StreamTest --sig "test_fundStream()" --debug - /// Draw memory in memory pane fn draw_memory( f: &mut Frame, @@ -623,7 +634,7 @@ impl Tui { ) { let memory = &debug_steps[current_step].memory; let stack_space = Block::default() - .title(format!(" Memory - Max Expansion: {} bytes", memory.effective_len())) + .title(format!("Memory (max expansion: {} bytes)", memory.effective_len())) .borders(Borders::ALL); let memory = memory.data(); let max_i = memory.len() / 32; @@ -633,24 +644,28 @@ impl Tui { .chunks(32) .enumerate() .map(|(i, mem_word)| { - let strings: String = mem_word - .chunks(4) - .map(|bytes4| { - bytes4 - .iter() - .map(|byte| { - let v: Vec = vec![*byte]; - hex::encode(&v[..]) - }) - .collect::>() - .join(" ") + let words: Vec = mem_word + .iter() + .map(|byte| { + Span::styled( + format!("{:02x} ", byte), + if *byte == 0 { + Style::default().fg(Color::Gray).add_modifier(Modifier::DIM) + } else { + Style::default().fg(Color::White) + }, + ) }) - .collect::>() - .join(" "); - Spans::from(Span::styled( - format!("{:0min_len$x}: {} \n", i * 32, strings, min_len = min_len), + .collect(); + + let mut spans = vec![Span::styled( + format!("{:0min_len$x}| ", i * 32, min_len = min_len), Style::default().fg(Color::White), - )) + )]; + spans.extend(words); + spans.push(Span::raw("\n")); + + Spans::from(spans) }) .collect(); let paragraph = Paragraph::new(text).block(stack_space).wrap(Wrap { trim: true }); @@ -660,23 +675,23 @@ impl Tui { impl Ui for Tui { fn start(mut self) -> Result { - // if something panics inside here, we should do everything we can to + // If something panics inside here, we should do everything we can to // not corrupt the user's terminal. std::panic::set_hook(Box::new(|e| { disable_raw_mode().expect("Unable to disable raw mode"); - execute!(std::io::stdout(), LeaveAlternateScreen, DisableMouseCapture) + execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture) .expect("unable to execute disable mouse capture"); println!("{}", e); })); - // this is the recommend tick rate from tui-rs, based on their examples + // This is the recommend tick rate from tui-rs, based on their examples let tick_rate = Duration::from_millis(200); - // setup a channel to send interrupts + // Setup a channel to send interrupts let (tx, rx) = mpsc::channel(); thread::spawn(move || { let mut last_tick = Instant::now(); loop { - // poll events since last tick + // Poll events since last tick if event::poll(tick_rate - last_tick.elapsed()).unwrap() { let event = event::read().unwrap(); if let Event::Key(key) = event { @@ -689,7 +704,7 @@ impl Ui for Tui { } } } - // force update if time has passed + // Force update if time has passed if last_tick.elapsed() > tick_rate { if tx.send(Interrupt::IntervalElapsed).is_err() { return @@ -716,9 +731,9 @@ impl Ui for Tui { .collect(); last_index = draw_memory.inner_call_index; } - // grab interrupt + // Grab interrupt match rx.recv()? { - // key press + // Key press Interrupt::KeyPressed(event) => match event.code { // Exit KeyCode::Char('q') => { @@ -732,7 +747,7 @@ impl Ui for Tui { } // Move down KeyCode::Char('j') | KeyCode::Down => { - // grab number of times to do it + // Grab number of times to do it for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { if self.current_step < opcode_list.len() - 1 { self.current_step += 1; diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 3bd0c8ea14c4..562df0f9122d 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "foundry-utils" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" @@ -31,4 +31,4 @@ ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = fals [features] -test = ["tracing-subscriber"] \ No newline at end of file +test = ["tracing-subscriber"] diff --git a/utils/src/lib.rs b/utils/src/lib.rs index 9ed458a20ecf..25ca6716d1fe 100644 --- a/utils/src/lib.rs +++ b/utils/src/lib.rs @@ -149,8 +149,6 @@ pub fn recurse_link<'a>( } } -const BASE_TX_COST: u64 = 21000; - /// Helper trait for converting types to Functions. Helpful for allowing the `call` /// function on the EVM to be generic over `String`, `&str` and `Function`. pub trait IntoFunction { @@ -183,23 +181,6 @@ impl<'a> IntoFunction for &'a str { } } -/// Given a gas value and a calldata array, it subtracts the calldata cost from the -/// gas value, as well as the 21k base gas cost for all transactions. -pub fn remove_extra_costs(gas: U256, calldata: &[u8]) -> U256 { - let mut calldata_cost = 0; - for i in calldata { - if *i != 0 { - // TODO: Check if EVM pre-eip2028 and charge 64 - // GTXDATANONZERO = 16 - calldata_cost += 16 - } else { - // GTXDATAZERO = 4 - calldata_cost += 4; - } - } - gas.saturating_sub(calldata_cost.into()).saturating_sub(BASE_TX_COST.into()) -} - /// Flattens a group of contracts into maps of all events and functions pub fn flatten_known_contracts( contracts: &BTreeMap)>, @@ -1020,37 +1001,53 @@ mod tests { solc::{artifacts::CompactContractBytecode, Project, ProjectPathsConfig}, types::{Address, Bytes}, }; - use std::path::PathBuf; #[test] - #[ignore] // TODO: This needs to be re-enabled one it's fixed in ethers-solc. fn test_linking() { - let lib_test_json_lib_test = "6101d1610053600b82828239805160001a607314610046577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c806314ba3f121461003a575b600080fd5b610054600480360381019061004f91906100bb565b61006a565b60405161006191906100f7565b60405180910390f35b60006064826100799190610141565b9050919050565b600080fd5b6000819050919050565b61009881610085565b81146100a357600080fd5b50565b6000813590506100b58161008f565b92915050565b6000602082840312156100d1576100d0610080565b5b60006100df848285016100a6565b91505092915050565b6100f181610085565b82525050565b600060208201905061010c60008301846100e8565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061014c82610085565b915061015783610085565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156101905761018f610112565b5b82820290509291505056fea264697066735822122089bbb5614fb9e62f207b40682b397b25f2000c514857bf7959055b0d9b5dcfbf64736f6c634300080b0033"; - let lib_test_nested_json_lib_test_nested = "610266610053600b82828239805160001a607314610046577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c80639acc23361461003a575b600080fd5b610054600480360381019061004f9190610116565b61006a565b604051610061919061015c565b60405180910390f35b60007347e9fbef8c83a1714f1951f142132e6e90f5fa5d6314ba3f1260656040518263ffffffff1660e01b81526004016100a491906101bc565b602060405180830381865af41580156100c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e59190610203565b9050919050565b600080fd5b600381106100fe57600080fd5b50565b600081359050610110816100f1565b92915050565b60006020828403121561012c5761012b6100ec565b5b600061013a84828501610101565b91505092915050565b6000819050919050565b61015681610143565b82525050565b6000602082019050610171600083018461014d565b92915050565b6000819050919050565b6000819050919050565b60006101a66101a161019c84610177565b610181565b610143565b9050919050565b6101b68161018b565b82525050565b60006020820190506101d160008301846101ad565b92915050565b6101e081610143565b81146101eb57600080fd5b50565b6000815190506101fd816101d7565b92915050565b600060208284031215610219576102186100ec565b5b6000610227848285016101ee565b9150509291505056fea26469706673582212204d96467c5d42f97ecaa460cca5137364d61ae850ee0be7c2d9c5ffb045bf8dc364736f6c634300080b0033"; let contract_names = [ - "DsTestMini.json:DsTestMini", - "LibLinkingTest.json:LibLinkingTest", - "LibTest.json:LibTest", - "LibTestNested.json:LibTestNested", - "Main.json:Main", + "DSTest.json:DSTest", + "Lib.json:Lib", + "LibraryConsumer.json:LibraryConsumer", + "LibraryLinkingTest.json:LibraryLinkingTest", + "NestedLib.json:NestedLib", ]; - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata/linking"); - let paths = ProjectPathsConfig::builder().root(&root).sources(&root).build().unwrap(); + let paths = ProjectPathsConfig::builder() + .root("../testdata") + .sources("../testdata") + .build() + .unwrap(); let project = Project::builder().paths(paths).ephemeral().no_artifacts().build().unwrap(); let output = project.compile().unwrap(); let contracts = output .into_artifacts() + .filter(|(i, _)| contract_names.contains(&i.slug().as_str())) .map(|(i, c)| (i.slug(), c.into_contract_bytecode())) .collect::>(); let mut known_contracts: BTreeMap)> = Default::default(); let mut deployable_contracts: BTreeMap)> = Default::default(); - assert_eq!(&contracts.keys().collect::>()[..], &contract_names[..]); + let lib_linked = hex::encode( + &contracts["Lib.json:Lib"] + .bytecode + .clone() + .expect("library had no bytecode") + .object + .into_bytes() + .expect("could not get bytecode as bytes"), + ); + let nested_lib_unlinked = &contracts["NestedLib.json:NestedLib"] + .bytecode + .as_ref() + .expect("nested library had no bytecode") + .object + .as_str() + .expect("could not get bytecode as str") + .to_string(); link( &contracts, @@ -1060,47 +1057,32 @@ mod tests { |file, key| (format!("{}.json:{}", key, key), file, key), |post_link_input| { match post_link_input.fname.as_str() { - "DsTestMini.json:DsTestMini" => { + "DSTest.json:DSTest" => { assert_eq!(post_link_input.dependencies.len(), 0); } - "LibLinkingTest.json:LibLinkingTest" => { + "LibraryLinkingTest.json:LibraryLinkingTest" => { assert_eq!(post_link_input.dependencies.len(), 3); - assert_eq!( - hex::encode(post_link_input.dependencies[0].clone()), - lib_test_json_lib_test - ); - assert_eq!( - hex::encode(post_link_input.dependencies[1].clone()), - lib_test_json_lib_test - ); - assert_eq!( - hex::encode(post_link_input.dependencies[2].clone()), - lib_test_nested_json_lib_test_nested + assert_eq!(hex::encode(&post_link_input.dependencies[0]), lib_linked); + assert_eq!(hex::encode(&post_link_input.dependencies[1]), lib_linked); + assert_ne!( + hex::encode(&post_link_input.dependencies[2]), + *nested_lib_unlinked ); } - "LibTest.json:LibTest" => { + "Lib.json:Lib" => { assert_eq!(post_link_input.dependencies.len(), 0); } - "LibTestNested.json:LibTestNested" => { + "NestedLib.json:NestedLib" => { assert_eq!(post_link_input.dependencies.len(), 1); - assert_eq!( - hex::encode(post_link_input.dependencies[0].clone()), - lib_test_json_lib_test - ); + assert_eq!(hex::encode(&post_link_input.dependencies[0]), lib_linked); } - "Main.json:Main" => { + "LibraryConsumer.json:LibraryConsumer" => { assert_eq!(post_link_input.dependencies.len(), 3); - assert_eq!( - hex::encode(post_link_input.dependencies[0].clone()), - lib_test_json_lib_test - ); - assert_eq!( - hex::encode(post_link_input.dependencies[1].clone()), - lib_test_json_lib_test - ); - assert_eq!( - hex::encode(post_link_input.dependencies[2].clone()), - lib_test_nested_json_lib_test_nested + assert_eq!(hex::encode(&post_link_input.dependencies[0]), lib_linked); + assert_eq!(hex::encode(&post_link_input.dependencies[1]), lib_linked); + assert_ne!( + hex::encode(&post_link_input.dependencies[2]), + *nested_lib_unlinked ); } _ => assert!(false), @@ -1190,19 +1172,30 @@ mod tests { #[test] #[cfg(any(target_os = "linux", target_os = "macos"))] fn abi2solidity() { - let contract_abi: Abi = - serde_json::from_slice(&std::fs::read("testdata/interfaceTestABI.json").unwrap()) - .unwrap(); + let contract_abi: Abi = serde_json::from_slice( + &std::fs::read("../testdata/fixtures/SolidityGeneration/InterfaceABI.json").unwrap(), + ) + .unwrap(); assert_eq!( - std::str::from_utf8(&std::fs::read("testdata/interfaceTest.sol").unwrap()) + std::str::from_utf8( + &std::fs::read( + "../testdata/fixtures/SolidityGeneration/GeneratedNamedInterface.sol" + ) .unwrap() - .to_string(), + ) + .unwrap() + .to_string(), abi_to_solidity(&contract_abi, "test").unwrap() ); assert_eq!( - std::str::from_utf8(&std::fs::read("testdata/interfaceTestNoName.sol").unwrap()) + std::str::from_utf8( + &std::fs::read( + "../testdata/fixtures/SolidityGeneration/GeneratedUnnamedInterface.sol" + ) .unwrap() - .to_string(), + ) + .unwrap() + .to_string(), abi_to_solidity(&contract_abi, "").unwrap() ); } diff --git a/utils/testdata/linking/LinkTest.sol b/utils/testdata/linking/LinkTest.sol deleted file mode 100644 index b6ae16ba928f..000000000000 --- a/utils/testdata/linking/LinkTest.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.11; - -//import "./LibTest.sol"; - -// a library that needs to be linked with another library -library LibTestNested { - enum TestEnum2 { - A, - B, - C - } - - function foobar(TestEnum2 test) public view returns (uint256) { - return LibTest.foobar(101); - } -} - -// a library -library LibTest { - function foobar(uint256 a) public view returns (uint256) { - return a * 100; - } -} - - -// a contract that uses 2 linked libraries -contract Main { - function foo() public returns (uint256) { - return LibTest.foobar(1); - } - - function bar() public returns (uint256) { - return LibTestNested.foobar(LibTestNested.TestEnum2(0)); - } -} - -contract DsTestMini { - bool public failed; - - function fail() private { - failed = true; - } - - function assertEq(uint a, uint b) internal { - if (a != b) { - fail(); - } - } -} - - -contract LibLinkingTest is DsTestMini { - Main main; - function setUp() public { - main = new Main(); - } - - function testCall() public { - assertEq(100, main.foo()); - } - - function testCall2() public { - assertEq(10100, main.bar()); - } -}