From 331844dcf278ccdf96ce3b63fb3e5f2c78970561 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Sat, 21 Jan 2023 00:19:38 +0100 Subject: [PATCH 001/124] fix: link (#545) --- docs/modules/ROOT/pages/udc.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/udc.adoc b/docs/modules/ROOT/pages/udc.adoc index 70a95bf70..61783690b 100644 --- a/docs/modules/ROOT/pages/udc.adoc +++ b/docs/modules/ROOT/pages/udc.adoc @@ -2,7 +2,7 @@ The Universal Deployer Contract (UDC) is a singleton smart contract that wraps the https://www.cairo-lang.org/docs/hello_starknet/deploying_from_contracts.html#the-deploy-system-call[`deploy syscall`] to expose it to any contract that doesn't implement it, such as account contracts. You can think of it as a **standardized generic factory for StarkNet contracts**. -And since StarkNet has no deployment transaction type, it offers a canonical way to deploy smart contracts by following the [standard deployer interface](https://community.starknet.io/t/snip-deployer-contract-interface/2772) and emitting a `ContractDeployed` event. +And since StarkNet has no deployment transaction type, it offers a canonical way to deploy smart contracts by following the https://community.starknet.io/t/snip-deployer-contract-interface/2772[standard deployer interface] and emitting a `ContractDeployed` event. TIP: For information on design decisions, see the https://community.starknet.io/t/universal-deployer-contract-proposal/1864[Universal Deployer Contract Proposal]. From b9ec20b8e2ccff982f85875aa884f2c68e76feee Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 17 Feb 2023 19:43:59 -0500 Subject: [PATCH 002/124] add submodule --- .gitmodules | 3 +++ cairo | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 cairo diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..269eb8546 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cairo"] + path = cairo + url = https://github.com/starkware-libs/cairo.git diff --git a/cairo b/cairo new file mode 160000 index 000000000..b89f575b6 --- /dev/null +++ b/cairo @@ -0,0 +1 @@ +Subproject commit b89f575b6d3873b5474af3731d68b7ac2614043e From bb401246d53f3e4555ed8ee13579dec409799103 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 17 Feb 2023 19:44:37 -0500 Subject: [PATCH 003/124] update cairo --- cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo b/cairo index b89f575b6..1991669a0 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit b89f575b6d3873b5474af3731d68b7ac2614043e +Subproject commit 1991669a0453bd65541ff81a12772bac05130052 From a0c3157791d71a7b3e4e256c36754edc853f77e9 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 17 Feb 2023 19:45:32 -0500 Subject: [PATCH 004/124] add Cargo and Makefile --- Cargo.lock | 3190 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 89 ++ Makefile | 28 + 3 files changed, 3307 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 Makefile diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..696ce9451 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3190 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits 0.2.15", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.0-alpha.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cf4b42c978bd9b967f6a2ba54a4cc57f34780f9d0cf86916f8f7e922b4f80fe" +dependencies = [ + "ark-ff-asm 0.4.0-alpha.7", + "ark-ff-macros 0.4.0-alpha.7", + "ark-serialize 0.4.0-alpha.7", + "ark-std 0.4.0-alpha", + "derivative", + "digest 0.10.6", + "itertools", + "num-bigint", + "num-traits 0.2.15", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.0-alpha.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3ba0a3cf584a8ede533a1749b86040e9018cf752265fc39a71c69fe1fafaba5" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits 0.2.15", + "quote", + "syn", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.0-alpha.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9989a01ec42d2f31232796831077ef730d4cd0d0931f5ef6962a43ebddd215fa" +dependencies = [ + "num-bigint", + "num-traits 0.2.15", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.0-alpha.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84aeb60f7c6792ae71e9e2225412ecd59d7c85cfec4183a8c497f2a3a4cdb36e" +dependencies = [ + "ark-std 0.4.0-alpha", + "digest 0.10.6", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits 0.2.15", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5b16d734e9b2e43886ff586755219df7fb9639cc04ab00c7e636708a5ba06a" +dependencies = [ + "num-traits 0.2.15", + "rand", +] + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-trait" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "auto_impl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bigdecimal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits 0.2.15", +] + +[[package]] +name = "bimap" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0455254eb5c6964c4545d8bac815e1a1be4f3afe0ae695ea539c12d728d44b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + +[[package]] +name = "cairo-felt" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a792f409586c42c2d62cff582989e573d45b0855be95e022421d25f608364cc1" +dependencies = [ + "lazy_static", + "num-bigint", + "num-integer", + "num-traits 0.2.15", + "serde", +] + +[[package]] +name = "cairo-lang-casm" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-utils", + "env_logger", + "indoc", + "itertools", + "num-bigint", + "num-traits 0.2.15", + "pretty_assertions", + "test-case", + "test-log", + "thiserror", +] + +[[package]] +name = "cairo-lang-compiler" +version = "1.0.0-alpha.2" +dependencies = [ + "anyhow", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-lowering", + "cairo-lang-parser", + "cairo-lang-plugins", + "cairo-lang-project", + "cairo-lang-semantic", + "cairo-lang-sierra", + "cairo-lang-sierra-generator", + "cairo-lang-syntax", + "cairo-lang-utils", + "clap 4.0.26", + "log", + "salsa", + "test-log", + "thiserror", +] + +[[package]] +name = "cairo-lang-debug" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-proc-macros", + "cairo-lang-utils", + "env_logger", + "salsa", + "test-log", +] + +[[package]] +name = "cairo-lang-defs" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-debug", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-parser", + "cairo-lang-syntax", + "cairo-lang-test-utils", + "cairo-lang-utils", + "env_logger", + "indexmap", + "indoc", + "itertools", + "pretty_assertions", + "salsa", + "smol_str", + "test-log", +] + +[[package]] +name = "cairo-lang-diagnostics" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-filesystem", + "cairo-lang-proc-macros", + "cairo-lang-utils", + "env_logger", + "indoc", + "itertools", + "pretty_assertions", + "salsa", + "test-log", +] + +[[package]] +name = "cairo-lang-eq-solver" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-utils", + "env_logger", + "good_lp", + "indexmap", + "indoc", + "itertools", + "test-case", + "test-log", +] + +[[package]] +name = "cairo-lang-filesystem" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-debug", + "cairo-lang-utils", + "env_logger", + "path-clean", + "salsa", + "smol_str", + "test-log", +] + +[[package]] +name = "cairo-lang-formatter" +version = "1.0.0-alpha.2" +dependencies = [ + "anyhow", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-parser", + "cairo-lang-syntax", + "cairo-lang-utils", + "clap 4.0.26", + "colored", + "diffy", + "ignore", + "itertools", + "log", + "pretty_assertions", + "salsa", + "smol_str", + "test-case", + "test-log", +] + +[[package]] +name = "cairo-lang-language-server" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-compiler", + "cairo-lang-debug", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-formatter", + "cairo-lang-lowering", + "cairo-lang-parser", + "cairo-lang-plugins", + "cairo-lang-project", + "cairo-lang-semantic", + "cairo-lang-starknet", + "cairo-lang-syntax", + "cairo-lang-utils", + "lsp-types", + "salsa", + "serde", + "serde_json", + "test-log", + "tokio", + "tower-lsp", +] + +[[package]] +name = "cairo-lang-lowering" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-debug", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-parser", + "cairo-lang-plugins", + "cairo-lang-proc-macros", + "cairo-lang-semantic", + "cairo-lang-syntax", + "cairo-lang-test-utils", + "cairo-lang-utils", + "env_logger", + "id-arena", + "indoc", + "itertools", + "log", + "num-bigint", + "num-traits 0.2.15", + "pretty_assertions", + "salsa", + "smol_str", + "test-log", +] + +[[package]] +name = "cairo-lang-parser" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-syntax", + "cairo-lang-syntax-codegen", + "cairo-lang-test-utils", + "cairo-lang-utils", + "colored", + "env_logger", + "itertools", + "log", + "pretty_assertions", + "salsa", + "smol_str", + "test-case", + "test-log", +] + +[[package]] +name = "cairo-lang-plugins" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-debug", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-parser", + "cairo-lang-semantic", + "cairo-lang-syntax", + "cairo-lang-test-utils", + "cairo-lang-utils", + "env_logger", + "indoc", + "itertools", + "pretty_assertions", + "salsa", + "smol_str", + "test-case", + "test-log", +] + +[[package]] +name = "cairo-lang-proc-macros" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-debug", + "quote", + "syn", +] + +[[package]] +name = "cairo-lang-project" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-filesystem", + "indoc", + "serde", + "smol_str", + "test-log", + "thiserror", + "toml", +] + +[[package]] +name = "cairo-lang-runner" +version = "1.0.0-alpha.2" +dependencies = [ + "anyhow", + "ark-ff 0.4.0-alpha.7", + "ark-std 0.3.0", + "cairo-felt", + "cairo-lang-casm", + "cairo-lang-compiler", + "cairo-lang-diagnostics", + "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-gas", + "cairo-lang-sierra-generator", + "cairo-lang-sierra-to-casm", + "cairo-lang-utils", + "cairo-vm", + "clap 4.0.26", + "itertools", + "num-bigint", + "num-traits 0.2.15", + "pretty_assertions", + "salsa", + "test-case", + "thiserror", +] + +[[package]] +name = "cairo-lang-semantic" +version = "1.0.0-alpha.2" +dependencies = [ + "assert_matches", + "cairo-lang-debug", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-parser", + "cairo-lang-plugins", + "cairo-lang-proc-macros", + "cairo-lang-syntax", + "cairo-lang-test-utils", + "cairo-lang-utils", + "env_logger", + "id-arena", + "indoc", + "itertools", + "log", + "num-bigint", + "num-traits 0.2.15", + "pretty_assertions", + "salsa", + "smol_str", + "test-case", + "test-log", + "unescaper", +] + +[[package]] +name = "cairo-lang-sierra" +version = "1.0.0-alpha.2" +dependencies = [ + "assert_matches", + "bimap", + "cairo-lang-utils", + "const-fnv1a-hash", + "convert_case", + "derivative", + "env_logger", + "indoc", + "itertools", + "lalrpop", + "lalrpop-util", + "num-bigint", + "num-traits 0.2.15", + "pretty_assertions", + "regex", + "salsa", + "serde", + "sha3", + "smol_str", + "test-case", + "test-log", + "thiserror", +] + +[[package]] +name = "cairo-lang-sierra-ap-change" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-eq-solver", + "cairo-lang-sierra", + "cairo-lang-utils", + "env_logger", + "indoc", + "itertools", + "test-case", + "test-log", + "thiserror", +] + +[[package]] +name = "cairo-lang-sierra-gas" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-eq-solver", + "cairo-lang-sierra", + "cairo-lang-test-utils", + "cairo-lang-utils", + "env_logger", + "indoc", + "itertools", + "pretty_assertions", + "test-case", + "test-log", + "thiserror", +] + +[[package]] +name = "cairo-lang-sierra-generator" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-debug", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-lowering", + "cairo-lang-parser", + "cairo-lang-plugins", + "cairo-lang-proc-macros", + "cairo-lang-semantic", + "cairo-lang-sierra", + "cairo-lang-syntax", + "cairo-lang-test-utils", + "cairo-lang-utils", + "env_logger", + "id-arena", + "indexmap", + "indoc", + "itertools", + "log", + "num-bigint", + "pretty_assertions", + "salsa", + "smol_str", + "test-case", + "test-log", +] + +[[package]] +name = "cairo-lang-sierra-to-casm" +version = "1.0.0-alpha.2" +dependencies = [ + "assert_matches", + "cairo-felt", + "cairo-lang-casm", + "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-gas", + "cairo-lang-utils", + "clap 4.0.26", + "env_logger", + "indoc", + "itertools", + "log", + "num-bigint", + "num-traits 0.2.15", + "pretty_assertions", + "test-case", + "test-log", + "thiserror", +] + +[[package]] +name = "cairo-lang-starknet" +version = "1.0.0-alpha.2" +dependencies = [ + "anyhow", + "cairo-lang-compiler", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-lowering", + "cairo-lang-parser", + "cairo-lang-plugins", + "cairo-lang-semantic", + "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-gas", + "cairo-lang-sierra-generator", + "cairo-lang-sierra-to-casm", + "cairo-lang-syntax", + "cairo-lang-test-utils", + "cairo-lang-utils", + "clap 4.0.26", + "convert_case", + "env_logger", + "genco", + "indoc", + "itertools", + "lazy_static", + "log", + "num-bigint", + "num-integer", + "num-traits 0.2.15", + "pretty_assertions", + "serde", + "serde_json", + "sha3", + "smol_str", + "test-case", + "test-log", + "thiserror", +] + +[[package]] +name = "cairo-lang-syntax" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-debug", + "cairo-lang-filesystem", + "cairo-lang-utils", + "env_logger", + "pretty_assertions", + "salsa", + "smol_str", + "test-log", +] + +[[package]] +name = "cairo-lang-syntax-codegen" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-utils", + "env_logger", + "genco", + "log", + "test-log", + "xshell", +] + +[[package]] +name = "cairo-lang-test-runner" +version = "1.0.0-alpha.2" +dependencies = [ + "anyhow", + "cairo-felt", + "cairo-lang-casm", + "cairo-lang-compiler", + "cairo-lang-debug", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-plugins", + "cairo-lang-project", + "cairo-lang-runner", + "cairo-lang-semantic", + "cairo-lang-sierra", + "cairo-lang-sierra-generator", + "cairo-lang-sierra-to-casm", + "cairo-lang-starknet", + "cairo-lang-syntax", + "cairo-lang-utils", + "cairo-vm", + "clap 4.0.26", + "colored", + "itertools", + "num-bigint", + "rayon", + "salsa", + "thiserror", +] + +[[package]] +name = "cairo-lang-test-utils" +version = "1.0.0-alpha.2" +dependencies = [ + "cairo-lang-utils", + "env_logger", + "log", + "pretty_assertions", + "test-log", +] + +[[package]] +name = "cairo-lang-utils" +version = "1.0.0-alpha.2" +dependencies = [ + "chrono", + "env_logger", + "indexmap", + "itertools", + "log", + "test-case", + "test-log", +] + +[[package]] +name = "cairo-vm" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4fa1ade23dd2a6e671a923e748406c2c5f6c27fc186950ed04fae392b552a51" +dependencies = [ + "bincode", + "cairo-felt", + "clap 3.2.23", + "generic-array", + "hex", + "keccak", + "lazy_static", + "mimalloc", + "nom", + "num-bigint", + "num-integer", + "num-traits 0.2.15", + "parse-hyperlinks", + "rand_core", + "serde", + "serde_bytes", + "serde_json", + "sha2 0.10.6", + "sha3", + "starknet-crypto", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits 0.2.15", + "time", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "clap" +version = "3.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +dependencies = [ + "atty", + "bitflags", + "clap_derive 3.2.18", + "clap_lex 0.2.4", + "indexmap", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap" +version = "4.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" +dependencies = [ + "atty", + "bitflags", + "clap_derive 4.0.21", + "clap_lex 0.3.0", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "3.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +dependencies = [ + "heck 0.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_derive" +version = "4.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +dependencies = [ + "heck 0.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "const-fnv1a-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "cxx" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core 0.9.4", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "diffy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e616e59155c92257e84970156f506287853355f58cd4a6eb167385722c32b790" +dependencies = [ + "nu-ansi-term", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "ena" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +dependencies = [ + "log", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "genco" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8598ff0782dbc5231cf9eb727c1c5e398515b7b62ee68761c2c73950a1de1f4" +dependencies = [ + "genco-macros", + "relative-path", + "smallvec", +] + +[[package]] +name = "genco-macros" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40803f2757f84c877f088e62420931f6e05a72514f1f03630384aa30b91d667b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "globset" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "good_lp" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b51d78cbb7b734379eea7f811ddb33b2b13defefa1dab50068d7bc7f781a3056" +dependencies = [ + "fnv", + "minilp", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "indoc" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" +dependencies = [ + "ascii-canvas", + "atty", + "bit-set", + "diff", + "ena", + "itertools", + "lalrpop-util", + "petgraph", + "pico-args", + "regex", + "regex-syntax", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" +dependencies = [ + "regex", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d1c67deb83e6b75fa4fe3309e09cfeade12e7721d95322af500d3814ea60c9" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lsp-types" +version = "0.93.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51" +dependencies = [ + "bitflags", + "serde", + "serde_json", + "serde_repr", + "url", +] + +[[package]] +name = "matrixmultiply" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916806ba0031cd542105d916a97c8572e1fa6dd79c9c51e7eb43a09ec2dd84c1" +dependencies = [ + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mimalloc" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2374e2999959a7b583e1811a1ddbf1d3a4b9496eceb9746f1192a59d871eca" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "minilp" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a7750a9e5076c660b7bec5e6457b4dbff402b9863c8d112891434e18fd5385" +dependencies = [ + "log", + "sprs", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "ndarray" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac06db03ec2f46ee0ecdca1a1c34a99c0d188a0d83439b84bf0cb4b386e4ab09" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits 0.2.15", + "rawpointer", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits 0.2.15", + "serde", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits 0.2.15", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits 0.2.15", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.15", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.4", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "parse-hyperlinks" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0181d37c4d5ae35cc8be7cf823c1a933005661da6a08bcb2855aa392c9a54b8e" +dependencies = [ + "html-escape", + "nom", + "percent-encoding", + "thiserror", +] + +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + +[[package]] +name = "path-clean" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd" + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pest" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "petgraph" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "pretty_assertions" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +dependencies = [ + "ctor", + "diff", + "output_vt100", + "yansi", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "relative-path" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df32d82cedd1499386877b062ebe8721f806de80b08d183c70184ef17dd1d42" + +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.16", +] + +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "salsa" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b84d9f96071f3f3be0dc818eae3327625d8ebc95b58da37d6850724f31d3403" +dependencies = [ + "crossbeam-utils", + "indexmap", + "lock_api", + "log", + "oorandom", + "parking_lot 0.11.2", + "rustc-hash", + "salsa-macros", + "smallvec", +] + +[[package]] +name = "salsa-macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3904a4ba0a9d0211816177fd34b04c7095443f8cdacd11175064fe541c8fe2" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +dependencies = [ + "digest 0.10.6", + "keccak", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "smol_str" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "sprs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec63571489873d4506683915840eeb1bb16b3198ee4894cc6f2fe3013d505e56" +dependencies = [ + "ndarray", + "num-complex", + "num-traits 0.1.43", +] + +[[package]] +name = "starknet-crypto" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be7d6b2c959fde2a10dbc31d54bdd0307eecb7ef6c05c23a0263e65b57b3e18a" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits 0.2.15", + "rfc6979", + "sha2 0.9.9", + "starknet-crypto-codegen", + "starknet-curve", + "starknet-ff", + "thiserror", + "zeroize", +] + +[[package]] +name = "starknet-crypto-codegen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6569d70430f0f6edc41f6820d00acf63356e6308046ca01e57eeac22ad258c47" +dependencies = [ + "starknet-curve", + "starknet-ff", + "syn", +] + +[[package]] +name = "starknet-curve" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84be6079d3060fdbd8b5335574fef3d3783fa2f7ee6474d08ae0c1e4b0a29ba4" +dependencies = [ + "starknet-ff", +] + +[[package]] +name = "starknet-ff" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5874510620214ebeac50915b01d67437d8ca10a6682b1de85b93cd01157b58eb" +dependencies = [ + "ark-ff 0.3.0", + "bigdecimal", + "crypto-bigint", + "getrandom", + "hex", + "num-bigint", + "serde", + "thiserror", +] + +[[package]] +name = "string_cache" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot 0.12.1", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "test-case" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d6cf5a7dffb3f9dceec8e6b8ca528d9bd71d36c9f074defb548ce161f598c0" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-macros" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45b7bf6e19353ddd832745c8fcf77a17a93171df7151187f26623f2b75b5b26" +dependencies = [ + "cfg-if", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "test-log" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f0c854faeb68a048f0f2dc410c5ddae3bf83854ef0e4977d58306a5edef50e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tests" +version = "1.0.0-alpha.2" +dependencies = [ + "assert_matches", + "cairo-felt", + "cairo-lang-casm", + "cairo-lang-compiler", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-parser", + "cairo-lang-plugins", + "cairo-lang-runner", + "cairo-lang-semantic", + "cairo-lang-sierra", + "cairo-lang-sierra-gas", + "cairo-lang-sierra-generator", + "cairo-lang-sierra-to-casm", + "cairo-lang-syntax", + "cairo-lang-test-utils", + "cairo-lang-utils", + "env_logger", + "itertools", + "log", + "num-bigint", + "pretty_assertions", + "salsa", + "test-case", + "test-log", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "parking_lot 0.12.1", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +dependencies = [ + "serde", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-lsp" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43e094780b4447366c59f79acfd65b1375ecaa84e61dddbde1421aa506334024" +dependencies = [ + "async-trait", + "auto_impl", + "bytes", + "dashmap", + "futures", + "httparse", + "log", + "lsp-types", + "memchr", + "serde", + "serde_json", + "tokio", + "tokio-util", + "tower", + "tower-lsp-macros", +] + +[[package]] +name = "tower-lsp-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebd99eec668d0a450c177acbc4d05e0d0d13b1f8d3db13cd706c52cbec4ac04" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unescaper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "995483205de764db1185c9461a000fff73fa4b9ee2bbe4c8b4027a94692700fe" +dependencies = [ + "thiserror", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "xshell" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d47097dc5c85234b1e41851b3422dd6d19b3befdd35b4ae5ce386724aeca981" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88301b56c26dd9bf5c43d858538f82d6f3f7764767defbc5d34e59459901c41a" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..1179081f2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,89 @@ +[workspace] + +members = [ + "cairo/crates/cairo-lang-casm", + "cairo/crates/cairo-lang-compiler", + "cairo/crates/cairo-lang-utils", + "cairo/crates/cairo-lang-debug", + "cairo/crates/cairo-lang-defs", + "cairo/crates/cairo-lang-proc-macros", + "cairo/crates/cairo-lang-diagnostics", + "cairo/crates/cairo-lang-eq-solver", + "cairo/crates/cairo-lang-filesystem", + "cairo/crates/cairo-lang-formatter", + "cairo/crates/cairo-lang-language-server", + "cairo/crates/cairo-lang-lowering", + "cairo/crates/cairo-lang-parser", + "cairo/crates/cairo-lang-plugins", + "cairo/crates/cairo-lang-project", + "cairo/crates/cairo-lang-runner", + "cairo/crates/cairo-lang-semantic", + "cairo/crates/cairo-lang-sierra-ap-change", + "cairo/crates/cairo-lang-sierra-gas", + "cairo/crates/cairo-lang-sierra-generator", + "cairo/crates/cairo-lang-sierra-to-casm", + "cairo/crates/cairo-lang-sierra", + "cairo/crates/cairo-lang-starknet", + "cairo/crates/cairo-lang-syntax-codegen", + "cairo/crates/cairo-lang-syntax", + "cairo/crates/cairo-lang-test-runner", + "cairo/tests", +] + +[workspace.package] +version = "1.0.0-alpha.2" +edition = "2021" +repository = "https://github.com/starkware-libs/cairo/" +license = "Apache-2.0" +license-file = "LICENSE" + +[workspace.dependencies] +anyhow = "1.0.66" +ark-ff = "0.4.0-alpha.7" +ark-std = "0.3.0" +assert_matches = "1.5" +bimap = "0.6.2" +cairo-felt = "0.1.1" +cairo-vm = "0.1.2" +chrono = "0.4.23" +clap = { version = "4.0", features = ["derive"] } +colored = "2" +const-fnv1a-hash = "1.1.0" +convert_case = "0.6.0" +derivative = "2.2.0" +diffy = "0.3.0" +env_logger = "0.9.3" +genco = "0.17.0" +good_lp = { version = "1.3.2", features = ["minilp"], default-features = false } +id-arena = "2.2.1" +ignore = "0.4.20" +indexmap = "1.9.1" +indoc = "1.0.7" +itertools = "0.10.3" +lalrpop-util = { version = "0.19.8", features = ["lexer"] } +lazy_static = "1.4.0" +log = "0.4" +lsp = { version = "0.93", package = "lsp-types" } +num-bigint = "0.4" +num-integer = "0.1" +num-traits = "0.2" +path-clean = "0.1.0" +pretty_assertions = "1.2.1" +proc-macro2 = "1.0" +quote = "1.0.21" +rayon = "0.9.0" +salsa = "0.16.1" +serde = { version = "1.0.130", features = ["derive"] } +serde_json = "1.0" +sha3 = "0.10.6" +smol_str = "0.1.23" +syn = { version = "1.0.99", features = ["full", "extra-traits"] } +test-case = "2.2.2" +test-case-macros = "2.2.2" +test-log = "0.2.11" +thiserror = "1.0.32" +tokio = { version = "1.18.2", features = ["full", "sync"] } +toml = "0.4.2" +tower-lsp = "0.17.0" +unescaper = "0.1.1" +xshell = "0.2.2" diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..020e49482 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +.SILENT: +.PHONY: compile +SOURCE_FOLDER=./src/openzeppelin + +install: + git submodule init && git submodule update && cp -rf cairo/corelib . + +update: + git submodule update && cp -rf cairo/corelib . + +build: + cargo build + +test: + cargo run --bin cairo-test -- --starknet --path $(dir) + +format: + cargo run --bin cairo-format -- --recursive $(SOURCE_FOLDER) --print-parsing-errors + +check-format: + cargo run --bin cairo-format -- --check --recursive $(SOURCE_FOLDER) + +starknet-compile: + mkdir -p artifacts && \ + cargo run --bin starknet-compile -- ${dir} artifacts/$(shell basename $(dir)).json --allowed-libfuncs-list-name experimental_v0.1.0 + +language-server: + cargo build --bin cairo-language-server --release From 3a6e20dd7897158258e0d9a7049d22822142b2ba Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 09:58:52 -0500 Subject: [PATCH 005/124] update cairo --- cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo b/cairo index 1991669a0..7d27aee2c 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 1991669a0453bd65541ff81a12772bac05130052 +Subproject commit 7d27aee2c7832592f3d091d01c3ceb39e45484e1 From 96431dedb001fb4adf822bcc5a7f4a5ad54e8943 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 10:00:44 -0500 Subject: [PATCH 006/124] add deps in cairo_project, create lib --- src/openzeppelin/token/erc20/cairo_project.toml | 3 +++ src/openzeppelin/token/erc20/lib.cairo | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 src/openzeppelin/token/erc20/cairo_project.toml create mode 100644 src/openzeppelin/token/erc20/lib.cairo diff --git a/src/openzeppelin/token/erc20/cairo_project.toml b/src/openzeppelin/token/erc20/cairo_project.toml new file mode 100644 index 000000000..ffd670876 --- /dev/null +++ b/src/openzeppelin/token/erc20/cairo_project.toml @@ -0,0 +1,3 @@ +[crate_roots] +erc20 = "." +presets = "presets" diff --git a/src/openzeppelin/token/erc20/lib.cairo b/src/openzeppelin/token/erc20/lib.cairo new file mode 100644 index 000000000..e87b836c1 --- /dev/null +++ b/src/openzeppelin/token/erc20/lib.cairo @@ -0,0 +1,6 @@ +mod erc20; +use erc20::ERC20Library; + +mod tests; + +mod presets; From 7b387068c30da1652d3cacf433d46e3072eb26e6 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 10:01:26 -0500 Subject: [PATCH 007/124] add presets --- src/openzeppelin/token/erc20/presets.cairo | 3 + .../token/erc20/presets/ERC20.cairo | 169 ++++++++---------- .../token/erc20/presets/ERC20Burnable.cairo | 118 ------------ .../token/erc20/presets/ERC20Mintable.cairo | 130 -------------- .../token/erc20/presets/ERC20Pausable.cairo | 146 --------------- .../erc20/presets/ERC20Upgradeable.cairo | 121 ------------- .../token/erc20/presets/cairo_project.toml | 2 + .../token/erc20/presets/erc20_burnable.cairo | 85 +++++++++ .../token/erc20/presets/erc20_mintable.cairo | 76 ++++++++ .../token/erc20/presets/lib.cairo | 8 + 10 files changed, 244 insertions(+), 614 deletions(-) create mode 100644 src/openzeppelin/token/erc20/presets.cairo delete mode 100644 src/openzeppelin/token/erc20/presets/ERC20Burnable.cairo delete mode 100644 src/openzeppelin/token/erc20/presets/ERC20Mintable.cairo delete mode 100644 src/openzeppelin/token/erc20/presets/ERC20Pausable.cairo delete mode 100644 src/openzeppelin/token/erc20/presets/ERC20Upgradeable.cairo create mode 100644 src/openzeppelin/token/erc20/presets/cairo_project.toml create mode 100644 src/openzeppelin/token/erc20/presets/erc20_burnable.cairo create mode 100644 src/openzeppelin/token/erc20/presets/erc20_mintable.cairo create mode 100644 src/openzeppelin/token/erc20/presets/lib.cairo diff --git a/src/openzeppelin/token/erc20/presets.cairo b/src/openzeppelin/token/erc20/presets.cairo new file mode 100644 index 000000000..0ca3c862c --- /dev/null +++ b/src/openzeppelin/token/erc20/presets.cairo @@ -0,0 +1,3 @@ +mod erc20; +mod erc20_mintable; +mod erc20_burnable; diff --git a/src/openzeppelin/token/erc20/presets/ERC20.cairo b/src/openzeppelin/token/erc20/presets/ERC20.cairo index aec8de917..d2273854e 100644 --- a/src/openzeppelin/token/erc20/presets/ERC20.cairo +++ b/src/openzeppelin/token/erc20/presets/ERC20.cairo @@ -1,100 +1,71 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc20/presets/ERC20.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.token.erc20.library import ERC20 - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, decimals: felt, initial_supply: Uint256, recipient: felt -) { - ERC20.initializer(name, symbol, decimals); - ERC20._mint(recipient, initial_supply); - return (); -} - -// -// Getters -// - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC20.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC20.symbol(); -} - -@view -func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - totalSupply: Uint256 -) { - let (totalSupply: Uint256) = ERC20.total_supply(); - return (totalSupply=totalSupply); -} - -@view -func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - decimals: felt -) { - return ERC20.decimals(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(account: felt) -> ( - balance: Uint256 -) { - return ERC20.balance_of(account); -} - -@view -func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, spender: felt -) -> (remaining: Uint256) { - return ERC20.allowance(owner, spender); -} - -// -// Externals -// - -@external -func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.transfer(recipient, amount); -} - -@external -func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - sender: felt, recipient: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.transfer_from(sender, recipient, amount); -} - -@external -func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.approve(spender, amount); -} - -@external -func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, added_value: Uint256 -) -> (success: felt) { - return ERC20.increase_allowance(spender, added_value); -} - -@external -func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, subtracted_value: Uint256 -) -> (success: felt) { - return ERC20.decrease_allowance(spender, subtracted_value); +#[contract] +mod ERC20 { + use erc20::ERC20Library; + + // TMP starknet testing isn't fully functional. + // Use to ensure paths are correctly set. + #[external] + fn mock_constructor(name: felt, symbol: felt) { + ERC20Library::mock_initializer(name, symbol); + } + + #[constructor] + fn constructor(name: felt, symbol: felt, initial_supply: u256, recipient: ContractAddress) { + ERC20Library::initializer(name, symbol, initial_supply, recipient); + } + + #[view] + fn name() -> felt { + ERC20Library::name() + } + + #[view] + fn symbol() -> felt { + ERC20Library::symbol() + } + + #[view] + fn decimals() -> u8 { + ERC20Library::decimals() + } + + #[view] + fn totalSupply() -> u256 { + ERC20Library::total_supply() + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + ERC20Library::balance_of(account) + } + + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + ERC20Library::allowance(owner, spender) + } + + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + ERC20Library::transfer(recipient, amount) + } + + #[external] + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20Library::transfer_from(sender, recipient, amount) + } + + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool { + ERC20Library::approve(spender, amount) + } + + #[external] + fn increaseAllowance(spender: ContractAddress, added_value: u256) -> bool { + ERC20Library::increase_allowance(spender, added_value) + } + + #[external] + fn decreaseAllowance(spender: ContractAddress, subtracted_value: u256) -> bool { + ERC20Library::decrease_allowance(spender, subtracted_value) + } } diff --git a/src/openzeppelin/token/erc20/presets/ERC20Burnable.cairo b/src/openzeppelin/token/erc20/presets/ERC20Burnable.cairo deleted file mode 100644 index 137fde7ce..000000000 --- a/src/openzeppelin/token/erc20/presets/ERC20Burnable.cairo +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Cairo Contracts v0.6.1 (token/erc20/presets/ERC20Burnable.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 -from starkware.starknet.common.syscalls import get_caller_address - -from openzeppelin.token.erc20.library import ERC20 - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, decimals: felt, initial_supply: Uint256, recipient: felt -) { - ERC20.initializer(name, symbol, decimals); - ERC20._mint(recipient, initial_supply); - return (); -} - -// -// Getters -// - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC20.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC20.symbol(); -} - -@view -func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - totalSupply: Uint256 -) { - let (totalSupply: Uint256) = ERC20.total_supply(); - return (totalSupply=totalSupply); -} - -@view -func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - decimals: felt -) { - return ERC20.decimals(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(account: felt) -> ( - balance: Uint256 -) { - return ERC20.balance_of(account); -} - -@view -func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, spender: felt -) -> (remaining: Uint256) { - return ERC20.allowance(owner, spender); -} - -// -// External -// - -@external -func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.transfer(recipient, amount); -} - -@external -func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - sender: felt, recipient: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.transfer_from(sender, recipient, amount); -} - -@external -func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.approve(spender, amount); -} - -@external -func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, added_value: Uint256 -) -> (success: felt) { - return ERC20.increase_allowance(spender, added_value); -} - -@external -func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, subtracted_value: Uint256 -) -> (success: felt) { - return ERC20.decrease_allowance(spender, subtracted_value); -} - -@external -func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(amount: Uint256) { - let (caller) = get_caller_address(); - ERC20._burn(caller, amount); - return (); -} - -@external -func burnFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - account: felt, amount: Uint256 -) { - let (caller) = get_caller_address(); - ERC20._spend_allowance(account, caller, amount); - ERC20._burn(account, amount); - return (); -} diff --git a/src/openzeppelin/token/erc20/presets/ERC20Mintable.cairo b/src/openzeppelin/token/erc20/presets/ERC20Mintable.cairo deleted file mode 100644 index f9e43843f..000000000 --- a/src/openzeppelin/token/erc20/presets/ERC20Mintable.cairo +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc20/presets/ERC20Mintable.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.access.ownable.library import Ownable -from openzeppelin.token.erc20.library import ERC20 - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, decimals: felt, initial_supply: Uint256, recipient: felt, owner: felt -) { - ERC20.initializer(name, symbol, decimals); - ERC20._mint(recipient, initial_supply); - Ownable.initializer(owner); - return (); -} - -// -// Getters -// - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC20.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC20.symbol(); -} - -@view -func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - totalSupply: Uint256 -) { - let (totalSupply: Uint256) = ERC20.total_supply(); - return (totalSupply=totalSupply); -} - -@view -func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - decimals: felt -) { - return ERC20.decimals(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(account: felt) -> ( - balance: Uint256 -) { - return ERC20.balance_of(account); -} - -@view -func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, spender: felt -) -> (remaining: Uint256) { - return ERC20.allowance(owner, spender); -} - -@view -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - -// -// Externals -// - -@external -func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.transfer(recipient, amount); -} - -@external -func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - sender: felt, recipient: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.transfer_from(sender, recipient, amount); -} - -@external -func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.approve(spender, amount); -} - -@external -func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, added_value: Uint256 -) -> (success: felt) { - return ERC20.increase_allowance(spender, added_value); -} - -@external -func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, subtracted_value: Uint256 -) -> (success: felt) { - return ERC20.decrease_allowance(spender, subtracted_value); -} - -@external -func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, amount: Uint256 -) { - Ownable.assert_only_owner(); - ERC20._mint(to, amount); - return (); -} - -@external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - newOwner: felt -) { - Ownable.transfer_ownership(newOwner); - return (); -} - -@external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); -} diff --git a/src/openzeppelin/token/erc20/presets/ERC20Pausable.cairo b/src/openzeppelin/token/erc20/presets/ERC20Pausable.cairo deleted file mode 100644 index 7519902fe..000000000 --- a/src/openzeppelin/token/erc20/presets/ERC20Pausable.cairo +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc20/presets/ERC20Pausable.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.access.ownable.library import Ownable -from openzeppelin.security.pausable.library import Pausable -from openzeppelin.token.erc20.library import ERC20 - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, decimals: felt, initial_supply: Uint256, recipient: felt, owner: felt -) { - ERC20.initializer(name, symbol, decimals); - ERC20._mint(recipient, initial_supply); - Ownable.initializer(owner); - return (); -} - -// -// Getters -// - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC20.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC20.symbol(); -} - -@view -func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - totalSupply: Uint256 -) { - let (totalSupply: Uint256) = ERC20.total_supply(); - return (totalSupply=totalSupply); -} - -@view -func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - decimals: felt -) { - return ERC20.decimals(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(account: felt) -> ( - balance: Uint256 -) { - return ERC20.balance_of(account); -} - -@view -func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, spender: felt -) -> (remaining: Uint256) { - return ERC20.allowance(owner, spender); -} - -@view -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - -@view -func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) { - return Pausable.is_paused(); -} - -// -// Externals -// - -@external -func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 -) -> (success: felt) { - Pausable.assert_not_paused(); - return ERC20.transfer(recipient, amount); -} - -@external -func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - sender: felt, recipient: felt, amount: Uint256 -) -> (success: felt) { - Pausable.assert_not_paused(); - return ERC20.transfer_from(sender, recipient, amount); -} - -@external -func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, amount: Uint256 -) -> (success: felt) { - Pausable.assert_not_paused(); - return ERC20.approve(spender, amount); -} - -@external -func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, added_value: Uint256 -) -> (success: felt) { - Pausable.assert_not_paused(); - return ERC20.increase_allowance(spender, added_value); -} - -@external -func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, subtracted_value: Uint256 -) -> (success: felt) { - Pausable.assert_not_paused(); - return ERC20.decrease_allowance(spender, subtracted_value); -} - -@external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - newOwner: felt -) { - Ownable.transfer_ownership(newOwner); - return (); -} - -@external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); -} - -@external -func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.assert_only_owner(); - Pausable._pause(); - return (); -} - -@external -func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.assert_only_owner(); - Pausable._unpause(); - return (); -} diff --git a/src/openzeppelin/token/erc20/presets/ERC20Upgradeable.cairo b/src/openzeppelin/token/erc20/presets/ERC20Upgradeable.cairo deleted file mode 100644 index 3244ba0a5..000000000 --- a/src/openzeppelin/token/erc20/presets/ERC20Upgradeable.cairo +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc20/presets/ERC20Upgradeable.cairo) - -%lang starknet -%builtins pedersen range_check - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.token.erc20.library import ERC20 -from openzeppelin.upgrades.library import Proxy - -// -// Initializer -// - -@external -func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, - symbol: felt, - decimals: felt, - initial_supply: Uint256, - recipient: felt, - proxy_admin: felt, -) { - ERC20.initializer(name, symbol, decimals); - ERC20._mint(recipient, initial_supply); - Proxy.initializer(proxy_admin); - return (); -} - -@external -func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_implementation: felt -) { - Proxy.assert_only_admin(); - Proxy._set_implementation_hash(new_implementation); - return (); -} - -// -// Getters -// - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC20.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC20.symbol(); -} - -@view -func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - totalSupply: Uint256 -) { - let (totalSupply: Uint256) = ERC20.total_supply(); - return (totalSupply=totalSupply); -} - -@view -func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - decimals: felt -) { - return ERC20.decimals(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(account: felt) -> ( - balance: Uint256 -) { - return ERC20.balance_of(account); -} - -@view -func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, spender: felt -) -> (remaining: Uint256) { - return ERC20.allowance(owner, spender); -} - -// -// Externals -// - -@external -func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.transfer(recipient, amount); -} - -@external -func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - sender: felt, recipient: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.transfer_from(sender, recipient, amount); -} - -@external -func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, amount: Uint256 -) -> (success: felt) { - return ERC20.approve(spender, amount); -} - -@external -func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, added_value: Uint256 -) -> (success: felt) { - return ERC20.increase_allowance(spender, added_value); -} - -@external -func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, subtracted_value: Uint256 -) -> (success: felt) { - return ERC20.decrease_allowance(spender, subtracted_value); -} diff --git a/src/openzeppelin/token/erc20/presets/cairo_project.toml b/src/openzeppelin/token/erc20/presets/cairo_project.toml new file mode 100644 index 000000000..2f96b70fe --- /dev/null +++ b/src/openzeppelin/token/erc20/presets/cairo_project.toml @@ -0,0 +1,2 @@ +[crate_roots] +presets = "." diff --git a/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo b/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo new file mode 100644 index 000000000..cd73016a3 --- /dev/null +++ b/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo @@ -0,0 +1,85 @@ +#[contract] +mod ERC20Burnable { + use erc20::ERC20Library; + use starknet::get_caller_address; + + // TMP starknet testing isn't fully functional. + // Use to ensure paths are correctly set. + #[external] + fn mock_constructor(name: felt, symbol: felt) { + ERC20Library::mock_initializer(name, symbol); + } + + #[constructor] + fn constructor(name: felt, symbol: felt, initial_supply: u256, recipient: ContractAddress) { + ERC20Library::initializer(name, symbol, initial_supply, recipient); + } + + #[view] + fn name() -> felt { + ERC20Library::name() + } + + #[view] + fn symbol() -> felt { + ERC20Library::symbol() + } + + #[view] + fn decimals() -> u8 { + ERC20Library::decimals() + } + + #[view] + fn totalSupply() -> u256 { + ERC20Library::total_supply() + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + ERC20Library::balance_of(account) + } + + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + ERC20Library::allowance(owner, spender) + } + + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + ERC20Library::transfer(recipient, amount) + } + + #[external] + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20Library::transfer_from(sender, recipient, amount) + } + + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool { + ERC20Library::approve(spender, amount) + } + + #[external] + fn increaseAllowance(spender: ContractAddress, added_value: u256) -> bool { + ERC20Library::increase_allowance(spender, added_value) + } + + #[external] + fn decreaseAllowance(spender: ContractAddress, subtracted_value: u256) -> bool { + ERC20Library::decrease_allowance(spender, subtracted_value) + } + + #[external] + fn burn(amount: u256) { + let caller = get_caller_address(); + ERC20Library::_burn(caller, amount); + } + + #[external] + fn burnFrom(account: ContractAddress, amount: u256) { + let caller = get_caller_address(); + ERC20Library::_spend_allowance(account, caller, amount); + ERC20Library::_burn(account, amount); + } +} diff --git a/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo b/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo new file mode 100644 index 000000000..0e176db91 --- /dev/null +++ b/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo @@ -0,0 +1,76 @@ +#[contract] +mod ERC20Mintable { + use erc20::ERC20Library; + + // TMP starknet testing isn't fully functional. + // Use to ensure paths are correctly set. + #[external] + fn mock_constructor(name: felt, symbol: felt) { + ERC20Library::mock_initializer(name, symbol); + } + + #[constructor] + fn constructor(name: felt, symbol: felt, initial_supply: u256, recipient: ContractAddress) { + ERC20Library::initializer(name, symbol, initial_supply, recipient); + } + + #[view] + fn name() -> felt { + ERC20Library::name() + } + + #[view] + fn symbol() -> felt { + ERC20Library::symbol() + } + + #[view] + fn decimals() -> u8 { + ERC20Library::decimals() + } + + #[view] + fn totalSupply() -> u256 { + ERC20Library::total_supply() + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + ERC20Library::balance_of(account) + } + + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + ERC20Library::allowance(owner, spender) + } + + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + ERC20Library::transfer(recipient, amount) + } + + #[external] + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20Library::transfer_from(sender, recipient, amount) + } + + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool { + ERC20Library::approve(spender, amount) + } + + #[external] + fn increaseAllowance(spender: ContractAddress, added_value: u256) -> bool { + ERC20Library::increase_allowance(spender, added_value) + } + + #[external] + fn decreaseAllowance(spender: ContractAddress, subtracted_value: u256) -> bool { + ERC20Library::decrease_allowance(spender, subtracted_value) + } + + #[external] + fn mint(recipient: ContractAddress, amount: u256) { + ERC20Library::_mint(recipient, amount); + } +} diff --git a/src/openzeppelin/token/erc20/presets/lib.cairo b/src/openzeppelin/token/erc20/presets/lib.cairo new file mode 100644 index 000000000..31d88e007 --- /dev/null +++ b/src/openzeppelin/token/erc20/presets/lib.cairo @@ -0,0 +1,8 @@ +mod erc20; +use erc20::ERC20; + +mod erc20_mintable; +use erc20_mintable::ERC20Mintable; + +mod erc20_burnable; +use erc20_burnable::ERC20Burnable; From 2fa00ddd16d3bcbe4413e32f7338fffd33c5ee10 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 10:02:31 -0500 Subject: [PATCH 008/124] add base lib --- src/openzeppelin/token/erc20/erc20.cairo | 128 +++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/openzeppelin/token/erc20/erc20.cairo diff --git a/src/openzeppelin/token/erc20/erc20.cairo b/src/openzeppelin/token/erc20/erc20.cairo new file mode 100644 index 000000000..e642211a5 --- /dev/null +++ b/src/openzeppelin/token/erc20/erc20.cairo @@ -0,0 +1,128 @@ +#[contract] +mod ERC20Library { + use starknet::get_caller_address; + use starknet::contract_address_const; + use starknet::ContractAddressZeroable; + use zeroable::Zeroable; + + struct Storage { + _name: felt, + _symbol: felt, + _total_supply: u256, + _balances: LegacyMap::, + _allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>, + } + + #[event] + fn Transfer(from: ContractAddress, to: ContractAddress, value: u256) {} + + #[event] + fn Approval(owner: ContractAddress, spender: ContractAddress, value: u256) {} + + // TMP starknet testing isn't fully functional. + // Use to ensure paths are correctly set. + fn mock_initializer(name_: felt, symbol_: felt) { + _name::write(name_); + _symbol::write(symbol_); + } + + fn initializer(name_: felt, symbol_: felt, initial_supply: u256, recipient: ContractAddress) { + _name::write(name_); + _symbol::write(symbol_); + _mint(recipient, initial_supply); + } + + fn name() -> felt { + _name::read() + } + + fn symbol() -> felt { + _symbol::read() + } + + fn decimals() -> u8 { + 18_u8 + } + + fn total_supply() -> u256 { + _total_supply::read() + } + + fn balance_of(account: ContractAddress) -> u256 { + _balances::read(account) + } + + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + _allowances::read((owner, spender)) + } + + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + let sender = get_caller_address(); + _transfer(sender, recipient, amount); + true + } + + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + let caller = get_caller_address(); + _spend_allowance(sender, caller, amount); + _transfer(sender, recipient, amount); + true + } + + fn approve(spender: ContractAddress, amount: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, amount); + true + } + + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, _allowances::read((caller, spender)) + added_value); + true + } + + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, _allowances::read((caller, spender)) - subtracted_value); + true + } + + fn _mint(recipient: ContractAddress, amount: u256) { + assert(!recipient.is_zero(), 'ERC20: mint to 0'); + _total_supply::write(_total_supply::read() + amount); + _balances::write(recipient, _balances::read(recipient) + amount); + Transfer(contract_address_const::<0>(), recipient, amount); + } + + fn _burn(account: ContractAddress, amount: u256) { + assert(!account.is_zero(), 'ERC20: burn from 0'); + _total_supply::write(_total_supply::read() - amount); + _balances::write(account, _balances::read(account) - amount); + Transfer(account, contract_address_const::<0>(), amount); + } + + fn _approve(owner: ContractAddress, spender: ContractAddress, amount: u256) { + assert(!owner.is_zero(), 'ERC20: approve from 0'); + assert(!spender.is_zero(), 'ERC20: approve to 0'); + _allowances::write((owner, spender), amount); + Approval(owner, spender, amount); + } + + fn _transfer(sender: ContractAddress, recipient: ContractAddress, amount: u256) { + assert(!sender.is_zero(), 'ERC20: transfer from 0'); + assert(!recipient.is_zero(), 'ERC20: transfer to 0'); + _balances::write(sender, _balances::read(sender) - amount); + _balances::write(recipient, _balances::read(recipient) + amount); + Transfer(sender, recipient, amount); + } + + fn _spend_allowance(owner: ContractAddress, spender: ContractAddress, amount: u256) { + let current_allowance = _allowances::read((owner, spender)); + let ONES_MASK = 0xffffffffffffffffffffffffffffffff_u128; + let is_unlimited_allowance = + current_allowance.low == ONES_MASK & current_allowance.high == ONES_MASK; + if !is_unlimited_allowance { + _approve(owner, spender, current_allowance - amount); + } + } +} From f0036e7da1a03f0a3a80811447e72cb5b84ffcda Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 10:03:01 -0500 Subject: [PATCH 009/124] add tests --- src/openzeppelin/token/erc20/tests.cairo | 4 + .../token/erc20/tests/test_erc20.cairo | 18 ++ .../erc20/tests/test_erc20_burnable.cairo | 18 ++ .../erc20/tests/test_erc20_library.cairo | 189 ++++++++++++++++++ .../erc20/tests/test_erc20_mintable.cairo | 18 ++ 5 files changed, 247 insertions(+) create mode 100644 src/openzeppelin/token/erc20/tests.cairo create mode 100644 src/openzeppelin/token/erc20/tests/test_erc20.cairo create mode 100644 src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo create mode 100644 src/openzeppelin/token/erc20/tests/test_erc20_library.cairo create mode 100644 src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo diff --git a/src/openzeppelin/token/erc20/tests.cairo b/src/openzeppelin/token/erc20/tests.cairo new file mode 100644 index 000000000..13e522153 --- /dev/null +++ b/src/openzeppelin/token/erc20/tests.cairo @@ -0,0 +1,4 @@ +mod test_erc20_library; +mod test_erc20; +mod test_erc20_mintable; +mod test_erc20_burnable; diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo new file mode 100644 index 000000000..330f08c83 --- /dev/null +++ b/src/openzeppelin/token/erc20/tests/test_erc20.cairo @@ -0,0 +1,18 @@ +use presets::ERC20; +use starknet::contract_address_const; +use integer::u256_from_felt; + +const NAME: felt = 111; +const SYMBOL: felt = 222; + +#[test] +#[available_gas(2000000)] +fn initialize() { + let decimals: u8 = 18_u8; + + ERC20::mock_constructor(NAME, SYMBOL); + + assert(ERC20::name() == NAME, 'Name should be NAME'); + assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20::decimals() == decimals, 'Decimals should be 18'); +} diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo new file mode 100644 index 000000000..0b64408ad --- /dev/null +++ b/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo @@ -0,0 +1,18 @@ +use presets::ERC20Burnable; +use starknet::contract_address_const; +use integer::u256_from_felt; + +const NAME: felt = 111; +const SYMBOL: felt = 222; + +#[test] +#[available_gas(2000000)] +fn initialize() { + let decimals: u8 = 18_u8; + + ERC20Burnable::mock_constructor(NAME, SYMBOL); + + assert(ERC20Burnable::name() == NAME, 'Name should be NAME'); + assert(ERC20Burnable::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20Burnable::decimals() == decimals, 'Decimals should be 18'); +} diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo new file mode 100644 index 000000000..d0f67ecc8 --- /dev/null +++ b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo @@ -0,0 +1,189 @@ +/// Tests only the internal functions of the erc20 library because +/// `get_caller_address` is not yet functional with accounts. +/// +/// Events are not yet recognized in starknet tests. +/// Some of these tests will panic with 'Unknown selector for system call!' +/// Comment out events in erc20/erc20.cairo to omit panicking. + +use erc20::ERC20Library; +use starknet::contract_address_const; +use integer::u256_from_felt; + +const NAME: felt = 111; +const SYMBOL: felt = 222; + +fn setup() -> (ContractAddress, u256) { + let account: ContractAddress = contract_address_const::<1>(); + let initial_supply: u256 = u256_from_felt(2000); + + ERC20Library::mock_initializer(NAME, SYMBOL); + ERC20Library::_total_supply::write(initial_supply); + ERC20Library::_balances::write(account, initial_supply); + (account, initial_supply) +} + +#[test] +#[available_gas(2000000)] +fn initialize() { + let decimals: u8 = 18_u8; + + ERC20Library::mock_initializer(NAME, SYMBOL); + + assert(ERC20Library::name() == NAME, 'Name should be NAME'); + assert(ERC20Library::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20Library::decimals() == decimals, 'Decimals should be 18'); +} + +#[test] +#[available_gas(2000000)] +fn test__approve() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::_approve(owner, spender, amount); + assert(ERC20Library::allowance(owner, spender) == amount, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__approve_from_zero() { + let owner: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<1>(); + let amount: u256 = u256_from_felt(100); + ERC20Library::_approve(owner, spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__approve_to_zero() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + ERC20Library::_approve(owner, spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__transfer() { + let (account, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + ERC20Library::_transfer(account, recipient, amount); + + assert(ERC20Library::balance_of(recipient) == amount, 'Balance should eq amount'); + assert(ERC20Library::balance_of(account) == supply - amount, 'Should eq supply - amount'); + assert(ERC20Library::total_supply() == supply, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__transfer_not_enough_balance() { + let (account, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = supply + u256_from_felt(1); + ERC20Library::_transfer(account, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__transfer_from_zero() { + let owner: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<1>(); + let amount: u256 = u256_from_felt(100); + ERC20Library::_transfer(owner, spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__transfer_to_zero() { + let (account, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + ERC20Library::_transfer(account, spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__spend_allowance_not_unlimited() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::_approve(owner, spender, supply); + ERC20Library::_spend_allowance(owner, spender, amount); + assert(ERC20Library::allowance(owner, spender) == supply - amount, 'Should eq supply - amount'); +} + +#[test] +#[available_gas(2000000)] +fn test__spend_allowance_unlimited() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + + let max_u256: u256 = u256_from_felt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) * u256_from_felt(256) + u256_from_felt(255); + let max_minus_one: u256 = max_u256 - u256_from_felt(1); + + ERC20Library::_approve(owner, spender, max_u256); + ERC20Library::_spend_allowance(owner, spender, max_minus_one); + + assert(ERC20Library::allowance(owner, spender) == max_u256, 'Allowance should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test__mint() { + let minter: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::_mint(minter, amount); + + assert(ERC20Library::total_supply() == amount, 'Should eq total supply'); + // assert(ERC20Library::balance_of(minter) == amount, 'Should eq amount'); + // Causes 'Error: Failed setting up runner' +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__mint_to_zero() { + let minter: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::_mint(minter, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__burn() { + let (owner, supply) = setup(); + + let amount: u256 = u256_from_felt(100); + ERC20Library::_burn(owner, amount); + + assert(ERC20Library::total_supply() == supply - amount, 'Should eq supply - amount'); + assert(ERC20Library::balance_of(owner) == supply - amount, 'Should eq supply - amount'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__burn_from_zero() { + setup(); + let zero_address: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::_burn(zero_address, amount); +} diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo new file mode 100644 index 000000000..2c2a07e2e --- /dev/null +++ b/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo @@ -0,0 +1,18 @@ +use presets::ERC20Mintable; +use starknet::contract_address_const; +use integer::u256_from_felt; + +const NAME: felt = 111; +const SYMBOL: felt = 222; + +#[test] +#[available_gas(2000000)] +fn initialize() { + let decimals: u8 = 18_u8; + + ERC20Mintable::mock_constructor(NAME, SYMBOL); + + assert(ERC20Mintable::name() == NAME, 'Name should be NAME'); + assert(ERC20Mintable::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20Mintable::decimals() == decimals, 'Decimals should be 18'); +} From 8d781a859aaa9d7fcd3aa4d20ca1116c753991ff Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 10:03:32 -0500 Subject: [PATCH 010/124] remove old cairo lib and interface --- src/openzeppelin/token/erc20/IERC20.cairo | 36 --- src/openzeppelin/token/erc20/library.cairo | 306 --------------------- 2 files changed, 342 deletions(-) delete mode 100644 src/openzeppelin/token/erc20/IERC20.cairo delete mode 100644 src/openzeppelin/token/erc20/library.cairo diff --git a/src/openzeppelin/token/erc20/IERC20.cairo b/src/openzeppelin/token/erc20/IERC20.cairo deleted file mode 100644 index 3c8cf7018..000000000 --- a/src/openzeppelin/token/erc20/IERC20.cairo +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc20/IERC20.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 - -@contract_interface -namespace IERC20 { - func name() -> (name: felt) { - } - - func symbol() -> (symbol: felt) { - } - - func decimals() -> (decimals: felt) { - } - - func totalSupply() -> (totalSupply: Uint256) { - } - - func balanceOf(account: felt) -> (balance: Uint256) { - } - - func allowance(owner: felt, spender: felt) -> (remaining: Uint256) { - } - - func transfer(recipient: felt, amount: Uint256) -> (success: felt) { - } - - func transferFrom(sender: felt, recipient: felt, amount: Uint256) -> (success: felt) { - } - - func approve(spender: felt, amount: Uint256) -> (success: felt) { - } -} diff --git a/src/openzeppelin/token/erc20/library.cairo b/src/openzeppelin/token/erc20/library.cairo deleted file mode 100644 index 3b89cd7fd..000000000 --- a/src/openzeppelin/token/erc20/library.cairo +++ /dev/null @@ -1,306 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc20/library.cairo) - -%lang starknet - -from starkware.starknet.common.syscalls import get_caller_address -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.math import assert_not_zero, assert_le -from starkware.cairo.common.bool import TRUE, FALSE -from starkware.cairo.common.uint256 import Uint256, uint256_check, uint256_eq, uint256_not - -from openzeppelin.security.safemath.library import SafeUint256 -from openzeppelin.utils.constants.library import UINT8_MAX - -// -// Events -// - -@event -func Transfer(from_: felt, to: felt, value: Uint256) { -} - -@event -func Approval(owner: felt, spender: felt, value: Uint256) { -} - -// -// Storage -// - -@storage_var -func ERC20_name() -> (name: felt) { -} - -@storage_var -func ERC20_symbol() -> (symbol: felt) { -} - -@storage_var -func ERC20_decimals() -> (decimals: felt) { -} - -@storage_var -func ERC20_total_supply() -> (total_supply: Uint256) { -} - -@storage_var -func ERC20_balances(account: felt) -> (balance: Uint256) { -} - -@storage_var -func ERC20_allowances(owner: felt, spender: felt) -> (remaining: Uint256) { -} - -namespace ERC20 { - // - // Initializer - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, decimals: felt - ) { - ERC20_name.write(name); - ERC20_symbol.write(symbol); - with_attr error_message("ERC20: decimals exceed 2^8") { - assert_le(decimals, UINT8_MAX); - } - ERC20_decimals.write(decimals); - return (); - } - - // - // Public functions - // - - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC20_name.read(); - } - - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - symbol: felt - ) { - return ERC20_symbol.read(); - } - - func total_supply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - total_supply: Uint256 - ) { - return ERC20_total_supply.read(); - } - - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - decimals: felt - ) { - return ERC20_decimals.read(); - } - - func balance_of{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - account: felt - ) -> (balance: Uint256) { - return ERC20_balances.read(account); - } - - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, spender: felt - ) -> (remaining: Uint256) { - return ERC20_allowances.read(owner, spender); - } - - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 - ) -> (success: felt) { - let (sender) = get_caller_address(); - _transfer(sender, recipient, amount); - return (success=TRUE); - } - - func transfer_from{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - sender: felt, recipient: felt, amount: Uint256 - ) -> (success: felt) { - let (caller) = get_caller_address(); - _spend_allowance(sender, caller, amount); - _transfer(sender, recipient, amount); - return (success=TRUE); - } - - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, amount: Uint256 - ) -> (success: felt) { - with_attr error_message("ERC20: amount is not a valid Uint256") { - uint256_check(amount); - } - - let (caller) = get_caller_address(); - _approve(caller, spender, amount); - return (success=TRUE); - } - - func increase_allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, added_value: Uint256 - ) -> (success: felt) { - with_attr error("ERC20: added_value is not a valid Uint256") { - uint256_check(added_value); - } - - let (caller) = get_caller_address(); - let (current_allowance: Uint256) = ERC20_allowances.read(caller, spender); - - // add allowance - with_attr error_message("ERC20: allowance overflow") { - let (new_allowance: Uint256) = SafeUint256.add(current_allowance, added_value); - } - - _approve(caller, spender, new_allowance); - return (success=TRUE); - } - - func decrease_allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, subtracted_value: Uint256 - ) -> (success: felt) { - alloc_locals; - with_attr error_message("ERC20: subtracted_value is not a valid Uint256") { - uint256_check(subtracted_value); - } - - let (caller) = get_caller_address(); - let (current_allowance: Uint256) = ERC20_allowances.read(owner=caller, spender=spender); - - with_attr error_message("ERC20: allowance below zero") { - let (new_allowance: Uint256) = SafeUint256.sub_le(current_allowance, subtracted_value); - } - - _approve(caller, spender, new_allowance); - return (success=TRUE); - } - - // - // Internal - // - - func _mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 - ) { - with_attr error_message("ERC20: amount is not a valid Uint256") { - uint256_check(amount); - } - - with_attr error_message("ERC20: cannot mint to the zero address") { - assert_not_zero(recipient); - } - - let (supply: Uint256) = ERC20_total_supply.read(); - with_attr error_message("ERC20: mint overflow") { - let (new_supply: Uint256) = SafeUint256.add(supply, amount); - } - ERC20_total_supply.write(new_supply); - - let (balance: Uint256) = ERC20_balances.read(account=recipient); - // overflow is not possible because sum is guaranteed to be less than total supply - // which we check for overflow below - let (new_balance: Uint256) = SafeUint256.add(balance, amount); - ERC20_balances.write(recipient, new_balance); - - Transfer.emit(0, recipient, amount); - return (); - } - - func _burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - account: felt, amount: Uint256 - ) { - with_attr error_message("ERC20: amount is not a valid Uint256") { - uint256_check(amount); - } - - with_attr error_message("ERC20: cannot burn from the zero address") { - assert_not_zero(account); - } - - let (balance: Uint256) = ERC20_balances.read(account); - with_attr error_message("ERC20: burn amount exceeds balance") { - let (new_balance: Uint256) = SafeUint256.sub_le(balance, amount); - } - - ERC20_balances.write(account, new_balance); - - let (supply: Uint256) = ERC20_total_supply.read(); - let (new_supply: Uint256) = SafeUint256.sub_le(supply, amount); - ERC20_total_supply.write(new_supply); - Transfer.emit(account, 0, amount); - return (); - } - - func _transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - sender: felt, recipient: felt, amount: Uint256 - ) { - with_attr error_message("ERC20: amount is not a valid Uint256") { - uint256_check(amount); // almost surely not needed, might remove after confirmation - } - - with_attr error_message("ERC20: cannot transfer from the zero address") { - assert_not_zero(sender); - } - - with_attr error_message("ERC20: cannot transfer to the zero address") { - assert_not_zero(recipient); - } - - let (sender_balance: Uint256) = ERC20_balances.read(account=sender); - with_attr error_message("ERC20: transfer amount exceeds balance") { - let (new_sender_balance: Uint256) = SafeUint256.sub_le(sender_balance, amount); - } - - ERC20_balances.write(sender, new_sender_balance); - - // add to recipient - let (recipient_balance: Uint256) = ERC20_balances.read(account=recipient); - // overflow is not possible because sum is guaranteed by mint to be less than total supply - let (new_recipient_balance: Uint256) = SafeUint256.add(recipient_balance, amount); - ERC20_balances.write(recipient, new_recipient_balance); - Transfer.emit(sender, recipient, amount); - return (); - } - - func _approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, spender: felt, amount: Uint256 - ) { - with_attr error_message("ERC20: amount is not a valid Uint256") { - uint256_check(amount); - } - - with_attr error_message("ERC20: cannot approve from the zero address") { - assert_not_zero(owner); - } - - with_attr error_message("ERC20: cannot approve to the zero address") { - assert_not_zero(spender); - } - - ERC20_allowances.write(owner, spender, amount); - Approval.emit(owner, spender, amount); - return (); - } - - func _spend_allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, spender: felt, amount: Uint256 - ) { - alloc_locals; - with_attr error_message("ERC20: amount is not a valid Uint256") { - uint256_check(amount); // almost surely not needed, might remove after confirmation - } - - let (current_allowance: Uint256) = ERC20_allowances.read(owner, spender); - let (infinite: Uint256) = uint256_not(Uint256(0, 0)); - let (is_infinite: felt) = uint256_eq(current_allowance, infinite); - - if (is_infinite == FALSE) { - with_attr error_message("ERC20: insufficient allowance") { - let (new_allowance: Uint256) = SafeUint256.sub_le(current_allowance, amount); - } - - _approve(owner, spender, new_allowance); - return (); - } - return (); - } -} From ae37b1cece52edeb96798da3006eacb17df8bd92 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 11:34:07 -0500 Subject: [PATCH 011/124] remove unused import --- src/openzeppelin/token/erc20/tests/test_erc20.cairo | 1 - src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo | 1 - src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo | 1 - 3 files changed, 3 deletions(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo index 330f08c83..b1458e457 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20.cairo @@ -1,6 +1,5 @@ use presets::ERC20; use starknet::contract_address_const; -use integer::u256_from_felt; const NAME: felt = 111; const SYMBOL: felt = 222; diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo index 0b64408ad..88dcbc24f 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo @@ -1,6 +1,5 @@ use presets::ERC20Burnable; use starknet::contract_address_const; -use integer::u256_from_felt; const NAME: felt = 111; const SYMBOL: felt = 222; diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo index 2c2a07e2e..82db86044 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo @@ -1,6 +1,5 @@ use presets::ERC20Mintable; use starknet::contract_address_const; -use integer::u256_from_felt; const NAME: felt = 111; const SYMBOL: felt = 222; From da57a91561fd6b728a2fd45a4b7e6638f44e4217 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 11:34:34 -0500 Subject: [PATCH 012/124] fix vars --- .../erc20/tests/test_erc20_library.cairo | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo index d0f67ecc8..857f5d7d0 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo @@ -70,14 +70,14 @@ fn test__approve_to_zero() { #[test] #[available_gas(2000000)] fn test__transfer() { - let (account, supply) = setup(); + let (sender, supply) = setup(); let recipient: ContractAddress = contract_address_const::<2>(); let amount: u256 = u256_from_felt(100); - ERC20Library::_transfer(account, recipient, amount); + ERC20Library::_transfer(sender, recipient, amount); assert(ERC20Library::balance_of(recipient) == amount, 'Balance should eq amount'); - assert(ERC20Library::balance_of(account) == supply - amount, 'Should eq supply - amount'); + assert(ERC20Library::balance_of(sender) == supply - amount, 'Should eq supply - amount'); assert(ERC20Library::total_supply() == supply, 'Total supply should not change'); } @@ -85,32 +85,32 @@ fn test__transfer() { #[available_gas(2000000)] #[should_panic] fn test__transfer_not_enough_balance() { - let (account, supply) = setup(); + let (sender, supply) = setup(); let recipient: ContractAddress = contract_address_const::<2>(); let amount: u256 = supply + u256_from_felt(1); - ERC20Library::_transfer(account, recipient, amount); + ERC20Library::_transfer(sender, recipient, amount); } #[test] #[available_gas(2000000)] #[should_panic] fn test__transfer_from_zero() { - let owner: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<1>(); + let sender: ContractAddress = contract_address_const::<0>(); + let recipient: ContractAddress = contract_address_const::<1>(); let amount: u256 = u256_from_felt(100); - ERC20Library::_transfer(owner, spender, amount); + ERC20Library::_transfer(sender, recipient, amount); } #[test] #[available_gas(2000000)] #[should_panic] fn test__transfer_to_zero() { - let (account, supply) = setup(); + let (sender, supply) = setup(); - let spender: ContractAddress = contract_address_const::<0>(); + let recipient: ContractAddress = contract_address_const::<0>(); let amount: u256 = u256_from_felt(100); - ERC20Library::_transfer(account, spender, amount); + ERC20Library::_transfer(sender, recipient, amount); } #[test] From fd42fddf984a0bf22667c6dc94fc2c80f21f8dc1 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 11:45:47 -0500 Subject: [PATCH 013/124] change external funcs to snake case --- src/openzeppelin/token/erc20/presets/ERC20.cairo | 10 +++++----- .../token/erc20/presets/erc20_burnable.cairo | 12 ++++++------ .../token/erc20/presets/erc20_mintable.cairo | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/openzeppelin/token/erc20/presets/ERC20.cairo b/src/openzeppelin/token/erc20/presets/ERC20.cairo index d2273854e..6d6ee2eac 100644 --- a/src/openzeppelin/token/erc20/presets/ERC20.cairo +++ b/src/openzeppelin/token/erc20/presets/ERC20.cairo @@ -30,12 +30,12 @@ mod ERC20 { } #[view] - fn totalSupply() -> u256 { + fn total_supply() -> u256 { ERC20Library::total_supply() } #[view] - fn balanceOf(account: ContractAddress) -> u256 { + fn balance_of(account: ContractAddress) -> u256 { ERC20Library::balance_of(account) } @@ -50,7 +50,7 @@ mod ERC20 { } #[external] - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { ERC20Library::transfer_from(sender, recipient, amount) } @@ -60,12 +60,12 @@ mod ERC20 { } #[external] - fn increaseAllowance(spender: ContractAddress, added_value: u256) -> bool { + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { ERC20Library::increase_allowance(spender, added_value) } #[external] - fn decreaseAllowance(spender: ContractAddress, subtracted_value: u256) -> bool { + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { ERC20Library::decrease_allowance(spender, subtracted_value) } } diff --git a/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo b/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo index cd73016a3..644dcdd6f 100644 --- a/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo +++ b/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo @@ -31,12 +31,12 @@ mod ERC20Burnable { } #[view] - fn totalSupply() -> u256 { + fn total_supply() -> u256 { ERC20Library::total_supply() } #[view] - fn balanceOf(account: ContractAddress) -> u256 { + fn balance_of(account: ContractAddress) -> u256 { ERC20Library::balance_of(account) } @@ -51,7 +51,7 @@ mod ERC20Burnable { } #[external] - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { ERC20Library::transfer_from(sender, recipient, amount) } @@ -61,12 +61,12 @@ mod ERC20Burnable { } #[external] - fn increaseAllowance(spender: ContractAddress, added_value: u256) -> bool { + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { ERC20Library::increase_allowance(spender, added_value) } #[external] - fn decreaseAllowance(spender: ContractAddress, subtracted_value: u256) -> bool { + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { ERC20Library::decrease_allowance(spender, subtracted_value) } @@ -77,7 +77,7 @@ mod ERC20Burnable { } #[external] - fn burnFrom(account: ContractAddress, amount: u256) { + fn burn_from(account: ContractAddress, amount: u256) { let caller = get_caller_address(); ERC20Library::_spend_allowance(account, caller, amount); ERC20Library::_burn(account, amount); diff --git a/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo b/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo index 0e176db91..d25661a88 100644 --- a/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo +++ b/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo @@ -30,12 +30,12 @@ mod ERC20Mintable { } #[view] - fn totalSupply() -> u256 { + fn total_supply() -> u256 { ERC20Library::total_supply() } #[view] - fn balanceOf(account: ContractAddress) -> u256 { + fn balance_of(account: ContractAddress) -> u256 { ERC20Library::balance_of(account) } @@ -50,7 +50,7 @@ mod ERC20Mintable { } #[external] - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { ERC20Library::transfer_from(sender, recipient, amount) } @@ -60,12 +60,12 @@ mod ERC20Mintable { } #[external] - fn increaseAllowance(spender: ContractAddress, added_value: u256) -> bool { + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { ERC20Library::increase_allowance(spender, added_value) } #[external] - fn decreaseAllowance(spender: ContractAddress, subtracted_value: u256) -> bool { + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { ERC20Library::decrease_allowance(spender, subtracted_value) } From 1cb12529f284c8d27ec92a3294419a2d79b83e65 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Feb 2023 11:48:30 -0500 Subject: [PATCH 014/124] remove unused import --- src/openzeppelin/token/erc20/tests/test_erc20.cairo | 1 - src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo | 1 - src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo | 1 - 3 files changed, 3 deletions(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo index b1458e457..7d5b903d5 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20.cairo @@ -1,5 +1,4 @@ use presets::ERC20; -use starknet::contract_address_const; const NAME: felt = 111; const SYMBOL: felt = 222; diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo index 88dcbc24f..53e2a53ee 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo @@ -1,5 +1,4 @@ use presets::ERC20Burnable; -use starknet::contract_address_const; const NAME: felt = 111; const SYMBOL: felt = 222; diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo index 82db86044..448bd82dd 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo @@ -1,5 +1,4 @@ use presets::ERC20Mintable; -use starknet::contract_address_const; const NAME: felt = 111; const SYMBOL: felt = 222; From f0330cdad40bfc4d304e30ffe18651f89eb936a2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 21 Feb 2023 01:02:52 -0500 Subject: [PATCH 015/124] update cairo --- Cargo.lock | 56 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- cairo | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 696ce9451..3dbb84efb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,7 +307,7 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-utils", "env_logger", @@ -323,7 +323,7 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "anyhow", "cairo-lang-defs", @@ -347,7 +347,7 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-proc-macros", "cairo-lang-utils", @@ -358,7 +358,7 @@ dependencies = [ [[package]] name = "cairo-lang-defs" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -379,7 +379,7 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-filesystem", "cairo-lang-proc-macros", @@ -394,7 +394,7 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-utils", "env_logger", @@ -408,7 +408,7 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -421,7 +421,7 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -444,7 +444,7 @@ dependencies = [ [[package]] name = "cairo-lang-language-server" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-compiler", "cairo-lang-debug", @@ -471,7 +471,7 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -499,7 +499,7 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -520,7 +520,7 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -543,7 +543,7 @@ dependencies = [ [[package]] name = "cairo-lang-proc-macros" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-debug", "quote", @@ -552,7 +552,7 @@ dependencies = [ [[package]] name = "cairo-lang-project" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-filesystem", "indoc", @@ -565,7 +565,7 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "anyhow", "ark-ff 0.4.0-alpha.7", @@ -593,7 +593,7 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "assert_matches", "cairo-lang-debug", @@ -623,7 +623,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "assert_matches", "bimap", @@ -651,7 +651,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -666,7 +666,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -683,7 +683,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -714,7 +714,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "assert_matches", "cairo-felt", @@ -738,7 +738,7 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -780,7 +780,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -794,7 +794,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-utils", "env_logger", @@ -806,7 +806,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-runner" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "anyhow", "cairo-felt", @@ -838,7 +838,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-utils" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "cairo-lang-utils", "env_logger", @@ -849,7 +849,7 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "chrono", "env_logger", @@ -2664,7 +2664,7 @@ dependencies = [ [[package]] name = "tests" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" dependencies = [ "assert_matches", "cairo-felt", diff --git a/Cargo.toml b/Cargo.toml index 1179081f2..4294fd6aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ members = [ ] [workspace.package] -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" edition = "2021" repository = "https://github.com/starkware-libs/cairo/" license = "Apache-2.0" diff --git a/cairo b/cairo index 7d27aee2c..d297e4721 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 7d27aee2c7832592f3d091d01c3ceb39e45484e1 +Subproject commit d297e472133680481068cba94d8758aa12117164 From abc737a09dcd103cd9db0aff1ff1b6a6133ce3cf Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 21 Feb 2023 01:04:14 -0500 Subject: [PATCH 016/124] add tests for externals --- .../erc20/tests/test_erc20_library.cairo | 265 +++++++++++++++++- 1 file changed, 251 insertions(+), 14 deletions(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo index 857f5d7d0..689e7d141 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo @@ -1,39 +1,80 @@ -/// Tests only the internal functions of the erc20 library because -/// `get_caller_address` is not yet functional with accounts. -/// -/// Events are not yet recognized in starknet tests. -/// Some of these tests will panic with 'Unknown selector for system call!' -/// Comment out events in erc20/erc20.cairo to omit panicking. - use erc20::ERC20Library; use starknet::contract_address_const; +use starknet_testing::set_caller_address; use integer::u256_from_felt; const NAME: felt = 111; const SYMBOL: felt = 222; fn setup() -> (ContractAddress, u256) { - let account: ContractAddress = contract_address_const::<1>(); let initial_supply: u256 = u256_from_felt(2000); + let account: ContractAddress = contract_address_const::<1>(); + // Set caller + starknet_testing::set_caller_address(account); - ERC20Library::mock_initializer(NAME, SYMBOL); - ERC20Library::_total_supply::write(initial_supply); - ERC20Library::_balances::write(account, initial_supply); + ERC20Library::initializer(NAME, SYMBOL, initial_supply, account); (account, initial_supply) } +fn set_caller_as_zero() { + starknet_testing::set_caller_address(contract_address_const::<0>()); +} + #[test] #[available_gas(2000000)] fn initialize() { + let initial_supply: u256 = u256_from_felt(2000); + let account: ContractAddress = contract_address_const::<1>(); let decimals: u8 = 18_u8; - ERC20Library::mock_initializer(NAME, SYMBOL); + ERC20Library::initializer(NAME, SYMBOL, initial_supply, account); + + let owner_balance: u256 = ERC20Library::balance_of(account); + assert(owner_balance == initial_supply, 'Should eq inital_supply'); + assert(ERC20Library::total_supply() == initial_supply, 'Should eq inital_supply'); assert(ERC20Library::name() == NAME, 'Name should be NAME'); assert(ERC20Library::symbol() == SYMBOL, 'Symbol should be SYMBOL'); assert(ERC20Library::decimals() == decimals, 'Decimals should be 18'); } +#[test] +#[available_gas(2000000)] +fn test_approve() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + let result: bool = ERC20Library::approve(spender, amount); + assert(result, ''); + assert(ERC20Library::allowance(owner, spender) == amount, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_approve_from_zero() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + set_caller_as_zero(); + + ERC20Library::approve(spender, amount); + assert(ERC20Library::allowance(owner, spender) == amount, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_approve_to_zero() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::approve(spender, amount); +} + #[test] #[available_gas(2000000)] fn test__approve() { @@ -67,6 +108,21 @@ fn test__approve_to_zero() { ERC20Library::_approve(owner, spender, amount); } +#[test] +#[available_gas(2000000)] +fn test_transfer() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + let success: bool = ERC20Library::transfer(recipient, amount); + + assert(success, ''); + assert(ERC20Library::balance_of(recipient) == amount, 'Balance should eq amount'); + assert(ERC20Library::balance_of(sender) == supply - amount, 'Should eq supply - amount'); + assert(ERC20Library::total_supply() == supply, 'Total supply should not change'); +} + #[test] #[available_gas(2000000)] fn test__transfer() { @@ -113,6 +169,186 @@ fn test__transfer_to_zero() { ERC20Library::_transfer(sender, recipient, amount); } +#[test] +#[available_gas(2000000)] +fn test_transfer_from() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::approve(spender, amount); + + starknet_testing::set_caller_address(spender); + + let success: bool = ERC20Library::transfer_from(owner, recipient, amount); + assert(success, 'Should return success'); + + // Will dangle without setting as a var + let spender_allowance: u256 = ERC20Library::allowance(owner, spender); + + assert(ERC20Library::balance_of(recipient) == amount, 'Should eq amount'); + assert(ERC20Library::balance_of(owner) == supply - amount, 'Should eq suppy - amount'); + assert(spender_allowance == u256_from_felt(0), 'Should eq 0'); + assert(ERC20Library::total_supply() == supply, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from_doesnt_consume_infinite_allowance() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + let max_u256: u256 = u256_from_felt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) * u256_from_felt(256) + u256_from_felt(255); + + ERC20Library::approve(spender, max_u256); + + starknet_testing::set_caller_address(spender); + + ERC20Library::transfer_from(owner, recipient, amount); + + let spender_allowance: u256 = ERC20Library::allowance(owner, spender); + assert(spender_allowance == max_u256, 'Should remain max_uint256'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_transfer_from_greater_than_allowance() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + let amount_plus_one: u256 = amount + u256_from_felt(1); + + ERC20Library::approve(spender, amount); + + starknet_testing::set_caller_address(spender); + + ERC20Library::transfer_from(owner, recipient, amount_plus_one); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_transfer_from_to_zero_address() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::approve(spender, amount); + + starknet_testing::set_caller_address(spender); + + ERC20Library::transfer_from(owner, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_transfer_from_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + + starknet_testing::set_caller_address(zero_address); + + ERC20Library::transfer_from(owner, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_increase_allowance() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::approve(spender, amount); + ERC20Library::increase_allowance(spender, amount); + + let spender_allowance: u256 = ERC20Library::allowance(owner, spender); + assert(spender_allowance == amount + amount, ''); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_increase_allowance_to_zero_address() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::increase_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_increase_allowance_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + starknet_testing::set_caller_address(zero_address); + + ERC20Library::increase_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_decrease_allowance() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::approve(spender, amount); + ERC20Library::decrease_allowance(spender, amount); + + let spender_allowance: u256 = ERC20Library::allowance(owner, spender); + assert(spender_allowance == amount - amount, ''); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_decrease_allowance_to_zero_address() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20Library::decrease_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_decrease_allowance_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + starknet_testing::set_caller_address(zero_address); + + ERC20Library::decrease_allowance(spender, amount); +} + #[test] #[available_gas(2000000)] fn test__spend_allowance_not_unlimited() { @@ -150,9 +386,10 @@ fn test__mint() { ERC20Library::_mint(minter, amount); + let minter_balance: u256 = ERC20Library::balance_of(minter); + assert(minter_balance == amount, 'Should eq amount'); + assert(ERC20Library::total_supply() == amount, 'Should eq total supply'); - // assert(ERC20Library::balance_of(minter) == amount, 'Should eq amount'); - // Causes 'Error: Failed setting up runner' } #[test] From 4ca2620dc023d83ec3f7fbd5612f92af6accb44e Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 21 Feb 2023 01:10:29 -0500 Subject: [PATCH 017/124] add bool assertions --- .../erc20/tests/test_erc20_library.cairo | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo index 689e7d141..519f73e17 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo @@ -45,8 +45,8 @@ fn test_approve() { let spender: ContractAddress = contract_address_const::<2>(); let amount: u256 = u256_from_felt(100); - let result: bool = ERC20Library::approve(spender, amount); - assert(result, ''); + let success: bool = ERC20Library::approve(spender, amount); + assert(success, 'Should return true'); assert(ERC20Library::allowance(owner, spender) == amount, 'Spender not approved correctly'); } @@ -117,7 +117,7 @@ fn test_transfer() { let amount: u256 = u256_from_felt(100); let success: bool = ERC20Library::transfer(recipient, amount); - assert(success, ''); + assert(success, 'Should return true'); assert(ERC20Library::balance_of(recipient) == amount, 'Balance should eq amount'); assert(ERC20Library::balance_of(sender) == supply - amount, 'Should eq supply - amount'); assert(ERC20Library::total_supply() == supply, 'Total supply should not change'); @@ -183,7 +183,7 @@ fn test_transfer_from() { starknet_testing::set_caller_address(spender); let success: bool = ERC20Library::transfer_from(owner, recipient, amount); - assert(success, 'Should return success'); + assert(success, 'Should return true'); // Will dangle without setting as a var let spender_allowance: u256 = ERC20Library::allowance(owner, spender); @@ -274,10 +274,12 @@ fn test_increase_allowance() { let amount: u256 = u256_from_felt(100); ERC20Library::approve(spender, amount); - ERC20Library::increase_allowance(spender, amount); + let success: bool = ERC20Library::increase_allowance(spender, amount); + assert(success, 'Should return true'); + let spender_allowance: u256 = ERC20Library::allowance(owner, spender); - assert(spender_allowance == amount + amount, ''); + assert(spender_allowance == amount + amount, 'Should be amount * 2'); } #[test] @@ -316,10 +318,11 @@ fn test_decrease_allowance() { let amount: u256 = u256_from_felt(100); ERC20Library::approve(spender, amount); - ERC20Library::decrease_allowance(spender, amount); + let success: bool = ERC20Library::decrease_allowance(spender, amount); + assert(success, 'Should return true'); let spender_allowance: u256 = ERC20Library::allowance(owner, spender); - assert(spender_allowance == amount - amount, ''); + assert(spender_allowance == amount - amount, 'Should be 0'); } #[test] From 8dd8ed34ccf7fb251018d9bb1908005356598d91 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Feb 2023 00:19:21 -0500 Subject: [PATCH 018/124] update cairo --- cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo b/cairo index d297e4721..30b4acdd4 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit d297e472133680481068cba94d8758aa12117164 +Subproject commit 30b4acdd4df7494b7216206c2a60bfc0876361b7 From 091a29c7cf9aa1ab4d05adab8d53970d2d9cced2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Feb 2023 00:21:32 -0500 Subject: [PATCH 019/124] remove preset mods --- src/openzeppelin/token/erc20/cairo_project.toml | 1 - src/openzeppelin/token/erc20/lib.cairo | 14 ++++++++++++-- src/openzeppelin/token/erc20/tests.cairo | 3 --- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/openzeppelin/token/erc20/cairo_project.toml b/src/openzeppelin/token/erc20/cairo_project.toml index ffd670876..e3dce5a73 100644 --- a/src/openzeppelin/token/erc20/cairo_project.toml +++ b/src/openzeppelin/token/erc20/cairo_project.toml @@ -1,3 +1,2 @@ [crate_roots] erc20 = "." -presets = "presets" diff --git a/src/openzeppelin/token/erc20/lib.cairo b/src/openzeppelin/token/erc20/lib.cairo index e87b836c1..29d85d5fe 100644 --- a/src/openzeppelin/token/erc20/lib.cairo +++ b/src/openzeppelin/token/erc20/lib.cairo @@ -1,6 +1,16 @@ mod erc20; -use erc20::ERC20Library; +use erc20::ERC20; mod tests; -mod presets; +trait IERC20 { + fn name() -> felt; + fn symbol() -> felt; + fn decimals() -> u8; + fn total_supply() -> u256; + fn balance_of(account: ContractAddress) -> u256; + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; + fn approve(spender: ContractAddress, amount: u256) -> bool; +} diff --git a/src/openzeppelin/token/erc20/tests.cairo b/src/openzeppelin/token/erc20/tests.cairo index 13e522153..0117a1281 100644 --- a/src/openzeppelin/token/erc20/tests.cairo +++ b/src/openzeppelin/token/erc20/tests.cairo @@ -1,4 +1 @@ -mod test_erc20_library; mod test_erc20; -mod test_erc20_mintable; -mod test_erc20_burnable; From 1c866f25df3437d6b0e89286568a727529012989 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Feb 2023 00:22:29 -0500 Subject: [PATCH 020/124] add IERC20 trait --- src/openzeppelin/token/erc20/erc20.cairo | 114 +++-- src/openzeppelin/token/erc20/presets.cairo | 3 - .../token/erc20/presets/ERC20.cairo | 71 --- .../token/erc20/presets/cairo_project.toml | 2 - .../token/erc20/presets/erc20_burnable.cairo | 85 ---- .../token/erc20/presets/erc20_mintable.cairo | 76 ---- .../token/erc20/presets/lib.cairo | 8 - .../token/erc20/tests/test_erc20.cairo | 417 ++++++++++++++++- .../erc20/tests/test_erc20_burnable.cairo | 16 - .../erc20/tests/test_erc20_library.cairo | 429 ------------------ .../erc20/tests/test_erc20_mintable.cairo | 16 - 11 files changed, 502 insertions(+), 735 deletions(-) delete mode 100644 src/openzeppelin/token/erc20/presets.cairo delete mode 100644 src/openzeppelin/token/erc20/presets/ERC20.cairo delete mode 100644 src/openzeppelin/token/erc20/presets/cairo_project.toml delete mode 100644 src/openzeppelin/token/erc20/presets/erc20_burnable.cairo delete mode 100644 src/openzeppelin/token/erc20/presets/erc20_mintable.cairo delete mode 100644 src/openzeppelin/token/erc20/presets/lib.cairo delete mode 100644 src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo delete mode 100644 src/openzeppelin/token/erc20/tests/test_erc20_library.cairo delete mode 100644 src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo diff --git a/src/openzeppelin/token/erc20/erc20.cairo b/src/openzeppelin/token/erc20/erc20.cairo index e642211a5..82aed427f 100644 --- a/src/openzeppelin/token/erc20/erc20.cairo +++ b/src/openzeppelin/token/erc20/erc20.cairo @@ -1,5 +1,6 @@ #[contract] -mod ERC20Library { +mod ERC20 { + use erc20::IERC20; use starknet::get_caller_address; use starknet::contract_address_const; use starknet::ContractAddressZeroable; @@ -19,69 +20,128 @@ mod ERC20Library { #[event] fn Approval(owner: ContractAddress, spender: ContractAddress, value: u256) {} - // TMP starknet testing isn't fully functional. - // Use to ensure paths are correctly set. - fn mock_initializer(name_: felt, symbol_: felt) { - _name::write(name_); - _symbol::write(symbol_); + impl ERC20 of IERC20 { + fn name() -> felt { + _name::read() + } + + fn symbol() -> felt { + _symbol::read() + } + + fn decimals() -> u8 { + 18_u8 + } + + fn total_supply() -> u256 { + _total_supply::read() + } + + fn balance_of(account: ContractAddress) -> u256 { + _balances::read(account) + } + + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + _allowances::read((owner, spender)) + } + + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + let sender = get_caller_address(); + _transfer(sender, recipient, amount); + true + } + + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + let caller = get_caller_address(); + _spend_allowance(sender, caller, amount); + _transfer(sender, recipient, amount); + true + } + + fn approve(spender: ContractAddress, amount: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, amount); + true + } } - fn initializer(name_: felt, symbol_: felt, initial_supply: u256, recipient: ContractAddress) { - _name::write(name_); - _symbol::write(symbol_); - _mint(recipient, initial_supply); + #[constructor] + fn constructor(name: felt, symbol: felt, initial_supply: u256, recipient: ContractAddress) { + initializer(name, symbol, initial_supply, recipient); } + #[view] fn name() -> felt { - _name::read() + ERC20::name() } + #[view] fn symbol() -> felt { - _symbol::read() + ERC20::symbol() } + #[view] fn decimals() -> u8 { - 18_u8 + ERC20::decimals() } + #[view] fn total_supply() -> u256 { - _total_supply::read() + ERC20::total_supply() } + #[view] fn balance_of(account: ContractAddress) -> u256 { - _balances::read(account) + ERC20::balance_of(account) } + #[view] fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - _allowances::read((owner, spender)) + ERC20::allowance(owner, spender) } + #[external] fn transfer(recipient: ContractAddress, amount: u256) -> bool { - let sender = get_caller_address(); - _transfer(sender, recipient, amount); - true + ERC20::transfer(recipient, amount) } + #[external] fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - let caller = get_caller_address(); - _spend_allowance(sender, caller, amount); - _transfer(sender, recipient, amount); - true + ERC20::transfer_from(sender, recipient, amount) } + #[external] fn approve(spender: ContractAddress, amount: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, amount); - true + ERC20::approve(spender, amount) } + #[external] fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { + _increase_allowance(spender, added_value) + } + + #[external] + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { + _decrease_allowance(spender, subtracted_value) + } + + /// + /// Internals + /// + + fn initializer(name_: felt, symbol_: felt, initial_supply: u256, recipient: ContractAddress) { + _name::write(name_); + _symbol::write(symbol_); + _mint(recipient, initial_supply); + } + + fn _increase_allowance(spender: ContractAddress, added_value: u256) -> bool { let caller = get_caller_address(); _approve(caller, spender, _allowances::read((caller, spender)) + added_value); true } - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { + fn _decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { let caller = get_caller_address(); _approve(caller, spender, _allowances::read((caller, spender)) - subtracted_value); true diff --git a/src/openzeppelin/token/erc20/presets.cairo b/src/openzeppelin/token/erc20/presets.cairo deleted file mode 100644 index 0ca3c862c..000000000 --- a/src/openzeppelin/token/erc20/presets.cairo +++ /dev/null @@ -1,3 +0,0 @@ -mod erc20; -mod erc20_mintable; -mod erc20_burnable; diff --git a/src/openzeppelin/token/erc20/presets/ERC20.cairo b/src/openzeppelin/token/erc20/presets/ERC20.cairo deleted file mode 100644 index 6d6ee2eac..000000000 --- a/src/openzeppelin/token/erc20/presets/ERC20.cairo +++ /dev/null @@ -1,71 +0,0 @@ -#[contract] -mod ERC20 { - use erc20::ERC20Library; - - // TMP starknet testing isn't fully functional. - // Use to ensure paths are correctly set. - #[external] - fn mock_constructor(name: felt, symbol: felt) { - ERC20Library::mock_initializer(name, symbol); - } - - #[constructor] - fn constructor(name: felt, symbol: felt, initial_supply: u256, recipient: ContractAddress) { - ERC20Library::initializer(name, symbol, initial_supply, recipient); - } - - #[view] - fn name() -> felt { - ERC20Library::name() - } - - #[view] - fn symbol() -> felt { - ERC20Library::symbol() - } - - #[view] - fn decimals() -> u8 { - ERC20Library::decimals() - } - - #[view] - fn total_supply() -> u256 { - ERC20Library::total_supply() - } - - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC20Library::balance_of(account) - } - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20Library::allowance(owner, spender) - } - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20Library::transfer(recipient, amount) - } - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20Library::transfer_from(sender, recipient, amount) - } - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20Library::approve(spender, amount) - } - - #[external] - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - ERC20Library::increase_allowance(spender, added_value) - } - - #[external] - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - ERC20Library::decrease_allowance(spender, subtracted_value) - } -} diff --git a/src/openzeppelin/token/erc20/presets/cairo_project.toml b/src/openzeppelin/token/erc20/presets/cairo_project.toml deleted file mode 100644 index 2f96b70fe..000000000 --- a/src/openzeppelin/token/erc20/presets/cairo_project.toml +++ /dev/null @@ -1,2 +0,0 @@ -[crate_roots] -presets = "." diff --git a/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo b/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo deleted file mode 100644 index 644dcdd6f..000000000 --- a/src/openzeppelin/token/erc20/presets/erc20_burnable.cairo +++ /dev/null @@ -1,85 +0,0 @@ -#[contract] -mod ERC20Burnable { - use erc20::ERC20Library; - use starknet::get_caller_address; - - // TMP starknet testing isn't fully functional. - // Use to ensure paths are correctly set. - #[external] - fn mock_constructor(name: felt, symbol: felt) { - ERC20Library::mock_initializer(name, symbol); - } - - #[constructor] - fn constructor(name: felt, symbol: felt, initial_supply: u256, recipient: ContractAddress) { - ERC20Library::initializer(name, symbol, initial_supply, recipient); - } - - #[view] - fn name() -> felt { - ERC20Library::name() - } - - #[view] - fn symbol() -> felt { - ERC20Library::symbol() - } - - #[view] - fn decimals() -> u8 { - ERC20Library::decimals() - } - - #[view] - fn total_supply() -> u256 { - ERC20Library::total_supply() - } - - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC20Library::balance_of(account) - } - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20Library::allowance(owner, spender) - } - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20Library::transfer(recipient, amount) - } - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20Library::transfer_from(sender, recipient, amount) - } - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20Library::approve(spender, amount) - } - - #[external] - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - ERC20Library::increase_allowance(spender, added_value) - } - - #[external] - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - ERC20Library::decrease_allowance(spender, subtracted_value) - } - - #[external] - fn burn(amount: u256) { - let caller = get_caller_address(); - ERC20Library::_burn(caller, amount); - } - - #[external] - fn burn_from(account: ContractAddress, amount: u256) { - let caller = get_caller_address(); - ERC20Library::_spend_allowance(account, caller, amount); - ERC20Library::_burn(account, amount); - } -} diff --git a/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo b/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo deleted file mode 100644 index d25661a88..000000000 --- a/src/openzeppelin/token/erc20/presets/erc20_mintable.cairo +++ /dev/null @@ -1,76 +0,0 @@ -#[contract] -mod ERC20Mintable { - use erc20::ERC20Library; - - // TMP starknet testing isn't fully functional. - // Use to ensure paths are correctly set. - #[external] - fn mock_constructor(name: felt, symbol: felt) { - ERC20Library::mock_initializer(name, symbol); - } - - #[constructor] - fn constructor(name: felt, symbol: felt, initial_supply: u256, recipient: ContractAddress) { - ERC20Library::initializer(name, symbol, initial_supply, recipient); - } - - #[view] - fn name() -> felt { - ERC20Library::name() - } - - #[view] - fn symbol() -> felt { - ERC20Library::symbol() - } - - #[view] - fn decimals() -> u8 { - ERC20Library::decimals() - } - - #[view] - fn total_supply() -> u256 { - ERC20Library::total_supply() - } - - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC20Library::balance_of(account) - } - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20Library::allowance(owner, spender) - } - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20Library::transfer(recipient, amount) - } - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20Library::transfer_from(sender, recipient, amount) - } - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20Library::approve(spender, amount) - } - - #[external] - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - ERC20Library::increase_allowance(spender, added_value) - } - - #[external] - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - ERC20Library::decrease_allowance(spender, subtracted_value) - } - - #[external] - fn mint(recipient: ContractAddress, amount: u256) { - ERC20Library::_mint(recipient, amount); - } -} diff --git a/src/openzeppelin/token/erc20/presets/lib.cairo b/src/openzeppelin/token/erc20/presets/lib.cairo deleted file mode 100644 index 31d88e007..000000000 --- a/src/openzeppelin/token/erc20/presets/lib.cairo +++ /dev/null @@ -1,8 +0,0 @@ -mod erc20; -use erc20::ERC20; - -mod erc20_mintable; -use erc20_mintable::ERC20Mintable; - -mod erc20_burnable; -use erc20_burnable::ERC20Burnable; diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo index 7d5b903d5..76d6f076c 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20.cairo @@ -1,16 +1,429 @@ -use presets::ERC20; +use erc20::ERC20; +use starknet::contract_address_const; +use starknet_testing::set_caller_address; +use integer::u256_from_felt; const NAME: felt = 111; const SYMBOL: felt = 222; +fn setup() -> (ContractAddress, u256) { + let initial_supply: u256 = u256_from_felt(2000); + let account: ContractAddress = contract_address_const::<1>(); + // Set account as default caller + starknet_testing::set_caller_address(account); + + ERC20::initializer(NAME, SYMBOL, initial_supply, account); + (account, initial_supply) +} + +fn set_caller_as_zero() { + starknet_testing::set_caller_address(contract_address_const::<0>()); +} + #[test] #[available_gas(2000000)] fn initialize() { + let initial_supply: u256 = u256_from_felt(2000); + let account: ContractAddress = contract_address_const::<1>(); let decimals: u8 = 18_u8; - ERC20::mock_constructor(NAME, SYMBOL); + ERC20::initializer(NAME, SYMBOL, initial_supply, account); + + let owner_balance: u256 = ERC20::balance_of(account); + assert(owner_balance == initial_supply, 'Should eq inital_supply'); + assert(ERC20::total_supply() == initial_supply, 'Should eq inital_supply'); assert(ERC20::name() == NAME, 'Name should be NAME'); assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); assert(ERC20::decimals() == decimals, 'Decimals should be 18'); } + +#[test] +#[available_gas(2000000)] +fn test_approve() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + let success: bool = ERC20::approve(spender, amount); + assert(success, 'Should return true'); + assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_approve_from_zero() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + set_caller_as_zero(); + + ERC20::approve(spender, amount); + assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_approve_to_zero() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20::approve(spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__approve() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20::_approve(owner, spender, amount); + assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__approve_from_zero() { + let owner: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<1>(); + let amount: u256 = u256_from_felt(100); + ERC20::_approve(owner, spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__approve_to_zero() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + ERC20::_approve(owner, spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + let success: bool = ERC20::transfer(recipient, amount); + + assert(success, 'Should return true'); + assert(ERC20::balance_of(recipient) == amount, 'Balance should eq amount'); + assert(ERC20::balance_of(sender) == supply - amount, 'Should eq supply - amount'); + assert(ERC20::total_supply() == supply, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test__transfer() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + ERC20::_transfer(sender, recipient, amount); + + assert(ERC20::balance_of(recipient) == amount, 'Balance should eq amount'); + assert(ERC20::balance_of(sender) == supply - amount, 'Should eq supply - amount'); + assert(ERC20::total_supply() == supply, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__transfer_not_enough_balance() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = supply + u256_from_felt(1); + ERC20::_transfer(sender, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__transfer_from_zero() { + let sender: ContractAddress = contract_address_const::<0>(); + let recipient: ContractAddress = contract_address_const::<1>(); + let amount: u256 = u256_from_felt(100); + ERC20::_transfer(sender, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__transfer_to_zero() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + ERC20::_transfer(sender, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + + ERC20::approve(spender, amount); + + starknet_testing::set_caller_address(spender); + + let success: bool = ERC20::transfer_from(owner, recipient, amount); + assert(success, 'Should return true'); + + // Will dangle without setting as a var + let spender_allowance: u256 = ERC20::allowance(owner, spender); + + assert(ERC20::balance_of(recipient) == amount, 'Should eq amount'); + assert(ERC20::balance_of(owner) == supply - amount, 'Should eq suppy - amount'); + assert(spender_allowance == u256_from_felt(0), 'Should eq 0'); + assert(ERC20::total_supply() == supply, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from_doesnt_consume_infinite_allowance() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + let max_u256: u256 = u256_from_felt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) * u256_from_felt(256) + u256_from_felt(255); + + ERC20::approve(spender, max_u256); + + starknet_testing::set_caller_address(spender); + + ERC20::transfer_from(owner, recipient, amount); + + let spender_allowance: u256 = ERC20::allowance(owner, spender); + assert(spender_allowance == max_u256, 'Should remain max_uint256'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_transfer_from_greater_than_allowance() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + let amount_plus_one: u256 = amount + u256_from_felt(1); + + ERC20::approve(spender, amount); + + starknet_testing::set_caller_address(spender); + + ERC20::transfer_from(owner, recipient, amount_plus_one); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_transfer_from_to_zero_address() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + + ERC20::approve(spender, amount); + + starknet_testing::set_caller_address(spender); + + ERC20::transfer_from(owner, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_transfer_from_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt(100); + + starknet_testing::set_caller_address(zero_address); + + ERC20::transfer_from(owner, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_increase_allowance() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20::approve(spender, amount); + let success: bool = ERC20::increase_allowance(spender, amount); + assert(success, 'Should return true'); + + + let spender_allowance: u256 = ERC20::allowance(owner, spender); + assert(spender_allowance == amount + amount, 'Should be amount * 2'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_increase_allowance_to_zero_address() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20::increase_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_increase_allowance_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + starknet_testing::set_caller_address(zero_address); + + ERC20::increase_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_decrease_allowance() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20::approve(spender, amount); + let success: bool = ERC20::decrease_allowance(spender, amount); + assert(success, 'Should return true'); + + let spender_allowance: u256 = ERC20::allowance(owner, spender); + assert(spender_allowance == amount - amount, 'Should be 0'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_decrease_allowance_to_zero_address() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20::decrease_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_decrease_allowance_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + starknet_testing::set_caller_address(zero_address); + + ERC20::decrease_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__spend_allowance_not_unlimited() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20::_approve(owner, spender, supply); + ERC20::_spend_allowance(owner, spender, amount); + assert(ERC20::allowance(owner, spender) == supply - amount, 'Should eq supply - amount'); +} + +#[test] +#[available_gas(2000000)] +fn test__spend_allowance_unlimited() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + + let max_u256: u256 = u256_from_felt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) * u256_from_felt(256) + u256_from_felt(255); + let max_minus_one: u256 = max_u256 - u256_from_felt(1); + + ERC20::_approve(owner, spender, max_u256); + ERC20::_spend_allowance(owner, spender, max_minus_one); + + assert(ERC20::allowance(owner, spender) == max_u256, 'Allowance should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test__mint() { + let minter: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt(100); + + ERC20::_mint(minter, amount); + + let minter_balance: u256 = ERC20::balance_of(minter); + assert(minter_balance == amount, 'Should eq amount'); + + assert(ERC20::total_supply() == amount, 'Should eq total supply'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__mint_to_zero() { + let minter: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20::_mint(minter, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__burn() { + let (owner, supply) = setup(); + + let amount: u256 = u256_from_felt(100); + ERC20::_burn(owner, amount); + + assert(ERC20::total_supply() == supply - amount, 'Should eq supply - amount'); + assert(ERC20::balance_of(owner) == supply - amount, 'Should eq supply - amount'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test__burn_from_zero() { + setup(); + let zero_address: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt(100); + + ERC20::_burn(zero_address, amount); +} diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo deleted file mode 100644 index 53e2a53ee..000000000 --- a/src/openzeppelin/token/erc20/tests/test_erc20_burnable.cairo +++ /dev/null @@ -1,16 +0,0 @@ -use presets::ERC20Burnable; - -const NAME: felt = 111; -const SYMBOL: felt = 222; - -#[test] -#[available_gas(2000000)] -fn initialize() { - let decimals: u8 = 18_u8; - - ERC20Burnable::mock_constructor(NAME, SYMBOL); - - assert(ERC20Burnable::name() == NAME, 'Name should be NAME'); - assert(ERC20Burnable::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20Burnable::decimals() == decimals, 'Decimals should be 18'); -} diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo deleted file mode 100644 index 519f73e17..000000000 --- a/src/openzeppelin/token/erc20/tests/test_erc20_library.cairo +++ /dev/null @@ -1,429 +0,0 @@ -use erc20::ERC20Library; -use starknet::contract_address_const; -use starknet_testing::set_caller_address; -use integer::u256_from_felt; - -const NAME: felt = 111; -const SYMBOL: felt = 222; - -fn setup() -> (ContractAddress, u256) { - let initial_supply: u256 = u256_from_felt(2000); - let account: ContractAddress = contract_address_const::<1>(); - // Set caller - starknet_testing::set_caller_address(account); - - ERC20Library::initializer(NAME, SYMBOL, initial_supply, account); - (account, initial_supply) -} - -fn set_caller_as_zero() { - starknet_testing::set_caller_address(contract_address_const::<0>()); -} - -#[test] -#[available_gas(2000000)] -fn initialize() { - let initial_supply: u256 = u256_from_felt(2000); - let account: ContractAddress = contract_address_const::<1>(); - let decimals: u8 = 18_u8; - - ERC20Library::initializer(NAME, SYMBOL, initial_supply, account); - - let owner_balance: u256 = ERC20Library::balance_of(account); - assert(owner_balance == initial_supply, 'Should eq inital_supply'); - - assert(ERC20Library::total_supply() == initial_supply, 'Should eq inital_supply'); - assert(ERC20Library::name() == NAME, 'Name should be NAME'); - assert(ERC20Library::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20Library::decimals() == decimals, 'Decimals should be 18'); -} - -#[test] -#[available_gas(2000000)] -fn test_approve() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - let success: bool = ERC20Library::approve(spender, amount); - assert(success, 'Should return true'); - assert(ERC20Library::allowance(owner, spender) == amount, 'Spender not approved correctly'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_approve_from_zero() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - set_caller_as_zero(); - - ERC20Library::approve(spender, amount); - assert(ERC20Library::allowance(owner, spender) == amount, 'Spender not approved correctly'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_approve_to_zero() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::approve(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__approve() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::_approve(owner, spender, amount); - assert(ERC20Library::allowance(owner, spender) == amount, 'Spender not approved correctly'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__approve_from_zero() { - let owner: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<1>(); - let amount: u256 = u256_from_felt(100); - ERC20Library::_approve(owner, spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__approve_to_zero() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - ERC20Library::_approve(owner, spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - let success: bool = ERC20Library::transfer(recipient, amount); - - assert(success, 'Should return true'); - assert(ERC20Library::balance_of(recipient) == amount, 'Balance should eq amount'); - assert(ERC20Library::balance_of(sender) == supply - amount, 'Should eq supply - amount'); - assert(ERC20Library::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test__transfer() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - ERC20Library::_transfer(sender, recipient, amount); - - assert(ERC20Library::balance_of(recipient) == amount, 'Balance should eq amount'); - assert(ERC20Library::balance_of(sender) == supply - amount, 'Should eq supply - amount'); - assert(ERC20Library::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__transfer_not_enough_balance() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = supply + u256_from_felt(1); - ERC20Library::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__transfer_from_zero() { - let sender: ContractAddress = contract_address_const::<0>(); - let recipient: ContractAddress = contract_address_const::<1>(); - let amount: u256 = u256_from_felt(100); - ERC20Library::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__transfer_to_zero() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - ERC20Library::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer_from() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::approve(spender, amount); - - starknet_testing::set_caller_address(spender); - - let success: bool = ERC20Library::transfer_from(owner, recipient, amount); - assert(success, 'Should return true'); - - // Will dangle without setting as a var - let spender_allowance: u256 = ERC20Library::allowance(owner, spender); - - assert(ERC20Library::balance_of(recipient) == amount, 'Should eq amount'); - assert(ERC20Library::balance_of(owner) == supply - amount, 'Should eq suppy - amount'); - assert(spender_allowance == u256_from_felt(0), 'Should eq 0'); - assert(ERC20Library::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer_from_doesnt_consume_infinite_allowance() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - let max_u256: u256 = u256_from_felt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) * u256_from_felt(256) + u256_from_felt(255); - - ERC20Library::approve(spender, max_u256); - - starknet_testing::set_caller_address(spender); - - ERC20Library::transfer_from(owner, recipient, amount); - - let spender_allowance: u256 = ERC20Library::allowance(owner, spender); - assert(spender_allowance == max_u256, 'Should remain max_uint256'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_transfer_from_greater_than_allowance() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - let amount_plus_one: u256 = amount + u256_from_felt(1); - - ERC20Library::approve(spender, amount); - - starknet_testing::set_caller_address(spender); - - ERC20Library::transfer_from(owner, recipient, amount_plus_one); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_transfer_from_to_zero_address() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::approve(spender, amount); - - starknet_testing::set_caller_address(spender); - - ERC20Library::transfer_from(owner, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_transfer_from_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - - starknet_testing::set_caller_address(zero_address); - - ERC20Library::transfer_from(owner, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_increase_allowance() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::approve(spender, amount); - let success: bool = ERC20Library::increase_allowance(spender, amount); - assert(success, 'Should return true'); - - - let spender_allowance: u256 = ERC20Library::allowance(owner, spender); - assert(spender_allowance == amount + amount, 'Should be amount * 2'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_increase_allowance_to_zero_address() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::increase_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_increase_allowance_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - starknet_testing::set_caller_address(zero_address); - - ERC20Library::increase_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_decrease_allowance() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::approve(spender, amount); - let success: bool = ERC20Library::decrease_allowance(spender, amount); - assert(success, 'Should return true'); - - let spender_allowance: u256 = ERC20Library::allowance(owner, spender); - assert(spender_allowance == amount - amount, 'Should be 0'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_decrease_allowance_to_zero_address() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::decrease_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_decrease_allowance_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - starknet_testing::set_caller_address(zero_address); - - ERC20Library::decrease_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__spend_allowance_not_unlimited() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::_approve(owner, spender, supply); - ERC20Library::_spend_allowance(owner, spender, amount); - assert(ERC20Library::allowance(owner, spender) == supply - amount, 'Should eq supply - amount'); -} - -#[test] -#[available_gas(2000000)] -fn test__spend_allowance_unlimited() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - - let max_u256: u256 = u256_from_felt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) * u256_from_felt(256) + u256_from_felt(255); - let max_minus_one: u256 = max_u256 - u256_from_felt(1); - - ERC20Library::_approve(owner, spender, max_u256); - ERC20Library::_spend_allowance(owner, spender, max_minus_one); - - assert(ERC20Library::allowance(owner, spender) == max_u256, 'Allowance should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test__mint() { - let minter: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::_mint(minter, amount); - - let minter_balance: u256 = ERC20Library::balance_of(minter); - assert(minter_balance == amount, 'Should eq amount'); - - assert(ERC20Library::total_supply() == amount, 'Should eq total supply'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__mint_to_zero() { - let minter: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::_mint(minter, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__burn() { - let (owner, supply) = setup(); - - let amount: u256 = u256_from_felt(100); - ERC20Library::_burn(owner, amount); - - assert(ERC20Library::total_supply() == supply - amount, 'Should eq supply - amount'); - assert(ERC20Library::balance_of(owner) == supply - amount, 'Should eq supply - amount'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__burn_from_zero() { - setup(); - let zero_address: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20Library::_burn(zero_address, amount); -} diff --git a/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo b/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo deleted file mode 100644 index 448bd82dd..000000000 --- a/src/openzeppelin/token/erc20/tests/test_erc20_mintable.cairo +++ /dev/null @@ -1,16 +0,0 @@ -use presets::ERC20Mintable; - -const NAME: felt = 111; -const SYMBOL: felt = 222; - -#[test] -#[available_gas(2000000)] -fn initialize() { - let decimals: u8 = 18_u8; - - ERC20Mintable::mock_constructor(NAME, SYMBOL); - - assert(ERC20Mintable::name() == NAME, 'Name should be NAME'); - assert(ERC20Mintable::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20Mintable::decimals() == decimals, 'Decimals should be 18'); -} From 3405063e308c470635f86965969c7b04a89f865c Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Feb 2023 11:31:31 -0500 Subject: [PATCH 021/124] update cairo --- cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo b/cairo index 30b4acdd4..34796ef86 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 30b4acdd4df7494b7216206c2a60bfc0876361b7 +Subproject commit 34796ef8615a96ea28888421dc2bc498786d01d6 From 8fe3c820f21082c909351ae04b5f9e63dedd643e Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Feb 2023 11:32:05 -0500 Subject: [PATCH 022/124] clean up test --- .../token/erc20/tests/test_erc20.cairo | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo index 76d6f076c..804c03879 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20.cairo @@ -10,14 +10,14 @@ fn setup() -> (ContractAddress, u256) { let initial_supply: u256 = u256_from_felt(2000); let account: ContractAddress = contract_address_const::<1>(); // Set account as default caller - starknet_testing::set_caller_address(account); + set_caller_address(account); ERC20::initializer(NAME, SYMBOL, initial_supply, account); (account, initial_supply) } fn set_caller_as_zero() { - starknet_testing::set_caller_address(contract_address_const::<0>()); + set_caller_address(contract_address_const::<0>()); } #[test] @@ -180,7 +180,7 @@ fn test_transfer_from() { ERC20::approve(spender, amount); - starknet_testing::set_caller_address(spender); + set_caller_address(spender); let success: bool = ERC20::transfer_from(owner, recipient, amount); assert(success, 'Should return true'); @@ -206,7 +206,7 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { ERC20::approve(spender, max_u256); - starknet_testing::set_caller_address(spender); + set_caller_address(spender); ERC20::transfer_from(owner, recipient, amount); @@ -227,7 +227,7 @@ fn test_transfer_from_greater_than_allowance() { ERC20::approve(spender, amount); - starknet_testing::set_caller_address(spender); + set_caller_address(spender); ERC20::transfer_from(owner, recipient, amount_plus_one); } @@ -244,7 +244,7 @@ fn test_transfer_from_to_zero_address() { ERC20::approve(spender, amount); - starknet_testing::set_caller_address(spender); + set_caller_address(spender); ERC20::transfer_from(owner, recipient, amount); } @@ -260,7 +260,7 @@ fn test_transfer_from_from_zero_address() { let spender: ContractAddress = contract_address_const::<3>(); let amount: u256 = u256_from_felt(100); - starknet_testing::set_caller_address(zero_address); + set_caller_address(zero_address); ERC20::transfer_from(owner, recipient, amount); } @@ -304,7 +304,7 @@ fn test_increase_allowance_from_zero_address() { let spender: ContractAddress = contract_address_const::<2>(); let amount: u256 = u256_from_felt(100); - starknet_testing::set_caller_address(zero_address); + set_caller_address(zero_address); ERC20::increase_allowance(spender, amount); } @@ -347,7 +347,7 @@ fn test_decrease_allowance_from_zero_address() { let spender: ContractAddress = contract_address_const::<2>(); let amount: u256 = u256_from_felt(100); - starknet_testing::set_caller_address(zero_address); + set_caller_address(zero_address); ERC20::decrease_allowance(spender, amount); } From ad928bc356d25446ee78c264d4ddd340d1a05840 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 23 Feb 2023 01:33:46 -0500 Subject: [PATCH 023/124] remove assertion --- src/openzeppelin/token/erc20/tests/test_erc20.cairo | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo index 804c03879..be8adc9e8 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20.cairo @@ -61,7 +61,6 @@ fn test_approve_from_zero() { set_caller_as_zero(); ERC20::approve(spender, amount); - assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); } #[test] From d883eb5bae10b56e36dda6b16ffaa12c253a91d2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 23 Feb 2023 01:33:59 -0500 Subject: [PATCH 024/124] update cairo --- Cargo.lock | 1 + cairo | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 3dbb84efb..e6cd6443e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -834,6 +834,7 @@ dependencies = [ "rayon", "salsa", "thiserror", + "unescaper", ] [[package]] diff --git a/cairo b/cairo index 34796ef86..176712e8e 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 34796ef8615a96ea28888421dc2bc498786d01d6 +Subproject commit 176712e8e54404a79f42bd90251571a5d90d7250 From 543501ba9cf14dc294e3d8e70bb3a5d82b184986 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 23 Feb 2023 01:43:57 -0500 Subject: [PATCH 025/124] simplify max_u256 --- src/openzeppelin/token/erc20/tests/test_erc20.cairo | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo index be8adc9e8..df329dff7 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20.cairo @@ -1,6 +1,7 @@ use erc20::ERC20; use starknet::contract_address_const; use starknet_testing::set_caller_address; +use integer::u256; use integer::u256_from_felt; const NAME: felt = 111; @@ -201,7 +202,10 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { let recipient: ContractAddress = contract_address_const::<2>(); let spender: ContractAddress = contract_address_const::<3>(); let amount: u256 = u256_from_felt(100); - let max_u256: u256 = u256_from_felt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) * u256_from_felt(256) + u256_from_felt(255); + let max_u256: u256 = u256 { + low: 0xffffffffffffffffffffffffffffffff_u128, + high: 0xffffffffffffffffffffffffffffffff_u128 + }; ERC20::approve(spender, max_u256); @@ -371,7 +375,10 @@ fn test__spend_allowance_unlimited() { let spender: ContractAddress = contract_address_const::<2>(); - let max_u256: u256 = u256_from_felt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) * u256_from_felt(256) + u256_from_felt(255); + let max_u256: u256 = u256 { + low: 0xffffffffffffffffffffffffffffffff_u128, + high: 0xffffffffffffffffffffffffffffffff_u128 + }; let max_minus_one: u256 = max_u256 - u256_from_felt(1); ERC20::_approve(owner, spender, max_u256); From 2ecba911baf559b92295057b3dba92c10d0e1330 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 23 Feb 2023 01:48:35 -0500 Subject: [PATCH 026/124] clarify error msg --- src/openzeppelin/token/erc20/tests/test_erc20.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo index df329dff7..a41cf5bd3 100644 --- a/src/openzeppelin/token/erc20/tests/test_erc20.cairo +++ b/src/openzeppelin/token/erc20/tests/test_erc20.cairo @@ -214,7 +214,7 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { ERC20::transfer_from(owner, recipient, amount); let spender_allowance: u256 = ERC20::allowance(owner, spender); - assert(spender_allowance == max_u256, 'Should remain max_uint256'); + assert(spender_allowance == max_u256, 'Allowance should not change'); } #[test] From 6c3978b519429a7190328b2a6fa525e5574408dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Fri, 3 Mar 2023 16:18:10 -0300 Subject: [PATCH 027/124] add erc165 + tests --- .../introspection/erc165/IERC165.cairo | 10 ----- .../introspection/erc165/cairo_project.toml | 2 + .../introspection/erc165/lib.cairo | 6 +++ .../introspection/erc165/library.cairo | 38 ---------------- .../introspection/erc165/tests.cairo | 2 + .../erc165/tests/erc165mock.cairo | 34 +++++++++++++++ .../erc165/tests/test_erc165.cairo | 43 +++++++++++++++++++ 7 files changed, 87 insertions(+), 48 deletions(-) delete mode 100644 src/openzeppelin/introspection/erc165/IERC165.cairo create mode 100644 src/openzeppelin/introspection/erc165/cairo_project.toml create mode 100644 src/openzeppelin/introspection/erc165/lib.cairo delete mode 100644 src/openzeppelin/introspection/erc165/library.cairo create mode 100644 src/openzeppelin/introspection/erc165/tests.cairo create mode 100644 src/openzeppelin/introspection/erc165/tests/erc165mock.cairo create mode 100644 src/openzeppelin/introspection/erc165/tests/test_erc165.cairo diff --git a/src/openzeppelin/introspection/erc165/IERC165.cairo b/src/openzeppelin/introspection/erc165/IERC165.cairo deleted file mode 100644 index d34be3a33..000000000 --- a/src/openzeppelin/introspection/erc165/IERC165.cairo +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (introspection/erc165/IERC165.cairo) - -%lang starknet - -@contract_interface -namespace IERC165 { - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/introspection/erc165/cairo_project.toml b/src/openzeppelin/introspection/erc165/cairo_project.toml new file mode 100644 index 000000000..ba52962d0 --- /dev/null +++ b/src/openzeppelin/introspection/erc165/cairo_project.toml @@ -0,0 +1,2 @@ +[crate_roots] +erc165 = "." diff --git a/src/openzeppelin/introspection/erc165/lib.cairo b/src/openzeppelin/introspection/erc165/lib.cairo new file mode 100644 index 000000000..32e5e1525 --- /dev/null +++ b/src/openzeppelin/introspection/erc165/lib.cairo @@ -0,0 +1,6 @@ +mod tests; + +trait IERC165 { + fn supports_interface(interface_id: felt) -> bool; + fn register_interface(interface_id: felt); +} diff --git a/src/openzeppelin/introspection/erc165/library.cairo b/src/openzeppelin/introspection/erc165/library.cairo deleted file mode 100644 index 8073cef40..000000000 --- a/src/openzeppelin/introspection/erc165/library.cairo +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (introspection/erc165/library.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.math import assert_not_equal -from starkware.cairo.common.bool import TRUE - -from openzeppelin.utils.constants.library import INVALID_ID, IERC165_ID - -@storage_var -func ERC165_supported_interfaces(interface_id: felt) -> (is_supported: felt) { -} - -namespace ERC165 { - func supports_interface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interface_id: felt - ) -> (success: felt) { - if (interface_id == IERC165_ID) { - return (success=TRUE); - } - - // Checks interface registry - let (is_supported) = ERC165_supported_interfaces.read(interface_id); - return (success=is_supported); - } - - func register_interface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interface_id: felt - ) { - with_attr error_message("ERC165: invalid interface id") { - assert_not_equal(interface_id, INVALID_ID); - } - ERC165_supported_interfaces.write(interface_id, TRUE); - return (); - } -} diff --git a/src/openzeppelin/introspection/erc165/tests.cairo b/src/openzeppelin/introspection/erc165/tests.cairo new file mode 100644 index 000000000..517c54280 --- /dev/null +++ b/src/openzeppelin/introspection/erc165/tests.cairo @@ -0,0 +1,2 @@ +mod test_erc165; +mod erc165mock; diff --git a/src/openzeppelin/introspection/erc165/tests/erc165mock.cairo b/src/openzeppelin/introspection/erc165/tests/erc165mock.cairo new file mode 100644 index 000000000..0526945e7 --- /dev/null +++ b/src/openzeppelin/introspection/erc165/tests/erc165mock.cairo @@ -0,0 +1,34 @@ +#[contract] +mod ERC165Mock { + use erc165::IERC165; + const IERC165_ID: felt = 0x01ffc9a7; + const INVALID_ID: felt = 0xffffffff; + + struct Storage { + supported_interfaces: LegacyMap::, + } + + impl ERC165 of IERC165 { + fn supports_interface(interface_id: felt) -> bool { + if interface_id == IERC165_ID { + return true; + } + supported_interfaces::read(interface_id) + } + + fn register_interface(interface_id: felt) { + assert(interface_id != INVALID_ID, 'Invalid id'); + supported_interfaces::write(interface_id, true); + } + } + + #[view] + fn supports_interface(interface_id: felt) -> bool { + ERC165::supports_interface(interface_id) + } + + #[external] + fn register_interface(interface_id: felt) { + ERC165::register_interface(interface_id) + } +} diff --git a/src/openzeppelin/introspection/erc165/tests/test_erc165.cairo b/src/openzeppelin/introspection/erc165/tests/test_erc165.cairo new file mode 100644 index 000000000..21ca324d5 --- /dev/null +++ b/src/openzeppelin/introspection/erc165/tests/test_erc165.cairo @@ -0,0 +1,43 @@ +use erc165::tests::erc165mock::ERC165Mock; + +const ERC165_ID: felt = 0x01ffc9a7; +const INVALID_ID: felt = 0xffffffff; +const OTHER_ID: felt = 0x12345678; + + +#[test] +#[available_gas(2000000)] +fn test_default_behavior() { + let supports_default_interface: bool = ERC165Mock::supports_interface(ERC165_ID); + assert(supports_default_interface, 'Should support base interface'); +} + +#[test] +#[available_gas(2000000)] +fn test_not_registered_interface() { + let supports_unregistered_interface: bool = ERC165Mock::supports_interface(OTHER_ID); + assert(! supports_unregistered_interface, 'Should not support unregistered'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_supports_invalid_interface() { + let supports_invalid_interface: bool = ERC165Mock::supports_interface(INVALID_ID); + assert(! supports_invalid_interface, 'Should not support invalid id'); +} + +#[test] +#[available_gas(2000000)] +fn test_register_interface() { + ERC165Mock::register_interface(OTHER_ID); + let supports_new_interface: bool = ERC165Mock::supports_interface(OTHER_ID); + assert(supports_new_interface, 'Should support new interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_register_invalid_interface() { + ERC165Mock::register_interface(INVALID_ID); +} From 60365c8425efd3fa14e8a47dc4260b93864f393a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Fri, 3 Mar 2023 17:02:11 -0300 Subject: [PATCH 028/124] kickstart account module --- src/openzeppelin/account/cairo_project.toml | 2 + src/openzeppelin/account/lib.cairo | 6 +++ .../account/{presets => old}/Account.cairo | 0 .../{presets => old}/AddressRegistry.cairo | 0 .../account/{presets => old}/EthAccount.cairo | 0 .../account/{ => old}/IAccount.cairo | 0 .../account/{ => old}/library.cairo | 0 src/openzeppelin/account/tests.cairo | 2 + .../account/tests/account_mock.cairo | 54 +++++++++++++++++++ .../account/tests/test_account.cairo | 43 +++++++++++++++ 10 files changed, 107 insertions(+) create mode 100644 src/openzeppelin/account/cairo_project.toml create mode 100644 src/openzeppelin/account/lib.cairo rename src/openzeppelin/account/{presets => old}/Account.cairo (100%) rename src/openzeppelin/account/{presets => old}/AddressRegistry.cairo (100%) rename src/openzeppelin/account/{presets => old}/EthAccount.cairo (100%) rename src/openzeppelin/account/{ => old}/IAccount.cairo (100%) rename src/openzeppelin/account/{ => old}/library.cairo (100%) create mode 100644 src/openzeppelin/account/tests.cairo create mode 100644 src/openzeppelin/account/tests/account_mock.cairo create mode 100644 src/openzeppelin/account/tests/test_account.cairo diff --git a/src/openzeppelin/account/cairo_project.toml b/src/openzeppelin/account/cairo_project.toml new file mode 100644 index 000000000..9a0b3f035 --- /dev/null +++ b/src/openzeppelin/account/cairo_project.toml @@ -0,0 +1,2 @@ +[crate_roots] +account = "." diff --git a/src/openzeppelin/account/lib.cairo b/src/openzeppelin/account/lib.cairo new file mode 100644 index 000000000..f6bc9aeb8 --- /dev/null +++ b/src/openzeppelin/account/lib.cairo @@ -0,0 +1,6 @@ +mod tests; + +trait IAccount { + // fn supports_interface(interface_id: felt) -> bool; + // fn register_interface(interface_id: felt); +} diff --git a/src/openzeppelin/account/presets/Account.cairo b/src/openzeppelin/account/old/Account.cairo similarity index 100% rename from src/openzeppelin/account/presets/Account.cairo rename to src/openzeppelin/account/old/Account.cairo diff --git a/src/openzeppelin/account/presets/AddressRegistry.cairo b/src/openzeppelin/account/old/AddressRegistry.cairo similarity index 100% rename from src/openzeppelin/account/presets/AddressRegistry.cairo rename to src/openzeppelin/account/old/AddressRegistry.cairo diff --git a/src/openzeppelin/account/presets/EthAccount.cairo b/src/openzeppelin/account/old/EthAccount.cairo similarity index 100% rename from src/openzeppelin/account/presets/EthAccount.cairo rename to src/openzeppelin/account/old/EthAccount.cairo diff --git a/src/openzeppelin/account/IAccount.cairo b/src/openzeppelin/account/old/IAccount.cairo similarity index 100% rename from src/openzeppelin/account/IAccount.cairo rename to src/openzeppelin/account/old/IAccount.cairo diff --git a/src/openzeppelin/account/library.cairo b/src/openzeppelin/account/old/library.cairo similarity index 100% rename from src/openzeppelin/account/library.cairo rename to src/openzeppelin/account/old/library.cairo diff --git a/src/openzeppelin/account/tests.cairo b/src/openzeppelin/account/tests.cairo new file mode 100644 index 000000000..b837159e4 --- /dev/null +++ b/src/openzeppelin/account/tests.cairo @@ -0,0 +1,2 @@ +mod test_account; +mod account_mock; diff --git a/src/openzeppelin/account/tests/account_mock.cairo b/src/openzeppelin/account/tests/account_mock.cairo new file mode 100644 index 000000000..cee549e12 --- /dev/null +++ b/src/openzeppelin/account/tests/account_mock.cairo @@ -0,0 +1,54 @@ +#[account_contract] +mod Account { + use erc165::ERC165Library; + use starknet::get_caller_address; + use starknet::get_contract_address; + + struct Storage { + public_key: felt, + } + + #[constructor] + fn constructor(_public_key: felt) { + public_key::write(_public_key); + } + + #[external] + fn __execute__(amount: felt) { + let is_valid = is_valid_signature(); + assert(is_valid == true, 'Invalid signature.'); + } + + #[external] + fn set_public_key(new_public_key: felt) { + only_self(); + public_key::write(new_public_key); + } + + #[view] + fn get_public_key() -> felt { + public_key::read() + } + + #[view] + fn is_valid_signature() -> bool { + true + } + + fn only_self() { + let caller = starknet::get_caller_address(); + let self = starknet::get_contract_address(); + assert(1 == 2, 'Account: unauthorized.'); + } + + // ERC165Library + #[view] + fn supports_interface(interface_id: felt) -> bool { + ERC165Library::supports_interface(interface_id) + } + + #[external] + fn register_interface(interface_id: felt) { + ERC165Library::register_interface(interface_id); + } +} diff --git a/src/openzeppelin/account/tests/test_account.cairo b/src/openzeppelin/account/tests/test_account.cairo new file mode 100644 index 000000000..21ca324d5 --- /dev/null +++ b/src/openzeppelin/account/tests/test_account.cairo @@ -0,0 +1,43 @@ +use erc165::tests::erc165mock::ERC165Mock; + +const ERC165_ID: felt = 0x01ffc9a7; +const INVALID_ID: felt = 0xffffffff; +const OTHER_ID: felt = 0x12345678; + + +#[test] +#[available_gas(2000000)] +fn test_default_behavior() { + let supports_default_interface: bool = ERC165Mock::supports_interface(ERC165_ID); + assert(supports_default_interface, 'Should support base interface'); +} + +#[test] +#[available_gas(2000000)] +fn test_not_registered_interface() { + let supports_unregistered_interface: bool = ERC165Mock::supports_interface(OTHER_ID); + assert(! supports_unregistered_interface, 'Should not support unregistered'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_supports_invalid_interface() { + let supports_invalid_interface: bool = ERC165Mock::supports_interface(INVALID_ID); + assert(! supports_invalid_interface, 'Should not support invalid id'); +} + +#[test] +#[available_gas(2000000)] +fn test_register_interface() { + ERC165Mock::register_interface(OTHER_ID); + let supports_new_interface: bool = ERC165Mock::supports_interface(OTHER_ID); + assert(supports_new_interface, 'Should support new interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic] +fn test_register_invalid_interface() { + ERC165Mock::register_interface(INVALID_ID); +} From be1e9dfdab63ed4e890ff013fb338bdb1776010d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Tue, 7 Mar 2023 16:21:25 -0300 Subject: [PATCH 029/124] clean up python project. ready for rust/cairo1 --- .gitattributes | 2 +- .gitignore | 5 + MANIFEST.in | 1 - pyproject.toml | 8 - scripts/update_version.py | 33 - setup.cfg | 37 - setup.py | 13 - src/openzeppelin/__init__.py | 11 - .../access/accesscontrol/IAccessControl.cairo | 22 - .../access/accesscontrol/library.cairo | 154 --- src/openzeppelin/access/ownable/library.cairo | 89 -- src/openzeppelin/account/IAccount.cairo | 45 - src/openzeppelin/account/library.cairo | 260 ----- .../account/presets/Account.cairo | 147 --- .../account/presets/AddressRegistry.cairo | 27 - .../account/presets/EthAccount.cairo | 146 --- .../introspection/erc165/IERC165.cairo | 10 - .../introspection/erc165/library.cairo | 38 - .../security/initializable/library.cairo | 28 - .../security/pausable/library.cairo | 70 -- .../security/reentrancyguard/library.cairo | 27 - .../security/safemath/library.cairo | 103 -- src/openzeppelin/token/erc1155/IERC1155.cairo | 56 -- .../token/erc1155/IERC1155MetadataURI.cairo | 50 - .../token/erc1155/IERC1155Receiver.cairo | 36 - src/openzeppelin/token/erc1155/library.cairo | 602 ------------ .../presets/ERC1155MintableBurnable.cairo | 159 --- .../erc1155/presets/utils/ERC1155Holder.cairo | 51 - .../token/erc20/cairo_project.toml | 2 - src/openzeppelin/token/erc20/erc20.cairo | 188 ---- src/openzeppelin/token/erc20/lib.cairo | 16 - src/openzeppelin/token/erc20/tests.cairo | 1 - .../token/erc20/tests/test_erc20.cairo | 435 --------- src/openzeppelin/token/erc721/IERC721.cairo | 38 - .../token/erc721/IERC721Metadata.cairo | 49 - .../token/erc721/IERC721Receiver.cairo | 18 - .../erc721/enumerable/IERC721Enumerable.cairo | 49 - .../token/erc721/enumerable/library.cairo | 201 ---- .../ERC721EnumerableMintableBurnable.cairo | 187 ---- src/openzeppelin/token/erc721/library.cairo | 471 --------- .../presets/ERC721MintableBurnable.cairo | 161 --- .../presets/ERC721MintablePausable.cairo | 179 ---- .../erc721/presets/utils/ERC721Holder.cairo | 31 - src/openzeppelin/upgrades/library.cairo | 113 --- src/openzeppelin/upgrades/presets/Proxy.cairo | 73 -- .../utils/constants/library.cairo | 49 - .../utils/presets/UniversalDeployer.cairo | 72 -- tests/access/OwnableBaseSuite.py | 65 -- tests/access/test_AccessControl.py | 231 ----- tests/access/test_Ownable.py | 63 -- tests/account/test_Account.py | 243 ----- tests/account/test_AddressRegistry.py | 58 -- tests/account/test_EthAccount.py | 240 ----- tests/conftest.py | 6 - tests/introspection/test_ERC165.py | 68 -- tests/mocks/AccessControl.cairo | 71 -- tests/mocks/AccountReentrancy.cairo | 40 - tests/mocks/ERC1155Mock.cairo | 34 - tests/mocks/ERC165.cairo | 22 - tests/mocks/ERC721SafeMintableMock.cairo | 162 --- tests/mocks/Initializable.cairo | 18 - tests/mocks/Ownable.cairo | 41 - tests/mocks/Pausable.cairo | 65 -- tests/mocks/ProxiableImplementation.cairo | 60 -- tests/mocks/ReentrancyAttackerMock.cairo | 19 - tests/mocks/ReentrancyMock.cairo | 111 --- tests/mocks/SafeMathMock.cairo | 33 - tests/mocks/UpgradesMockV1.cairo | 66 -- tests/mocks/UpgradesMockV2.cairo | 93 -- tests/security/test_initializable.py | 24 - tests/security/test_pausable.py | 146 --- tests/security/test_reentrancy.py | 60 -- tests/security/test_safemath.py | 206 ---- tests/signers.py | 215 ---- tests/test_signers.py | 72 -- tests/token/erc1155/ERC1155BaseSuite.py | 811 --------------- tests/token/erc1155/test_ERC1155Internals.py | 67 -- .../erc1155/test_ERC1155MintableBurnable.py | 723 -------------- tests/token/erc20/ERC20BaseSuite.py | 714 -------------- tests/token/erc20/test_ERC20.py | 54 - tests/token/erc20/test_ERC20Burnable.py | 216 ---- tests/token/erc20/test_ERC20Mintable.py | 152 --- tests/token/erc20/test_ERC20Pausable.py | 194 ---- tests/token/erc20/test_ERC20Upgradeable.py | 179 ---- tests/token/erc721/ERC721BaseSuite.py | 924 ------------------ .../test_ERC721EnumerableMintableBurnable.py | 514 ---------- .../erc721/test_ERC721MintableBurnable.py | 279 ------ .../erc721/test_ERC721MintablePausable.py | 314 ------ .../erc721/test_ERC721SafeMintableMock.py | 231 ----- tests/upgrades/test_Proxy.py | 167 ---- tests/upgrades/test_upgrades.py | 368 ------- tests/utils.py | 154 --- tests/utils/test_UniversalDeployer.py | 102 -- tox.ini | 63 -- 94 files changed, 6 insertions(+), 13315 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 pyproject.toml delete mode 100644 scripts/update_version.py delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 src/openzeppelin/__init__.py delete mode 100644 src/openzeppelin/access/accesscontrol/IAccessControl.cairo delete mode 100644 src/openzeppelin/access/accesscontrol/library.cairo delete mode 100644 src/openzeppelin/access/ownable/library.cairo delete mode 100644 src/openzeppelin/account/IAccount.cairo delete mode 100644 src/openzeppelin/account/library.cairo delete mode 100644 src/openzeppelin/account/presets/Account.cairo delete mode 100644 src/openzeppelin/account/presets/AddressRegistry.cairo delete mode 100644 src/openzeppelin/account/presets/EthAccount.cairo delete mode 100644 src/openzeppelin/introspection/erc165/IERC165.cairo delete mode 100644 src/openzeppelin/introspection/erc165/library.cairo delete mode 100644 src/openzeppelin/security/initializable/library.cairo delete mode 100644 src/openzeppelin/security/pausable/library.cairo delete mode 100644 src/openzeppelin/security/reentrancyguard/library.cairo delete mode 100644 src/openzeppelin/security/safemath/library.cairo delete mode 100644 src/openzeppelin/token/erc1155/IERC1155.cairo delete mode 100644 src/openzeppelin/token/erc1155/IERC1155MetadataURI.cairo delete mode 100644 src/openzeppelin/token/erc1155/IERC1155Receiver.cairo delete mode 100644 src/openzeppelin/token/erc1155/library.cairo delete mode 100644 src/openzeppelin/token/erc1155/presets/ERC1155MintableBurnable.cairo delete mode 100644 src/openzeppelin/token/erc1155/presets/utils/ERC1155Holder.cairo delete mode 100644 src/openzeppelin/token/erc20/cairo_project.toml delete mode 100644 src/openzeppelin/token/erc20/erc20.cairo delete mode 100644 src/openzeppelin/token/erc20/lib.cairo delete mode 100644 src/openzeppelin/token/erc20/tests.cairo delete mode 100644 src/openzeppelin/token/erc20/tests/test_erc20.cairo delete mode 100644 src/openzeppelin/token/erc721/IERC721.cairo delete mode 100644 src/openzeppelin/token/erc721/IERC721Metadata.cairo delete mode 100644 src/openzeppelin/token/erc721/IERC721Receiver.cairo delete mode 100644 src/openzeppelin/token/erc721/enumerable/IERC721Enumerable.cairo delete mode 100644 src/openzeppelin/token/erc721/enumerable/library.cairo delete mode 100644 src/openzeppelin/token/erc721/enumerable/presets/ERC721EnumerableMintableBurnable.cairo delete mode 100644 src/openzeppelin/token/erc721/library.cairo delete mode 100644 src/openzeppelin/token/erc721/presets/ERC721MintableBurnable.cairo delete mode 100644 src/openzeppelin/token/erc721/presets/ERC721MintablePausable.cairo delete mode 100644 src/openzeppelin/token/erc721/presets/utils/ERC721Holder.cairo delete mode 100644 src/openzeppelin/upgrades/library.cairo delete mode 100644 src/openzeppelin/upgrades/presets/Proxy.cairo delete mode 100644 src/openzeppelin/utils/constants/library.cairo delete mode 100644 src/openzeppelin/utils/presets/UniversalDeployer.cairo delete mode 100644 tests/access/OwnableBaseSuite.py delete mode 100644 tests/access/test_AccessControl.py delete mode 100644 tests/access/test_Ownable.py delete mode 100644 tests/account/test_Account.py delete mode 100644 tests/account/test_AddressRegistry.py delete mode 100644 tests/account/test_EthAccount.py delete mode 100644 tests/conftest.py delete mode 100644 tests/introspection/test_ERC165.py delete mode 100644 tests/mocks/AccessControl.cairo delete mode 100644 tests/mocks/AccountReentrancy.cairo delete mode 100644 tests/mocks/ERC1155Mock.cairo delete mode 100644 tests/mocks/ERC165.cairo delete mode 100644 tests/mocks/ERC721SafeMintableMock.cairo delete mode 100644 tests/mocks/Initializable.cairo delete mode 100644 tests/mocks/Ownable.cairo delete mode 100644 tests/mocks/Pausable.cairo delete mode 100644 tests/mocks/ProxiableImplementation.cairo delete mode 100644 tests/mocks/ReentrancyAttackerMock.cairo delete mode 100644 tests/mocks/ReentrancyMock.cairo delete mode 100644 tests/mocks/SafeMathMock.cairo delete mode 100644 tests/mocks/UpgradesMockV1.cairo delete mode 100644 tests/mocks/UpgradesMockV2.cairo delete mode 100644 tests/security/test_initializable.py delete mode 100644 tests/security/test_pausable.py delete mode 100644 tests/security/test_reentrancy.py delete mode 100644 tests/security/test_safemath.py delete mode 100644 tests/signers.py delete mode 100644 tests/test_signers.py delete mode 100644 tests/token/erc1155/ERC1155BaseSuite.py delete mode 100644 tests/token/erc1155/test_ERC1155Internals.py delete mode 100644 tests/token/erc1155/test_ERC1155MintableBurnable.py delete mode 100644 tests/token/erc20/ERC20BaseSuite.py delete mode 100644 tests/token/erc20/test_ERC20.py delete mode 100644 tests/token/erc20/test_ERC20Burnable.py delete mode 100644 tests/token/erc20/test_ERC20Mintable.py delete mode 100644 tests/token/erc20/test_ERC20Pausable.py delete mode 100644 tests/token/erc20/test_ERC20Upgradeable.py delete mode 100644 tests/token/erc721/ERC721BaseSuite.py delete mode 100644 tests/token/erc721/test_ERC721EnumerableMintableBurnable.py delete mode 100644 tests/token/erc721/test_ERC721MintableBurnable.py delete mode 100644 tests/token/erc721/test_ERC721MintablePausable.py delete mode 100644 tests/token/erc721/test_ERC721SafeMintableMock.py delete mode 100644 tests/upgrades/test_Proxy.py delete mode 100644 tests/upgrades/test_upgrades.py delete mode 100644 tests/utils.py delete mode 100644 tests/utils/test_UniversalDeployer.py delete mode 100644 tox.ini diff --git a/.gitattributes b/.gitattributes index 039e8bc61..5ab9b291a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -*.cairo linguist-language=python +*.cairo linguist-language=rust diff --git a/.gitignore b/.gitignore index 984c53af2..73cda39c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,9 @@ artifacts/ +.DS_Store + +# Cairo 1 + +corelib/ # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 90ec14aba..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -recursive-include src/ *.cairo diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 2c63dbb2b..000000000 --- a/pyproject.toml +++ /dev/null @@ -1,8 +0,0 @@ -[build-system] -# AVOID CHANGING REQUIRES: IT WILL BE UPDATED BY PYSCAFFOLD! -requires = ["setuptools>=46.1.0", "setuptools_scm[toml]>=5", "wheel"] -build-backend = "setuptools.build_meta" - -[tool.setuptools_scm] -# See configuration details in https://github.com/pypa/setuptools_scm -version_scheme = "no-guess-dev" diff --git a/scripts/update_version.py b/scripts/update_version.py deleted file mode 100644 index b48aebb24..000000000 --- a/scripts/update_version.py +++ /dev/null @@ -1,33 +0,0 @@ -import fileinput -import itertools -import sys -from pathlib import Path - -CURRENT_VERSION = "v0.6.1" -OTHER_PATHS = ["docs/antora.yml", "README.md"] - - -def main(): - new_version = str(sys.argv[1]) - src_path = Path("src") - docs_path = Path("docs") - for p in itertools.chain( - src_path.glob("**/*.cairo"), - docs_path.glob("**/*.adoc"), OTHER_PATHS): - _update_version(p, new_version) - _update_version("scripts/update_version.py", new_version) - - -def _update_version(path, version): - with fileinput.input(path, inplace=True) as file: - for line in file: - old, new = CURRENT_VERSION, version - if path in OTHER_PATHS: - old = old.strip("v") - new = new.strip("v") - new_line = line.replace(old, new) - print(new_line, end="") - - -if __name__ == "__main__": - main() diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index f2f12ebb3..000000000 --- a/setup.cfg +++ /dev/null @@ -1,37 +0,0 @@ -[metadata] -name = openzeppelin-cairo-contracts -version = attr: openzeppelin.__version__ -description = Library for secure smart contract development written in Cairo -author = OpenZeppelin Community -author_email = maintainers@openzeppelin.org -license = MIT -long_description = file: README.md -long_description_content_type = text/markdown; charset=UTF-8 -url = https://github.com/OpenZeppelin/cairo-contracts -platforms = any -classifiers = - Operating System :: OS Independent - -[options] -zip_safe = False -packages = find_namespace: -include_package_data = True -package_dir = - =src - -install_requires = - importlib-metadata>=4.0 - -[options.packages.find] -where = src -exclude = - tests - -[options.package_data] -openzeppelin = "*.cairo" - -[options.extras_require] -testing = - setuptools - tox - pytest diff --git a/setup.py b/setup.py deleted file mode 100644 index 7a781f058..000000000 --- a/setup.py +++ /dev/null @@ -1,13 +0,0 @@ -from setuptools import setup - -if __name__ == "__main__": - try: - setup(use_scm_version={"version_scheme": "no-guess-dev"}) - except: # noqa - print( - "\n\nAn error occurred while building the project, " - "please ensure you have the most updated version of setuptools, " - "setuptools_scm and wheel with:\n" - " pip install -U setuptools setuptools_scm wheel\n\n" - ) - raise diff --git a/src/openzeppelin/__init__.py b/src/openzeppelin/__init__.py deleted file mode 100644 index 3ad9240c2..000000000 --- a/src/openzeppelin/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -"""StarkNet/Cairo development toolbelt.""" - -try: - from importlib import metadata as importlib_metadata -except ImportError: - import importlib_metadata - -try: - __version__ = importlib_metadata.version("openzeppelin-cairo-contracts") -except importlib_metadata.PackageNotFoundError: - __version__ = None diff --git a/src/openzeppelin/access/accesscontrol/IAccessControl.cairo b/src/openzeppelin/access/accesscontrol/IAccessControl.cairo deleted file mode 100644 index d45bf8f72..000000000 --- a/src/openzeppelin/access/accesscontrol/IAccessControl.cairo +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (access/accesscontrol/IAccessControl.cairo) - -%lang starknet - -@contract_interface -namespace IAccessControl { - func hasRole(role: felt, account: felt) -> (hasRole: felt) { - } - - func getRoleAdmin(role: felt) -> (admin: felt) { - } - - func grantRole(role: felt, account: felt) { - } - - func revokeRole(role: felt, account: felt) { - } - - func renounceRole(role: felt, account: felt) { - } -} diff --git a/src/openzeppelin/access/accesscontrol/library.cairo b/src/openzeppelin/access/accesscontrol/library.cairo deleted file mode 100644 index 2571877a9..000000000 --- a/src/openzeppelin/access/accesscontrol/library.cairo +++ /dev/null @@ -1,154 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (access/accesscontrol/library.cairo) - -%lang starknet - -from starkware.starknet.common.syscalls import get_caller_address -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.bool import TRUE, FALSE - -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.utils.constants.library import IACCESSCONTROL_ID - -// -// Events -// - -@event -func RoleGranted(role: felt, account: felt, sender: felt) { -} - -@event -func RoleRevoked(role: felt, account: felt, sender: felt) { -} - -@event -func RoleAdminChanged(role: felt, previousAdminRole: felt, newAdminRole: felt) { -} - -// -// Storage -// - -@storage_var -func AccessControl_role_admin(role: felt) -> (admin: felt) { -} - -@storage_var -func AccessControl_role_member(role: felt, account: felt) -> (has_role: felt) { -} - -namespace AccessControl { - // - // Initializer - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - ERC165.register_interface(IACCESSCONTROL_ID); - return (); - } - - // - // Modifier - // - - func assert_only_role{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt - ) { - alloc_locals; - let (caller) = get_caller_address(); - let (authorized) = has_role(role, caller); - with_attr error_message("AccessControl: caller is missing role {role}") { - assert authorized = TRUE; - } - return (); - } - - // - // Getters - // - - func has_role{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt - ) -> (has_role: felt) { - return AccessControl_role_member.read(role, user); - } - - func get_role_admin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt - ) -> (admin: felt) { - return AccessControl_role_admin.read(role); - } - - // - // Externals - // - - func grant_role{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt - ) { - let (admin: felt) = get_role_admin(role); - assert_only_role(admin); - _grant_role(role, user); - return (); - } - - func revoke_role{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt - ) { - let (admin: felt) = get_role_admin(role); - assert_only_role(admin); - _revoke_role(role, user); - return (); - } - - func renounce_role{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt - ) { - let (caller: felt) = get_caller_address(); - with_attr error_message("AccessControl: can only renounce roles for self") { - assert user = caller; - } - _revoke_role(role, user); - return (); - } - - // - // Unprotected - // - - func _grant_role{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt - ) { - let (user_has_role: felt) = has_role(role, user); - if (user_has_role == FALSE) { - let (caller: felt) = get_caller_address(); - AccessControl_role_member.write(role, user, TRUE); - RoleGranted.emit(role, user, caller); - return (); - } - return (); - } - - func _revoke_role{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt - ) { - let (user_has_role: felt) = has_role(role, user); - if (user_has_role == TRUE) { - let (caller: felt) = get_caller_address(); - AccessControl_role_member.write(role, user, FALSE); - RoleRevoked.emit(role, user, caller); - return (); - } - return (); - } - - func _set_role_admin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, admin_role: felt - ) { - let (previous_admin_role: felt) = get_role_admin(role); - AccessControl_role_admin.write(role, admin_role); - RoleAdminChanged.emit(role, previous_admin_role, admin_role); - return (); - } -} diff --git a/src/openzeppelin/access/ownable/library.cairo b/src/openzeppelin/access/ownable/library.cairo deleted file mode 100644 index 36f84cf98..000000000 --- a/src/openzeppelin/access/ownable/library.cairo +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (access/ownable/library.cairo) - -%lang starknet - -from starkware.starknet.common.syscalls import get_caller_address -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.math import assert_not_zero - -// -// Events -// - -@event -func OwnershipTransferred(previousOwner: felt, newOwner: felt) { -} - -// -// Storage -// - -@storage_var -func Ownable_owner() -> (owner: felt) { -} - -namespace Ownable { - // - // Initializer - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) { - _transfer_ownership(owner); - return (); - } - - // - // Guards - // - - func assert_only_owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - let (owner) = Ownable.owner(); - let (caller) = get_caller_address(); - with_attr error_message("Ownable: caller is the zero address") { - assert_not_zero(caller); - } - with_attr error_message("Ownable: caller is not the owner") { - assert owner = caller; - } - return (); - } - - // - // Public - // - - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable_owner.read(); - } - - func transfer_ownership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_owner: felt - ) { - with_attr error_message("Ownable: new owner is the zero address") { - assert_not_zero(new_owner); - } - assert_only_owner(); - _transfer_ownership(new_owner); - return (); - } - - func renounce_ownership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - assert_only_owner(); - _transfer_ownership(0); - return (); - } - - // - // Internal - // - - func _transfer_ownership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_owner: felt - ) { - let (previous_owner: felt) = Ownable.owner(); - Ownable_owner.write(new_owner); - OwnershipTransferred.emit(previous_owner, new_owner); - return (); - } -} diff --git a/src/openzeppelin/account/IAccount.cairo b/src/openzeppelin/account/IAccount.cairo deleted file mode 100644 index 8a22d38c1..000000000 --- a/src/openzeppelin/account/IAccount.cairo +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/IAccount.cairo) - -%lang starknet - -from openzeppelin.account.library import AccountCallArray - -@contract_interface -namespace IAccount { - func isValidSignature( - hash: felt, - signature_len: felt, - signature: felt* - ) -> (isValid: felt) { - } - - func __validate__( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* - ) { - } - - // Parameter temporarily named `cls_hash` instead of `class_hash` (expected). - // See https://github.com/starkware-libs/cairo-lang/issues/100 for details. - func __validate_declare__(cls_hash: felt) { - } - - func __execute__( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* - ) -> ( - response_len: felt, - response: felt* - ) { - } - - // ERC165 - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/account/library.cairo b/src/openzeppelin/account/library.cairo deleted file mode 100644 index 6723032eb..000000000 --- a/src/openzeppelin/account/library.cairo +++ /dev/null @@ -1,260 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/library.cairo) - -%lang starknet - -from starkware.cairo.common.registers import get_fp_and_pc -from starkware.cairo.common.signature import verify_ecdsa_signature -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin -from starkware.cairo.common.alloc import alloc -from starkware.cairo.common.uint256 import Uint256 -from starkware.cairo.common.memcpy import memcpy -from starkware.cairo.common.math import split_felt -from starkware.cairo.common.math_cmp import is_le_felt -from starkware.cairo.common.bool import TRUE, FALSE -from starkware.starknet.common.syscalls import ( - call_contract, - get_caller_address, - get_contract_address, - get_tx_info -) -from starkware.cairo.common.cairo_secp.signature import ( - finalize_keccak, - verify_eth_signature_uint256 -) -from openzeppelin.utils.constants.library import ( - IACCOUNT_ID, - IERC165_ID, - TRANSACTION_VERSION -) - -// -// Storage -// - -@storage_var -func Account_public_key() -> (public_key: felt) { -} - -// -// Structs -// - -struct Call { - to: felt, - selector: felt, - calldata_len: felt, - calldata: felt*, -} - -// Tmp struct introduced while we wait for Cairo -// to support passing `[AccountCall]` to __execute__ -struct AccountCallArray { - to: felt, - selector: felt, - data_offset: felt, - data_len: felt, -} - -namespace Account { - // - // Initializer - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - _public_key: felt - ) { - Account_public_key.write(_public_key); - return (); - } - - // - // Guards - // - - func assert_only_self{syscall_ptr: felt*}() { - let (self) = get_contract_address(); - let (caller) = get_caller_address(); - with_attr error_message("Account: caller is not this account") { - assert self = caller; - } - return (); - } - - // - // Getters - // - - func get_public_key{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - public_key: felt - ) { - return Account_public_key.read(); - } - - func supports_interface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(interface_id: felt) -> ( - success: felt - ) { - if (interface_id == IERC165_ID) { - return (success=TRUE); - } - if (interface_id == IACCOUNT_ID) { - return (success=TRUE); - } - return (success=FALSE); - } - - // - // Setters - // - - func set_public_key{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_public_key: felt - ) { - assert_only_self(); - Account_public_key.write(new_public_key); - return (); - } - - // - // Business logic - // - - func is_valid_signature{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr, - }(hash: felt, signature_len: felt, signature: felt*) -> (is_valid: felt) { - let (_public_key) = Account_public_key.read(); - - // This interface expects a signature pointer and length to make - // no assumption about signature validation schemes. - // But this implementation does, and it expects a (sig_r, sig_s) pair. - let sig_r = signature[0]; - let sig_s = signature[1]; - - verify_ecdsa_signature( - message=hash, public_key=_public_key, signature_r=sig_r, signature_s=sig_s - ); - - return (is_valid=TRUE); - } - - func is_valid_eth_signature{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, - }(hash: felt, signature_len: felt, signature: felt*) -> (is_valid: felt) { - alloc_locals; - let (_public_key) = get_public_key(); - let (__fp__, _) = get_fp_and_pc(); - - // This interface expects a signature pointer and length to make - // no assumption about signature validation schemes. - // But this implementation does, and it expects a the sig_v, sig_r, - // sig_s, and hash elements. - let sig_v: felt = signature[0]; - let sig_r: Uint256 = Uint256(low=signature[1], high=signature[2]); - let sig_s: Uint256 = Uint256(low=signature[3], high=signature[4]); - let (high, low) = split_felt(hash); - let msg_hash: Uint256 = Uint256(low=low, high=high); - - let (keccak_ptr: felt*) = alloc(); - local keccak_ptr_start: felt* = keccak_ptr; - - with keccak_ptr { - verify_eth_signature_uint256( - msg_hash=msg_hash, r=sig_r, s=sig_s, v=sig_v, eth_address=_public_key - ); - } - // Required to ensure sequencers cannot spoof validation check. - finalize_keccak(keccak_ptr_start=keccak_ptr_start, keccak_ptr_end=keccak_ptr); - - return (is_valid=TRUE); - } - - func execute{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, - }(call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt*) -> ( - response_len: felt, response: felt* - ) { - alloc_locals; - - let (tx_info) = get_tx_info(); - // Disallow deprecated tx versions - with_attr error_message("Account: deprecated tx version") { - assert is_le_felt(TRANSACTION_VERSION, tx_info.version) = TRUE; - } - - // Assert not a reentrant call - let (caller) = get_caller_address(); - with_attr error_message("Account: reentrant call") { - assert caller = 0; - } - - // TMP: Convert `AccountCallArray` to 'Call'. - let (calls: Call*) = alloc(); - _from_call_array_to_call(call_array_len, call_array, calldata, calls); - let calls_len = call_array_len; - - // Execute call - let (response: felt*) = alloc(); - let (response_len) = _execute_list(calls_len, calls, response); - - return (response_len=response_len, response=response); - } - - func _execute_list{syscall_ptr: felt*}(calls_len: felt, calls: Call*, response: felt*) -> ( - response_len: felt - ) { - alloc_locals; - - // if no more calls - if (calls_len == 0) { - return (response_len=0); - } - - // do the current call - let this_call: Call = [calls]; - let res = call_contract( - contract_address=this_call.to, - function_selector=this_call.selector, - calldata_size=this_call.calldata_len, - calldata=this_call.calldata, - ); - // copy the result in response - memcpy(response, res.retdata, res.retdata_size); - // do the next calls recursively - let (response_len) = _execute_list( - calls_len - 1, calls + Call.SIZE, response + res.retdata_size - ); - return (response_len=response_len + res.retdata_size); - } - - func _from_call_array_to_call{syscall_ptr: felt*}( - call_array_len: felt, call_array: AccountCallArray*, calldata: felt*, calls: Call* - ) { - // if no more calls - if (call_array_len == 0) { - return (); - } - - // parse the current call - assert [calls] = Call( - to=[call_array].to, - selector=[call_array].selector, - calldata_len=[call_array].data_len, - calldata=calldata + [call_array].data_offset - ); - // parse the remaining calls recursively - _from_call_array_to_call( - call_array_len - 1, call_array + AccountCallArray.SIZE, calldata, calls + Call.SIZE - ); - return (); - } -} diff --git a/src/openzeppelin/account/presets/Account.cairo b/src/openzeppelin/account/presets/Account.cairo deleted file mode 100644 index 23c10199b..000000000 --- a/src/openzeppelin/account/presets/Account.cairo +++ /dev/null @@ -1,147 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/presets/Account.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin -from starkware.starknet.common.syscalls import get_tx_info - -from openzeppelin.account.library import Account, AccountCallArray - - -// -// Constructor -// - -@constructor -func constructor{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -}(publicKey: felt) { - Account.initializer(publicKey); - return (); -} - -// -// Getters -// - -@view -func getPublicKey{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} () -> (publicKey: felt) { - let (publicKey: felt) = Account.get_public_key(); - return (publicKey=publicKey); -} - -@view -func supportsInterface{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} (interfaceId: felt) -> (success: felt) { - return Account.supports_interface(interfaceId); -} - -// -// Setters -// - -@external -func setPublicKey{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} (newPublicKey: felt) { - Account.set_public_key(newPublicKey); - return (); -} - -// -// Business logic -// - -@view -func isValidSignature{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr -}( - hash: felt, - signature_len: felt, - signature: felt* -) -> (isValid: felt) { - let (isValid: felt) = Account.is_valid_signature(hash, signature_len, signature); - return (isValid=isValid); -} - -@external -func __validate__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr -}( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* -) { - let (tx_info) = get_tx_info(); - Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __validate_declare__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr -} (class_hash: felt) { - let (tx_info) = get_tx_info(); - Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __validate_deploy__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr -} ( - class_hash: felt, - salt: felt, - publicKey: felt -) { - let (tx_info) = get_tx_info(); - Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __execute__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -}( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* -) -> ( - response_len: felt, - response: felt* -) { - let (response_len, response) = Account.execute( - call_array_len, call_array, calldata_len, calldata - ); - return (response_len, response); -} diff --git a/src/openzeppelin/account/presets/AddressRegistry.cairo b/src/openzeppelin/account/presets/AddressRegistry.cairo deleted file mode 100644 index 7076bd25a..000000000 --- a/src/openzeppelin/account/presets/AddressRegistry.cairo +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/presets/AddressRegistry.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.starknet.common.syscalls import get_caller_address - -@storage_var -func L1_address(L2_address: felt) -> (address: felt) { -} - -@external -func get_L1_address{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - L2_address: felt -) -> (address: felt) { - return L1_address.read(L2_address); -} - -@external -func set_L1_address{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_L1_address: felt -) { - let (caller) = get_caller_address(); - L1_address.write(caller, new_L1_address); - return (); -} diff --git a/src/openzeppelin/account/presets/EthAccount.cairo b/src/openzeppelin/account/presets/EthAccount.cairo deleted file mode 100644 index 50277380d..000000000 --- a/src/openzeppelin/account/presets/EthAccount.cairo +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/presets/EthAccount.cairo) - -%lang starknet -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin -from starkware.starknet.common.syscalls import get_tx_info - -from openzeppelin.account.library import Account, AccountCallArray - -// -// Constructor -// - -@constructor -func constructor{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -}(ethAddress: felt) { - Account.initializer(ethAddress); - return (); -} - -// -// Getters -// - -@view -func getEthAddress{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} () -> (ethAddress: felt) { - let (ethAddress: felt) = Account.get_public_key(); - return (ethAddress=ethAddress); -} - -@view -func supportsInterface{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} (interfaceId: felt) -> (success: felt) { - return Account.supports_interface(interfaceId); -} - -// -// Setters -// - -@external -func setEthAddress{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} (newEthAddress: felt) { - Account.set_public_key(newEthAddress); - return (); -} - -// -// Business logic -// - -@view -func isValidSignature{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -}( - hash: felt, - signature_len: felt, - signature: felt* -) -> (isValid: felt) { - let (isValid) = Account.is_valid_eth_signature(hash, signature_len, signature); - return (isValid=isValid); -} - -@external -func __validate__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -}( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* -) { - let (tx_info) = get_tx_info(); - Account.is_valid_eth_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __validate_declare__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -} (class_hash: felt) { - let (tx_info) = get_tx_info(); - Account.is_valid_eth_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - - -@external -func __validate_deploy__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr -} ( - class_hash: felt, - salt: felt, - ethAddress: felt -) { - let (tx_info) = get_tx_info(); - Account.is_valid_eth_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __execute__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -}( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* -) -> ( - response_len: felt, - response: felt* -) { - let (response_len, response) = Account.execute( - call_array_len, call_array, calldata_len, calldata - ); - return (response_len, response); -} diff --git a/src/openzeppelin/introspection/erc165/IERC165.cairo b/src/openzeppelin/introspection/erc165/IERC165.cairo deleted file mode 100644 index d34be3a33..000000000 --- a/src/openzeppelin/introspection/erc165/IERC165.cairo +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (introspection/erc165/IERC165.cairo) - -%lang starknet - -@contract_interface -namespace IERC165 { - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/introspection/erc165/library.cairo b/src/openzeppelin/introspection/erc165/library.cairo deleted file mode 100644 index 8073cef40..000000000 --- a/src/openzeppelin/introspection/erc165/library.cairo +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (introspection/erc165/library.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.math import assert_not_equal -from starkware.cairo.common.bool import TRUE - -from openzeppelin.utils.constants.library import INVALID_ID, IERC165_ID - -@storage_var -func ERC165_supported_interfaces(interface_id: felt) -> (is_supported: felt) { -} - -namespace ERC165 { - func supports_interface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interface_id: felt - ) -> (success: felt) { - if (interface_id == IERC165_ID) { - return (success=TRUE); - } - - // Checks interface registry - let (is_supported) = ERC165_supported_interfaces.read(interface_id); - return (success=is_supported); - } - - func register_interface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interface_id: felt - ) { - with_attr error_message("ERC165: invalid interface id") { - assert_not_equal(interface_id, INVALID_ID); - } - ERC165_supported_interfaces.write(interface_id, TRUE); - return (); - } -} diff --git a/src/openzeppelin/security/initializable/library.cairo b/src/openzeppelin/security/initializable/library.cairo deleted file mode 100644 index e1af27aea..000000000 --- a/src/openzeppelin/security/initializable/library.cairo +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (security/initializable/library.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.bool import TRUE, FALSE - -@storage_var -func Initializable_initialized() -> (initialized: felt) { -} - -namespace Initializable { - func initialized{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - felt - ) { - return Initializable_initialized.read(); - } - - func initialize{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - let (is_initialized) = Initializable_initialized.read(); - with_attr error_message("Initializable: contract already initialized") { - assert is_initialized = FALSE; - } - Initializable_initialized.write(TRUE); - return (); - } -} diff --git a/src/openzeppelin/security/pausable/library.cairo b/src/openzeppelin/security/pausable/library.cairo deleted file mode 100644 index fecec4954..000000000 --- a/src/openzeppelin/security/pausable/library.cairo +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (security/pausable/library.cairo) - -%lang starknet - -from starkware.starknet.common.syscalls import get_caller_address -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.bool import TRUE, FALSE - -// -// Storage -// - -@storage_var -func Pausable_paused() -> (paused: felt) { -} - -// -// Events -// - -@event -func Paused(account: felt) { -} - -@event -func Unpaused(account: felt) { -} - -namespace Pausable { - func is_paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - paused: felt - ) { - return Pausable_paused.read(); - } - - func assert_not_paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - let (is_paused) = Pausable_paused.read(); - with_attr error_message("Pausable: paused") { - assert is_paused = FALSE; - } - return (); - } - - func assert_paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - let (is_paused) = Pausable_paused.read(); - with_attr error_message("Pausable: not paused") { - assert is_paused = TRUE; - } - return (); - } - - func _pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - assert_not_paused(); - Pausable_paused.write(TRUE); - - let (account) = get_caller_address(); - Paused.emit(account); - return (); - } - - func _unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - assert_paused(); - Pausable_paused.write(FALSE); - - let (account) = get_caller_address(); - Unpaused.emit(account); - return (); - } -} diff --git a/src/openzeppelin/security/reentrancyguard/library.cairo b/src/openzeppelin/security/reentrancyguard/library.cairo deleted file mode 100644 index 84914aee7..000000000 --- a/src/openzeppelin/security/reentrancyguard/library.cairo +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (security/reentrancyguard/library.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.bool import TRUE, FALSE - -@storage_var -func ReentrancyGuard_entered() -> (entered: felt) { -} - -namespace ReentrancyGuard { - func start{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - let (has_entered) = ReentrancyGuard_entered.read(); - with_attr error_message("ReentrancyGuard: reentrant call") { - assert has_entered = FALSE; - } - ReentrancyGuard_entered.write(TRUE); - return (); - } - - func end{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - ReentrancyGuard_entered.write(FALSE); - return (); - } -} diff --git a/src/openzeppelin/security/safemath/library.cairo b/src/openzeppelin/security/safemath/library.cairo deleted file mode 100644 index c31c1b623..000000000 --- a/src/openzeppelin/security/safemath/library.cairo +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (security/safemath/library.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.bool import TRUE, FALSE -from starkware.cairo.common.uint256 import ( - Uint256, - uint256_check, - uint256_add, - uint256_sub, - uint256_mul, - uint256_unsigned_div_rem, - uint256_le, - uint256_lt, - uint256_eq, -) - -namespace SafeUint256 { - // Adds two integers. - // Reverts if the sum overflows. - func add{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256) { - uint256_check(a); - uint256_check(b); - let (c: Uint256, is_overflow) = uint256_add(a, b); - with_attr error_message("SafeUint256: addition overflow") { - assert is_overflow = FALSE; - } - return (c=c); - } - - // Subtracts two integers. - // Reverts if subtrahend (`b`) is greater than minuend (`a`). - func sub_le{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256) { - alloc_locals; - uint256_check(a); - uint256_check(b); - let (is_le) = uint256_le(b, a); - with_attr error_message("SafeUint256: subtraction overflow") { - assert is_le = TRUE; - } - let (c: Uint256) = uint256_sub(a, b); - return (c=c); - } - - // Subtracts two integers. - // Reverts if subtrahend (`b`) is greater than or equal to minuend (`a`). - func sub_lt{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256) { - alloc_locals; - uint256_check(a); - uint256_check(b); - - let (is_lt) = uint256_lt(b, a); - with_attr error_message("SafeUint256: subtraction overflow or the difference equals zero") { - assert is_lt = TRUE; - } - let (c: Uint256) = uint256_sub(a, b); - return (c=c); - } - - // Multiplies two integers. - // Reverts if product is greater than 2^256. - func mul{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256) { - alloc_locals; - uint256_check(a); - uint256_check(b); - let (a_zero) = uint256_eq(a, Uint256(0, 0)); - if (a_zero == TRUE) { - return (c=a); - } - - let (b_zero) = uint256_eq(b, Uint256(0, 0)); - if (b_zero == TRUE) { - return (c=b); - } - - let (c: Uint256, overflow: Uint256) = uint256_mul(a, b); - with_attr error_message("SafeUint256: multiplication overflow") { - assert overflow = Uint256(0, 0); - } - return (c=c); - } - - // Integer division of two numbers. Returns uint256 quotient and remainder. - // Reverts if divisor is zero as per OpenZeppelin's Solidity implementation. - // Cairo's `uint256_unsigned_div_rem` already checks: - // remainder < divisor - // quotient * divisor + remainder == dividend - func div_rem{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256, rem: Uint256) { - alloc_locals; - uint256_check(a); - uint256_check(b); - - let (is_zero) = uint256_eq(b, Uint256(0, 0)); - with_attr error_message("SafeUint256: divisor cannot be zero") { - assert is_zero = FALSE; - } - - let (c: Uint256, rem: Uint256) = uint256_unsigned_div_rem(a, b); - return (c=c, rem=rem); - } -} diff --git a/src/openzeppelin/token/erc1155/IERC1155.cairo b/src/openzeppelin/token/erc1155/IERC1155.cairo deleted file mode 100644 index 95465eb8e..000000000 --- a/src/openzeppelin/token/erc1155/IERC1155.cairo +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc1155/IERC1155.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 - -@contract_interface -namespace IERC1155 { - func balanceOf(account: felt, id: Uint256) -> (balance: Uint256) { - } - - func balanceOfBatch( - accounts_len: felt, - accounts: felt*, - ids_len: felt, - ids: Uint256* - ) -> ( - balances_len: felt, - balances: Uint256* - ) { - } - - func isApprovedForAll(account: felt, operator: felt) -> (approved: felt) { - } - - func setApprovalForAll(operator: felt, approved: felt) { - } - - func safeTransferFrom( - from_: felt, - to: felt, - id: Uint256, - value: Uint256, - data_len: felt, - data: felt* - ) { - } - - func safeBatchTransferFrom( - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, - ) { - } - - // ERC165 - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/token/erc1155/IERC1155MetadataURI.cairo b/src/openzeppelin/token/erc1155/IERC1155MetadataURI.cairo deleted file mode 100644 index 100f157dc..000000000 --- a/src/openzeppelin/token/erc1155/IERC1155MetadataURI.cairo +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc1155/IERC1155MetadataURI.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 - -@contract_interface -namespace IERC1155MetadataURI { - func uri(id: Uint256) -> (uri: felt) { - } - - // ERC1155 - - func balanceOf(account: felt, id: Uint256) -> (balance: Uint256) { - } - - func balanceOfBatch(accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*) -> ( - balances_len: felt, balances: Uint256* - ) { - } - - func isApprovedForAll(account: felt, operator: felt) -> (approved: felt) { - } - - func setApprovalForAll(operator: felt, approved: felt) { - } - - func safeTransferFrom( - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt* - ) { - } - - func safeBatchTransferFrom( - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, - ) { - } - - // ERC165 - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/token/erc1155/IERC1155Receiver.cairo b/src/openzeppelin/token/erc1155/IERC1155Receiver.cairo deleted file mode 100644 index 1466d6ba6..000000000 --- a/src/openzeppelin/token/erc1155/IERC1155Receiver.cairo +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc1155/IERC1155Receiver.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 - -@contract_interface -namespace IERC1155Receiver { - func onERC1155Received( - operator: felt, - from_: felt, - id: Uint256, - value: Uint256, - data_len: felt, - data: felt* - ) -> (selector: felt) { - } - - func onERC1155BatchReceived( - operator: felt, - from_: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, - ) -> (selector: felt) { - } - - // ERC165 - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/token/erc1155/library.cairo b/src/openzeppelin/token/erc1155/library.cairo deleted file mode 100644 index 27622e84a..000000000 --- a/src/openzeppelin/token/erc1155/library.cairo +++ /dev/null @@ -1,602 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc1155/library.cairo) - -%lang starknet - -from starkware.starknet.common.syscalls import get_caller_address -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.math import assert_not_zero, assert_not_equal -from starkware.cairo.common.alloc import alloc -from starkware.cairo.common.uint256 import Uint256, uint256_check -from starkware.cairo.common.bool import TRUE - -from openzeppelin.introspection.erc165.IERC165 import IERC165 -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.token.erc1155.IERC1155Receiver import IERC1155Receiver -from openzeppelin.security.safemath.library import SafeUint256 -from openzeppelin.utils.constants.library import ( - IERC1155_ID, - IERC1155_METADATA_ID, - IERC1155_RECEIVER_ID, - IACCOUNT_ID, - ON_ERC1155_RECEIVED_SELECTOR, - ON_ERC1155_BATCH_RECEIVED_SELECTOR, -) - -// -// Events -// - -@event -func TransferSingle( - operator: felt, - from_: felt, - to: felt, - id: Uint256, - value: Uint256 -) { -} - -@event -func TransferBatch( - operator: felt, - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, -) { -} - -@event -func ApprovalForAll(account: felt, operator: felt, approved: felt) { -} - -@event -func URI(value: felt, id: Uint256) { -} - -// -// Storage -// - -@storage_var -func ERC1155_balances(id: Uint256, account: felt) -> (balance: Uint256) { -} - -@storage_var -func ERC1155_operator_approvals(account: felt, operator: felt) -> (approved: felt) { -} - -@storage_var -func ERC1155_uri() -> (uri: felt) { -} - -namespace ERC1155 { - // - // Initializer - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(uri: felt) { - _set_uri(uri); - ERC165.register_interface(IERC1155_ID); - ERC165.register_interface(IERC1155_METADATA_ID); - return (); - } - - // - // Modifiers - // - - func assert_owner_or_approved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt - ) { - let (caller) = get_caller_address(); - if (caller == owner) { - return (); - } - let (approved) = ERC1155.is_approved_for_all(owner, caller); - with_attr error_message("ERC1155: caller is not owner nor approved") { - assert approved = TRUE; - } - return (); - } - - // - // Getters - // - - // This implementation returns the same URI for *all* token types. It relies - // on the token type ID substitution mechanism - // https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. - // - // Clients calling this function must replace the `\{id\}` substring with the - // actual token type ID. - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(id: Uint256) -> ( - uri: felt - ) { - return ERC1155_uri.read(); - } - - func balance_of{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - account: felt, id: Uint256 - ) -> (balance: Uint256) { - with_attr error_message("ERC1155: address zero is not a valid owner") { - assert_not_zero(account); - } - _check_id(id); - return ERC1155_balances.read(id, account); - } - - func balance_of_batch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256* - ) -> (balances_len: felt, balances: Uint256*) { - alloc_locals; - // Check args are equal length arrays - with_attr error_message("ERC1155: accounts and ids length mismatch") { - assert ids_len = accounts_len; - } - // Allocate memory - let (local balances: Uint256*) = alloc(); - // Call iterator - _balance_of_batch_iter(accounts_len, accounts, ids, balances); - return (accounts_len, balances); - } - - func is_approved_for_all{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - account: felt, operator: felt - ) -> (approved: felt) { - return ERC1155_operator_approvals.read(account, operator); - } - - // - // Externals - // - - func set_approval_for_all{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - operator: felt, approved: felt - ) { - let (caller) = get_caller_address(); - with_attr error_message("ERC1155: cannot approve from the zero address") { - assert_not_zero(caller); - } - _set_approval_for_all(caller, operator, approved); - return (); - } - - func safe_transfer_from{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt* - ) { - let (caller) = get_caller_address(); - with_attr error_message("ERC1155: cannot call transfer from the zero address") { - assert_not_zero(caller); - } - assert_owner_or_approved(from_); - _safe_transfer_from(from_, to, id, value, data_len, data); - return (); - } - - func safe_batch_transfer_from{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, - ) { - let (caller) = get_caller_address(); - with_attr error_message("ERC1155: cannot call transfer from the zero address") { - assert_not_zero(caller); - } - assert_owner_or_approved(from_); - _safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data); - return (); - } - - // - // Internals - // - - func _safe_transfer_from{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt* - ) { - alloc_locals; - // Validate input - with_attr error_message("ERC1155: transfer to the zero address") { - assert_not_zero(to); - } - _check_id(id); - _check_value(value); - - // Deduct from sender - let (from_balance: Uint256) = ERC1155_balances.read(id, from_); - with_attr error_message("ERC1155: insufficient balance for transfer") { - let (new_balance: Uint256) = SafeUint256.sub_le(from_balance, value); - } - ERC1155_balances.write(id, from_, new_balance); - - // Add to receiver - _add_to_receiver(id, value, to); - - // Emit events and check - let (operator) = get_caller_address(); - TransferSingle.emit(operator, from_, to, id, value); - - _do_safe_transfer_acceptance_check(operator, from_, to, id, value, data_len, data); - return (); - } - - func _safe_batch_transfer_from{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, - ) { - alloc_locals; - // Check args - with_attr error_message("ERC1155: transfer to the zero address") { - assert_not_zero(to); - } - with_attr error_message("ERC1155: ids and values length mismatch") { - assert ids_len = values_len; - } - // Recursive call - _safe_batch_transfer_from_iter(from_, to, ids_len, ids, values); - - // Emit events and check - let (operator) = get_caller_address(); - TransferBatch.emit(operator, from_, to, ids_len, ids, values_len, values); - - _do_safe_batch_transfer_acceptance_check( - operator, from_, to, ids_len, ids, values_len, values, data_len, data - ); - return (); - } - - func _mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt* - ) { - // Validate input - with_attr error_message("ERC1155: mint to the zero address") { - assert_not_zero(to); - } - _check_id(id); - _check_value(value); - - // Add to minter, check for overflow - _add_to_receiver(id, value, to); - - // Emit events and check - let (operator) = get_caller_address(); - TransferSingle.emit(operator=operator, from_=0, to=to, id=id, value=value); - _do_safe_transfer_acceptance_check( - operator=operator, from_=0, to=to, id=id, value=value, data_len=data_len, data=data - ); - return (); - } - - func _mint_batch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, - ) { - alloc_locals; - // Cannot mint to zero address - with_attr error_message("ERC1155: mint to the zero address") { - assert_not_zero(to); - } - // Check args are equal length arrays - with_attr error_message("ERC1155: ids and values length mismatch") { - assert ids_len = values_len; - } - - // Recursive call - _mint_batch_iter(to, ids_len, ids, values); - - // Emit events and check - let (operator) = get_caller_address(); - TransferBatch.emit( - operator=operator, - from_=0, - to=to, - ids_len=ids_len, - ids=ids, - values_len=values_len, - values=values, - ); - _do_safe_batch_transfer_acceptance_check( - operator=operator, - from_=0, - to=to, - ids_len=ids_len, - ids=ids, - values_len=values_len, - values=values, - data_len=data_len, - data=data, - ); - return (); - } - - func _burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, id: Uint256, value: Uint256 - ) { - alloc_locals; - // Validate input - with_attr error_message("ERC1155: burn from the zero address") { - assert_not_zero(from_); - } - _check_id(id); - _check_value(value); - - // Deduct from burner - let (from_balance: Uint256) = ERC1155_balances.read(id, from_); - with_attr error_message("ERC1155: burn value exceeds balance") { - let (new_balance: Uint256) = SafeUint256.sub_le(from_balance, value); - } - - ERC1155_balances.write(id, from_, new_balance); - - let (operator) = get_caller_address(); - TransferSingle.emit(operator=operator, from_=from_, to=0, id=id, value=value); - return (); - } - - func _burn_batch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, ids_len: felt, ids: Uint256*, values_len: felt, values: Uint256* - ) { - alloc_locals; - with_attr error_message("ERC1155: burn from the zero address") { - assert_not_zero(from_); - } - with_attr error_message("ERC1155: ids and values length mismatch") { - assert ids_len = values_len; - } - - // Recursive call - _burn_batch_iter(from_, ids_len, ids, values); - let (operator) = get_caller_address(); - TransferBatch.emit( - operator=operator, - from_=from_, - to=0, - ids_len=ids_len, - ids=ids, - values_len=values_len, - values=values, - ); - return (); - } - - func _set_approval_for_all{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, operator: felt, approved: felt - ) { - // check approved is bool - with_attr error_message("ERC1155: approval is not boolean") { - assert approved * (approved - 1) = 0; - } - - // caller/owner already checked non-0 - with_attr error_message("ERC1155: setting approval status for zero address") { - assert_not_zero(operator); - } - - with_attr error_message("ERC1155: setting approval status for self") { - assert_not_equal(owner, operator); - } - - ERC1155_operator_approvals.write(owner, operator, approved); - ApprovalForAll.emit(owner, operator, approved); - return (); - } - - func _set_uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(uri: felt) { - ERC1155_uri.write(uri); - return (); - } -} - -// -// Private -// - -func _do_safe_transfer_acceptance_check{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr -}( - operator: felt, from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt* -) { - // Confirm supports IERC1155receiver interface - let (is_supported) = IERC165.supportsInterface(to, IERC1155_RECEIVER_ID); - if (is_supported == TRUE) { - let (selector) = IERC1155Receiver.onERC1155Received( - to, operator, from_, id, value, data_len, data - ); - - // Confirm onERC1155Recieved selector returned - with_attr error_message("ERC1155: ERC1155Receiver rejected tokens") { - assert selector = ON_ERC1155_RECEIVED_SELECTOR; - } - return (); - } - - // Alternatively confirm account - let (is_account) = IERC165.supportsInterface(to, IACCOUNT_ID); - with_attr error_message("ERC1155: transfer to non-ERC1155Receiver implementer") { - assert is_account = TRUE; - } - return (); -} - -func _do_safe_batch_transfer_acceptance_check{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr -}( - operator: felt, - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, -) { - // Confirm supports IERC1155receiver interface - let (is_supported) = IERC165.supportsInterface(to, IERC1155_RECEIVER_ID); - if (is_supported == TRUE) { - let (selector) = IERC1155Receiver.onERC1155BatchReceived( - contract_address=to, - operator=operator, - from_=from_, - ids_len=ids_len, - ids=ids, - values_len=values_len, - values=values, - data_len=data_len, - data=data, - ); - // Confirm onBatchERC1155Recieved selector returned - with_attr error_message("ERC1155: ERC1155Receiver rejected tokens") { - assert selector = ON_ERC1155_BATCH_RECEIVED_SELECTOR; - } - return (); - } - - // Alternatively confirm account - let (is_account) = IERC165.supportsInterface(to, IACCOUNT_ID); - with_attr error_message("ERC1155: transfer to non-ERC1155Receiver implementer") { - assert is_account = TRUE; - } - return (); -} - -func _balance_of_batch_iter{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - len: felt, accounts: felt*, ids: Uint256*, batch_balances: Uint256* -) { - if (len == 0) { - return (); - } - // Read current entries - let id: Uint256 = [ids]; - _check_id(id); - let account: felt = [accounts]; - - // Get balance - let (balance: Uint256) = ERC1155.balance_of(account, id); - assert [batch_balances] = balance; - return _balance_of_batch_iter( - len - 1, accounts + 1, ids + Uint256.SIZE, batch_balances + Uint256.SIZE - ); -} - -func _safe_batch_transfer_from_iter{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr -}(from_: felt, to: felt, len: felt, ids: Uint256*, values: Uint256*) { - // Base case - alloc_locals; - if (len == 0) { - return (); - } - - // Read current entries, perform Uint256 checks - let id = [ids]; - let value = [values]; - _check_id(id); - _check_value(value); - - // deduct from sender - let (from_balance: Uint256) = ERC1155_balances.read(id, from_); - with_attr error_message("ERC1155: insufficient balance for transfer") { - let (new_balance: Uint256) = SafeUint256.sub_le(from_balance, value); - } - ERC1155_balances.write(id, from_, new_balance); - - _add_to_receiver(id, value, to); - - // Recursive call - return _safe_batch_transfer_from_iter( - from_, to, len - 1, ids + Uint256.SIZE, values + Uint256.SIZE - ); -} - -func _mint_batch_iter{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, len: felt, ids: Uint256*, values: Uint256* -) { - // Base case - alloc_locals; - if (len == 0) { - return (); - } - - // Read current entries - let id: Uint256 = [ids]; - let value: Uint256 = [values]; - _check_id(id); - _check_value(value); - - _add_to_receiver(id, value, to); - - // Recursive call - return _mint_batch_iter(to, len - 1, ids + Uint256.SIZE, values + Uint256.SIZE); -} - -func _burn_batch_iter{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, len: felt, ids: Uint256*, values: Uint256* -) { - // Base case - alloc_locals; - if (len == 0) { - return (); - } - - // Read current entries - let id: Uint256 = [ids]; - let value: Uint256 = [values]; - _check_id(id); - _check_value(value); - - // Deduct from burner - let (from_balance: Uint256) = ERC1155_balances.read(id, from_); - with_attr error_message("ERC1155: burn value exceeds balance") { - let (new_balance: Uint256) = SafeUint256.sub_le(from_balance, value); - } - ERC1155_balances.write(id, from_, new_balance); - - // Recursive call - return _burn_batch_iter(from_, len - 1, ids + Uint256.SIZE, values + Uint256.SIZE); -} - -func _add_to_receiver{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - id: Uint256, value: Uint256, receiver: felt -) { - let (receiver_balance: Uint256) = ERC1155_balances.read(id, receiver); - with_attr error_message("ERC1155: balance overflow") { - let (new_balance: Uint256) = SafeUint256.add(receiver_balance, value); - } - ERC1155_balances.write(id, receiver, new_balance); - return (); -} - -func _check_id{range_check_ptr}(id: Uint256) { - with_attr error_message("ERC1155: token_id is not a valid Uint256") { - uint256_check(id); - } - return (); -} - -func _check_value{range_check_ptr}(value: Uint256) { - with_attr error_message("ERC1155: value is not a valid Uint256") { - uint256_check(value); - } - return (); -} diff --git a/src/openzeppelin/token/erc1155/presets/ERC1155MintableBurnable.cairo b/src/openzeppelin/token/erc1155/presets/ERC1155MintableBurnable.cairo deleted file mode 100644 index e280effae..000000000 --- a/src/openzeppelin/token/erc1155/presets/ERC1155MintableBurnable.cairo +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc1155/presets/ERC1155MintableBurnable.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.access.ownable.library import Ownable -from openzeppelin.token.erc1155.library import ERC1155 -from openzeppelin.introspection.erc165.library import ERC165 - -// -// Constructor -// - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - uri: felt, owner: felt -) { - ERC1155.initializer(uri); - Ownable.initializer(owner); - return (); -} - -// -// Getters -// - -@view -func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) -> (success: felt) { - return ERC165.supports_interface(interfaceId); -} - -@view -func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(id: Uint256) -> ( - uri: felt -) { - return ERC1155.uri(id); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - account: felt, id: Uint256 -) -> (balance: Uint256) { - return ERC1155.balance_of(account, id); -} - -@view -func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256* -) -> (balances_len: felt, balances: Uint256*) { - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids); -} - -@view -func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - account: felt, operator: felt -) -> (approved: felt) { - return ERC1155.is_approved_for_all(account, operator); -} - -@view -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - -// -// Externals -// - -@external -func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - operator: felt, approved: felt -) { - ERC1155.set_approval_for_all(operator, approved); - return (); -} - -@external -func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt* -) { - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data); - return (); -} - -@external -func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, -) { - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data); - return (); -} - -@external -func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt* -) { - Ownable.assert_only_owner(); - ERC1155._mint(to, id, value, data_len, data); - return (); -} - -@external -func mintBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, -) { - Ownable.assert_only_owner(); - ERC1155._mint_batch(to, ids_len, ids, values_len, values, data_len, data); - return (); -} - -@external -func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, id: Uint256, value: Uint256 -) { - ERC1155.assert_owner_or_approved(owner=from_); - ERC1155._burn(from_, id, value); - return (); -} - -@external -func burnBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, ids_len: felt, ids: Uint256*, values_len: felt, values: Uint256* -) { - ERC1155.assert_owner_or_approved(owner=from_); - ERC1155._burn_batch(from_, ids_len, ids, values_len, values); - return (); -} - -@external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - newOwner: felt -) { - Ownable.transfer_ownership(newOwner); - return (); -} - -@external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); -} diff --git a/src/openzeppelin/token/erc1155/presets/utils/ERC1155Holder.cairo b/src/openzeppelin/token/erc1155/presets/utils/ERC1155Holder.cairo deleted file mode 100644 index a369cc754..000000000 --- a/src/openzeppelin/token/erc1155/presets/utils/ERC1155Holder.cairo +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc1155/presets/utils/ERC1155Holder.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 -from starkware.cairo.common.bool import TRUE, FALSE - -from openzeppelin.utils.constants.library import ( - IERC1155_RECEIVER_ID, - ON_ERC1155_RECEIVED_SELECTOR, - ON_ERC1155_BATCH_RECEIVED_SELECTOR, -) - -@view -func onERC1155Received( - operator: felt, from_: felt, id: Uint256, value: Uint256, data_len: felt, data: felt* -) -> (selector: felt) { - if (data_len == 0) { - return (ON_ERC1155_RECEIVED_SELECTOR,); - } else { - return (FALSE,); - } -} - -@view -func onERC1155BatchReceived( - operator: felt, - from_: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, -) -> (selector: felt) { - if (data_len == 0) { - return (ON_ERC1155_BATCH_RECEIVED_SELECTOR,); - } else { - return (FALSE,); - } -} - -@view -func supportsInterface(interfaceId: felt) -> (success: felt) { - if (interfaceId == IERC1155_RECEIVER_ID) { - return (TRUE,); - } else { - return (FALSE,); - } -} diff --git a/src/openzeppelin/token/erc20/cairo_project.toml b/src/openzeppelin/token/erc20/cairo_project.toml deleted file mode 100644 index e3dce5a73..000000000 --- a/src/openzeppelin/token/erc20/cairo_project.toml +++ /dev/null @@ -1,2 +0,0 @@ -[crate_roots] -erc20 = "." diff --git a/src/openzeppelin/token/erc20/erc20.cairo b/src/openzeppelin/token/erc20/erc20.cairo deleted file mode 100644 index 82aed427f..000000000 --- a/src/openzeppelin/token/erc20/erc20.cairo +++ /dev/null @@ -1,188 +0,0 @@ -#[contract] -mod ERC20 { - use erc20::IERC20; - use starknet::get_caller_address; - use starknet::contract_address_const; - use starknet::ContractAddressZeroable; - use zeroable::Zeroable; - - struct Storage { - _name: felt, - _symbol: felt, - _total_supply: u256, - _balances: LegacyMap::, - _allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>, - } - - #[event] - fn Transfer(from: ContractAddress, to: ContractAddress, value: u256) {} - - #[event] - fn Approval(owner: ContractAddress, spender: ContractAddress, value: u256) {} - - impl ERC20 of IERC20 { - fn name() -> felt { - _name::read() - } - - fn symbol() -> felt { - _symbol::read() - } - - fn decimals() -> u8 { - 18_u8 - } - - fn total_supply() -> u256 { - _total_supply::read() - } - - fn balance_of(account: ContractAddress) -> u256 { - _balances::read(account) - } - - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - _allowances::read((owner, spender)) - } - - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - let sender = get_caller_address(); - _transfer(sender, recipient, amount); - true - } - - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - let caller = get_caller_address(); - _spend_allowance(sender, caller, amount); - _transfer(sender, recipient, amount); - true - } - - fn approve(spender: ContractAddress, amount: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, amount); - true - } - } - - #[constructor] - fn constructor(name: felt, symbol: felt, initial_supply: u256, recipient: ContractAddress) { - initializer(name, symbol, initial_supply, recipient); - } - - #[view] - fn name() -> felt { - ERC20::name() - } - - #[view] - fn symbol() -> felt { - ERC20::symbol() - } - - #[view] - fn decimals() -> u8 { - ERC20::decimals() - } - - #[view] - fn total_supply() -> u256 { - ERC20::total_supply() - } - - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC20::balance_of(account) - } - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20::allowance(owner, spender) - } - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20::transfer(recipient, amount) - } - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20::transfer_from(sender, recipient, amount) - } - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20::approve(spender, amount) - } - - #[external] - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - _increase_allowance(spender, added_value) - } - - #[external] - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - _decrease_allowance(spender, subtracted_value) - } - - /// - /// Internals - /// - - fn initializer(name_: felt, symbol_: felt, initial_supply: u256, recipient: ContractAddress) { - _name::write(name_); - _symbol::write(symbol_); - _mint(recipient, initial_supply); - } - - fn _increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, _allowances::read((caller, spender)) + added_value); - true - } - - fn _decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, _allowances::read((caller, spender)) - subtracted_value); - true - } - - fn _mint(recipient: ContractAddress, amount: u256) { - assert(!recipient.is_zero(), 'ERC20: mint to 0'); - _total_supply::write(_total_supply::read() + amount); - _balances::write(recipient, _balances::read(recipient) + amount); - Transfer(contract_address_const::<0>(), recipient, amount); - } - - fn _burn(account: ContractAddress, amount: u256) { - assert(!account.is_zero(), 'ERC20: burn from 0'); - _total_supply::write(_total_supply::read() - amount); - _balances::write(account, _balances::read(account) - amount); - Transfer(account, contract_address_const::<0>(), amount); - } - - fn _approve(owner: ContractAddress, spender: ContractAddress, amount: u256) { - assert(!owner.is_zero(), 'ERC20: approve from 0'); - assert(!spender.is_zero(), 'ERC20: approve to 0'); - _allowances::write((owner, spender), amount); - Approval(owner, spender, amount); - } - - fn _transfer(sender: ContractAddress, recipient: ContractAddress, amount: u256) { - assert(!sender.is_zero(), 'ERC20: transfer from 0'); - assert(!recipient.is_zero(), 'ERC20: transfer to 0'); - _balances::write(sender, _balances::read(sender) - amount); - _balances::write(recipient, _balances::read(recipient) + amount); - Transfer(sender, recipient, amount); - } - - fn _spend_allowance(owner: ContractAddress, spender: ContractAddress, amount: u256) { - let current_allowance = _allowances::read((owner, spender)); - let ONES_MASK = 0xffffffffffffffffffffffffffffffff_u128; - let is_unlimited_allowance = - current_allowance.low == ONES_MASK & current_allowance.high == ONES_MASK; - if !is_unlimited_allowance { - _approve(owner, spender, current_allowance - amount); - } - } -} diff --git a/src/openzeppelin/token/erc20/lib.cairo b/src/openzeppelin/token/erc20/lib.cairo deleted file mode 100644 index 29d85d5fe..000000000 --- a/src/openzeppelin/token/erc20/lib.cairo +++ /dev/null @@ -1,16 +0,0 @@ -mod erc20; -use erc20::ERC20; - -mod tests; - -trait IERC20 { - fn name() -> felt; - fn symbol() -> felt; - fn decimals() -> u8; - fn total_supply() -> u256; - fn balance_of(account: ContractAddress) -> u256; - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - fn approve(spender: ContractAddress, amount: u256) -> bool; -} diff --git a/src/openzeppelin/token/erc20/tests.cairo b/src/openzeppelin/token/erc20/tests.cairo deleted file mode 100644 index 0117a1281..000000000 --- a/src/openzeppelin/token/erc20/tests.cairo +++ /dev/null @@ -1 +0,0 @@ -mod test_erc20; diff --git a/src/openzeppelin/token/erc20/tests/test_erc20.cairo b/src/openzeppelin/token/erc20/tests/test_erc20.cairo deleted file mode 100644 index a41cf5bd3..000000000 --- a/src/openzeppelin/token/erc20/tests/test_erc20.cairo +++ /dev/null @@ -1,435 +0,0 @@ -use erc20::ERC20; -use starknet::contract_address_const; -use starknet_testing::set_caller_address; -use integer::u256; -use integer::u256_from_felt; - -const NAME: felt = 111; -const SYMBOL: felt = 222; - -fn setup() -> (ContractAddress, u256) { - let initial_supply: u256 = u256_from_felt(2000); - let account: ContractAddress = contract_address_const::<1>(); - // Set account as default caller - set_caller_address(account); - - ERC20::initializer(NAME, SYMBOL, initial_supply, account); - (account, initial_supply) -} - -fn set_caller_as_zero() { - set_caller_address(contract_address_const::<0>()); -} - -#[test] -#[available_gas(2000000)] -fn initialize() { - let initial_supply: u256 = u256_from_felt(2000); - let account: ContractAddress = contract_address_const::<1>(); - let decimals: u8 = 18_u8; - - ERC20::initializer(NAME, SYMBOL, initial_supply, account); - - let owner_balance: u256 = ERC20::balance_of(account); - assert(owner_balance == initial_supply, 'Should eq inital_supply'); - - assert(ERC20::total_supply() == initial_supply, 'Should eq inital_supply'); - assert(ERC20::name() == NAME, 'Name should be NAME'); - assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20::decimals() == decimals, 'Decimals should be 18'); -} - -#[test] -#[available_gas(2000000)] -fn test_approve() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - let success: bool = ERC20::approve(spender, amount); - assert(success, 'Should return true'); - assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_approve_from_zero() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - set_caller_as_zero(); - - ERC20::approve(spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_approve_to_zero() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20::approve(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__approve() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20::_approve(owner, spender, amount); - assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__approve_from_zero() { - let owner: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<1>(); - let amount: u256 = u256_from_felt(100); - ERC20::_approve(owner, spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__approve_to_zero() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - ERC20::_approve(owner, spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - let success: bool = ERC20::transfer(recipient, amount); - - assert(success, 'Should return true'); - assert(ERC20::balance_of(recipient) == amount, 'Balance should eq amount'); - assert(ERC20::balance_of(sender) == supply - amount, 'Should eq supply - amount'); - assert(ERC20::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test__transfer() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - ERC20::_transfer(sender, recipient, amount); - - assert(ERC20::balance_of(recipient) == amount, 'Balance should eq amount'); - assert(ERC20::balance_of(sender) == supply - amount, 'Should eq supply - amount'); - assert(ERC20::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__transfer_not_enough_balance() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = supply + u256_from_felt(1); - ERC20::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__transfer_from_zero() { - let sender: ContractAddress = contract_address_const::<0>(); - let recipient: ContractAddress = contract_address_const::<1>(); - let amount: u256 = u256_from_felt(100); - ERC20::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__transfer_to_zero() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - ERC20::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer_from() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - - ERC20::approve(spender, amount); - - set_caller_address(spender); - - let success: bool = ERC20::transfer_from(owner, recipient, amount); - assert(success, 'Should return true'); - - // Will dangle without setting as a var - let spender_allowance: u256 = ERC20::allowance(owner, spender); - - assert(ERC20::balance_of(recipient) == amount, 'Should eq amount'); - assert(ERC20::balance_of(owner) == supply - amount, 'Should eq suppy - amount'); - assert(spender_allowance == u256_from_felt(0), 'Should eq 0'); - assert(ERC20::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer_from_doesnt_consume_infinite_allowance() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - let max_u256: u256 = u256 { - low: 0xffffffffffffffffffffffffffffffff_u128, - high: 0xffffffffffffffffffffffffffffffff_u128 - }; - - ERC20::approve(spender, max_u256); - - set_caller_address(spender); - - ERC20::transfer_from(owner, recipient, amount); - - let spender_allowance: u256 = ERC20::allowance(owner, spender); - assert(spender_allowance == max_u256, 'Allowance should not change'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_transfer_from_greater_than_allowance() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - let amount_plus_one: u256 = amount + u256_from_felt(1); - - ERC20::approve(spender, amount); - - set_caller_address(spender); - - ERC20::transfer_from(owner, recipient, amount_plus_one); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_transfer_from_to_zero_address() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - - ERC20::approve(spender, amount); - - set_caller_address(spender); - - ERC20::transfer_from(owner, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_transfer_from_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt(100); - - set_caller_address(zero_address); - - ERC20::transfer_from(owner, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_increase_allowance() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20::approve(spender, amount); - let success: bool = ERC20::increase_allowance(spender, amount); - assert(success, 'Should return true'); - - - let spender_allowance: u256 = ERC20::allowance(owner, spender); - assert(spender_allowance == amount + amount, 'Should be amount * 2'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_increase_allowance_to_zero_address() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20::increase_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_increase_allowance_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - set_caller_address(zero_address); - - ERC20::increase_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_decrease_allowance() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20::approve(spender, amount); - let success: bool = ERC20::decrease_allowance(spender, amount); - assert(success, 'Should return true'); - - let spender_allowance: u256 = ERC20::allowance(owner, spender); - assert(spender_allowance == amount - amount, 'Should be 0'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_decrease_allowance_to_zero_address() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20::decrease_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_decrease_allowance_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - set_caller_address(zero_address); - - ERC20::decrease_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__spend_allowance_not_unlimited() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20::_approve(owner, spender, supply); - ERC20::_spend_allowance(owner, spender, amount); - assert(ERC20::allowance(owner, spender) == supply - amount, 'Should eq supply - amount'); -} - -#[test] -#[available_gas(2000000)] -fn test__spend_allowance_unlimited() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - - let max_u256: u256 = u256 { - low: 0xffffffffffffffffffffffffffffffff_u128, - high: 0xffffffffffffffffffffffffffffffff_u128 - }; - let max_minus_one: u256 = max_u256 - u256_from_felt(1); - - ERC20::_approve(owner, spender, max_u256); - ERC20::_spend_allowance(owner, spender, max_minus_one); - - assert(ERC20::allowance(owner, spender) == max_u256, 'Allowance should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test__mint() { - let minter: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt(100); - - ERC20::_mint(minter, amount); - - let minter_balance: u256 = ERC20::balance_of(minter); - assert(minter_balance == amount, 'Should eq amount'); - - assert(ERC20::total_supply() == amount, 'Should eq total supply'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__mint_to_zero() { - let minter: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20::_mint(minter, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__burn() { - let (owner, supply) = setup(); - - let amount: u256 = u256_from_felt(100); - ERC20::_burn(owner, amount); - - assert(ERC20::total_supply() == supply - amount, 'Should eq supply - amount'); - assert(ERC20::balance_of(owner) == supply - amount, 'Should eq supply - amount'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test__burn_from_zero() { - setup(); - let zero_address: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt(100); - - ERC20::_burn(zero_address, amount); -} diff --git a/src/openzeppelin/token/erc721/IERC721.cairo b/src/openzeppelin/token/erc721/IERC721.cairo deleted file mode 100644 index 48a4c62e6..000000000 --- a/src/openzeppelin/token/erc721/IERC721.cairo +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/IERC721.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 - -@contract_interface -namespace IERC721 { - func balanceOf(owner: felt) -> (balance: Uint256) { - } - - func ownerOf(tokenId: Uint256) -> (owner: felt) { - } - - func safeTransferFrom(from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*) { - } - - func transferFrom(from_: felt, to: felt, tokenId: Uint256) { - } - - func approve(approved: felt, tokenId: Uint256) { - } - - func setApprovalForAll(operator: felt, approved: felt) { - } - - func getApproved(tokenId: Uint256) -> (approved: felt) { - } - - func isApprovedForAll(owner: felt, operator: felt) -> (approved: felt) { - } - - // ERC165 - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/token/erc721/IERC721Metadata.cairo b/src/openzeppelin/token/erc721/IERC721Metadata.cairo deleted file mode 100644 index 65cdac38e..000000000 --- a/src/openzeppelin/token/erc721/IERC721Metadata.cairo +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/IERC721Metadata.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 - -@contract_interface -namespace IERC721Metadata { - func name() -> (name: felt) { - } - - func symbol() -> (symbol: felt) { - } - - func tokenURI(tokenId: Uint256) -> (tokenURI: felt) { - } - - /// IERC721 - - func balanceOf(owner: felt) -> (balance: Uint256) { - } - - func ownerOf(tokenId: Uint256) -> (owner: felt) { - } - - func safeTransferFrom(from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*) { - } - - func transferFrom(from_: felt, to: felt, tokenId: Uint256) { - } - - func approve(approved: felt, tokenId: Uint256) { - } - - func setApprovalForAll(operator: felt, approved: felt) { - } - - func getApproved(tokenId: Uint256) -> (approved: felt) { - } - - func isApprovedForAll(owner: felt, operator: felt) -> (approved: felt) { - } - - // ERC165 - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/token/erc721/IERC721Receiver.cairo b/src/openzeppelin/token/erc721/IERC721Receiver.cairo deleted file mode 100644 index 30cfb36fd..000000000 --- a/src/openzeppelin/token/erc721/IERC721Receiver.cairo +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/IERC721Receiver.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 - -@contract_interface -namespace IERC721Receiver { - func onERC721Received( - operator: felt, - from_: felt, - tokenId: Uint256, - data_len: felt, - data: felt* - ) -> (selector: felt) { - } -} diff --git a/src/openzeppelin/token/erc721/enumerable/IERC721Enumerable.cairo b/src/openzeppelin/token/erc721/enumerable/IERC721Enumerable.cairo deleted file mode 100644 index 06e82584f..000000000 --- a/src/openzeppelin/token/erc721/enumerable/IERC721Enumerable.cairo +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/enumerable/IERC721Enumerable.cairo) - -%lang starknet - -from starkware.cairo.common.uint256 import Uint256 - -@contract_interface -namespace IERC721Enumerable { - func totalSupply() -> (totalSupply: Uint256) { - } - - func tokenByIndex(index: Uint256) -> (tokenId: Uint256) { - } - - func tokenOfOwnerByIndex(owner: felt, index: Uint256) -> (tokenId: Uint256) { - } - - /// IERC721 - - func balanceOf(owner: felt) -> (balance: Uint256) { - } - - func ownerOf(tokenId: Uint256) -> (owner: felt) { - } - - func safeTransferFrom(from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*) { - } - - func transferFrom(from_: felt, to: felt, tokenId: Uint256) { - } - - func approve(approved: felt, tokenId: Uint256) { - } - - func setApprovalForAll(operator: felt, approved: felt) { - } - - func getApproved(tokenId: Uint256) -> (approved: felt) { - } - - func isApprovedForAll(owner: felt, operator: felt) -> (approved: felt) { - } - - // ERC165 - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/token/erc721/enumerable/library.cairo b/src/openzeppelin/token/erc721/enumerable/library.cairo deleted file mode 100644 index 2ffb05023..000000000 --- a/src/openzeppelin/token/erc721/enumerable/library.cairo +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/enumerable/library.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.bool import TRUE, FALSE -from starkware.cairo.common.uint256 import Uint256, uint256_lt, uint256_eq, uint256_check - -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.security.safemath.library import SafeUint256 -from openzeppelin.token.erc721.library import ERC721 -from openzeppelin.utils.constants.library import IERC721_ENUMERABLE_ID - -// -// Storage -// - -@storage_var -func ERC721Enumerable_all_tokens_len() -> (total_supply: Uint256) { -} - -@storage_var -func ERC721Enumerable_all_tokens(index: Uint256) -> (token_id: Uint256) { -} - -@storage_var -func ERC721Enumerable_all_tokens_index(token_id: Uint256) -> (index: Uint256) { -} - -@storage_var -func ERC721Enumerable_owned_tokens(owner: felt, index: Uint256) -> (token_id: Uint256) { -} - -@storage_var -func ERC721Enumerable_owned_tokens_index(token_id: Uint256) -> (index: Uint256) { -} - -namespace ERC721Enumerable { - // - // Constructor - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - ERC165.register_interface(IERC721_ENUMERABLE_ID); - return (); - } - - // - // Getters - // - - func total_supply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - total_supply: Uint256 - ) { - return ERC721Enumerable_all_tokens_len.read(); - } - - func token_by_index{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - index: Uint256 - ) -> (token_id: Uint256) { - alloc_locals; - uint256_check(index); - // Ensures index argument is less than total_supply - let (len: Uint256) = ERC721Enumerable.total_supply(); - let (is_lt) = uint256_lt(index, len); - with_attr error_message("ERC721Enumerable: global index out of bounds") { - assert is_lt = TRUE; - } - - return ERC721Enumerable_all_tokens.read(index); - } - - func token_of_owner_by_index{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, index: Uint256 - ) -> (token_id: Uint256) { - alloc_locals; - uint256_check(index); - // Ensures index argument is less than owner's balance - let (len: Uint256) = ERC721.balance_of(owner); - let (is_lt) = uint256_lt(index, len); - with_attr error_message("ERC721Enumerable: owner index out of bounds") { - assert is_lt = TRUE; - } - - return ERC721Enumerable_owned_tokens.read(owner, index); - } - - // - // Externals - // - func transfer_from{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, token_id: Uint256 - ) { - _remove_token_from_owner_enumeration(from_, token_id); - _add_token_to_owner_enumeration(to, token_id); - ERC721.transfer_from(from_, to, token_id); - return (); - } - - func safe_transfer_from{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, token_id: Uint256, data_len: felt, data: felt* - ) { - _remove_token_from_owner_enumeration(from_, token_id); - _add_token_to_owner_enumeration(to, token_id); - ERC721.safe_transfer_from(from_, to, token_id, data_len, data); - return (); - } - - // - // Internals - // - - func _mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, token_id: Uint256 - ) { - _add_token_to_all_tokens_enumeration(token_id); - _add_token_to_owner_enumeration(to, token_id); - ERC721._mint(to, token_id); - return (); - } - - func _burn{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}(token_id: Uint256) { - let (from_) = ERC721.owner_of(token_id); - _remove_token_from_owner_enumeration(from_, token_id); - _remove_token_from_all_tokens_enumeration(token_id); - ERC721._burn(token_id); - return (); - } -} - -// -// Private -// - -func _add_token_to_all_tokens_enumeration{ - pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr -}(token_id: Uint256) { - let (supply: Uint256) = ERC721Enumerable_all_tokens_len.read(); - ERC721Enumerable_all_tokens.write(supply, token_id); - ERC721Enumerable_all_tokens_index.write(token_id, supply); - - let (new_supply: Uint256) = SafeUint256.add(supply, Uint256(1, 0)); - ERC721Enumerable_all_tokens_len.write(new_supply); - return (); -} - -func _remove_token_from_all_tokens_enumeration{ - pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr -}(token_id: Uint256) { - alloc_locals; - let (supply: Uint256) = ERC721Enumerable_all_tokens_len.read(); - let (last_token_index: Uint256) = SafeUint256.sub_le(supply, Uint256(1, 0)); - let (token_index: Uint256) = ERC721Enumerable_all_tokens_index.read(token_id); - let (last_token_id: Uint256) = ERC721Enumerable_all_tokens.read(last_token_index); - - ERC721Enumerable_all_tokens.write(last_token_index, Uint256(0, 0)); - ERC721Enumerable_all_tokens_index.write(token_id, Uint256(0, 0)); - ERC721Enumerable_all_tokens_len.write(last_token_index); - - let (is_equal) = uint256_eq(last_token_index, token_index); - if (is_equal == FALSE) { - ERC721Enumerable_all_tokens_index.write(last_token_id, token_index); - ERC721Enumerable_all_tokens.write(token_index, last_token_id); - return (); - } - return (); -} - -func _add_token_to_owner_enumeration{ - pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr -}(to: felt, token_id: Uint256) { - let (length: Uint256) = ERC721.balance_of(to); - ERC721Enumerable_owned_tokens.write(to, length, token_id); - ERC721Enumerable_owned_tokens_index.write(token_id, length); - return (); -} - -func _remove_token_from_owner_enumeration{ - pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr -}(from_: felt, token_id: Uint256) { - alloc_locals; - let (last_token_index: Uint256) = ERC721.balance_of(from_); - // the index starts at zero therefore the user's last token index is their balance minus one - let (last_token_index) = SafeUint256.sub_le(last_token_index, Uint256(1, 0)); - let (token_index: Uint256) = ERC721Enumerable_owned_tokens_index.read(token_id); - - // If index is last, we can just set the return values to zero - let (is_equal) = uint256_eq(token_index, last_token_index); - if (is_equal == TRUE) { - ERC721Enumerable_owned_tokens_index.write(token_id, Uint256(0, 0)); - ERC721Enumerable_owned_tokens.write(from_, last_token_index, Uint256(0, 0)); - return (); - } - - // If index is not last, reposition owner's last token to the removed token's index - let (last_token_id: Uint256) = ERC721Enumerable_owned_tokens.read(from_, last_token_index); - ERC721Enumerable_owned_tokens.write(from_, token_index, last_token_id); - ERC721Enumerable_owned_tokens_index.write(last_token_id, token_index); - return (); -} diff --git a/src/openzeppelin/token/erc721/enumerable/presets/ERC721EnumerableMintableBurnable.cairo b/src/openzeppelin/token/erc721/enumerable/presets/ERC721EnumerableMintableBurnable.cairo deleted file mode 100644 index 44ac448ea..000000000 --- a/src/openzeppelin/token/erc721/enumerable/presets/ERC721EnumerableMintableBurnable.cairo +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/enumerable/presets/ERC721EnumerableMintableBurnable.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.access.ownable.library import Ownable -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.token.erc721.library import ERC721 -from openzeppelin.token.erc721.enumerable.library import ERC721Enumerable - -// -// Constructor -// - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, owner: felt -) { - ERC721.initializer(name, symbol); - ERC721Enumerable.initializer(); - Ownable.initializer(owner); - return (); -} - -// -// Getters -// - -@view -func totalSupply{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}() -> ( - totalSupply: Uint256 -) { - let (totalSupply: Uint256) = ERC721Enumerable.total_supply(); - return (totalSupply=totalSupply); -} - -@view -func tokenByIndex{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - index: Uint256 -) -> (tokenId: Uint256) { - let (tokenId: Uint256) = ERC721Enumerable.token_by_index(index); - return (tokenId=tokenId); -} - -@view -func tokenOfOwnerByIndex{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - owner: felt, index: Uint256 -) -> (tokenId: Uint256) { - let (tokenId: Uint256) = ERC721Enumerable.token_of_owner_by_index(owner, index); - return (tokenId=tokenId); -} - -@view -func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) -> (success: felt) { - return ERC165.supports_interface(interfaceId); -} - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC721.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC721.symbol(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> ( - balance: Uint256 -) { - return ERC721.balance_of(owner); -} - -@view -func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(tokenId: Uint256) -> ( - owner: felt -) { - return ERC721.owner_of(tokenId); -} - -@view -func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - tokenId: Uint256 -) -> (approved: felt) { - return ERC721.get_approved(tokenId); -} - -@view -func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, operator: felt -) -> (approved: felt) { - return ERC721.is_approved_for_all(owner, operator); -} - -@view -func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - tokenId: Uint256 -) -> (tokenURI: felt) { - let (tokenURI: felt) = ERC721.token_uri(tokenId); - return (tokenURI=tokenURI); -} - -@view -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - -// -// Externals -// - -@external -func approve{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256 -) { - ERC721.approve(to, tokenId); - return (); -} - -@external -func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - operator: felt, approved: felt -) { - ERC721.set_approval_for_all(operator, approved); - return (); -} - -@external -func transferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, tokenId: Uint256 -) { - ERC721Enumerable.transfer_from(from_, to, tokenId); - return (); -} - -@external -func safeTransferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt* -) { - ERC721Enumerable.safe_transfer_from(from_, to, tokenId, data_len, data); - return (); -} - -@external -func mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256 -) { - Ownable.assert_only_owner(); - ERC721Enumerable._mint(to, tokenId); - return (); -} - -@external -func burn{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}(tokenId: Uint256) { - ERC721.assert_only_token_owner(tokenId); - ERC721Enumerable._burn(tokenId); - return (); -} - -@external -func setTokenURI{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - tokenId: Uint256, tokenURI: felt -) { - Ownable.assert_only_owner(); - ERC721._set_token_uri(tokenId, tokenURI); - return (); -} - -@external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - newOwner: felt -) { - Ownable.transfer_ownership(newOwner); - return (); -} - -@external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); -} diff --git a/src/openzeppelin/token/erc721/library.cairo b/src/openzeppelin/token/erc721/library.cairo deleted file mode 100644 index 3a4b58f95..000000000 --- a/src/openzeppelin/token/erc721/library.cairo +++ /dev/null @@ -1,471 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/library.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.starknet.common.syscalls import get_caller_address -from starkware.cairo.common.math import assert_not_zero, assert_not_equal -from starkware.cairo.common.bool import TRUE, FALSE -from starkware.cairo.common.uint256 import Uint256, uint256_check - -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.introspection.erc165.IERC165 import IERC165 -from openzeppelin.security.safemath.library import SafeUint256 -from openzeppelin.token.erc721.IERC721Receiver import IERC721Receiver -from openzeppelin.utils.constants.library import ( - IERC721_ID, - IERC721_METADATA_ID, - IERC721_RECEIVER_ID, - IACCOUNT_ID, -) - -// -// Events -// - -@event -func Transfer(from_: felt, to: felt, tokenId: Uint256) { -} - -@event -func Approval(owner: felt, approved: felt, tokenId: Uint256) { -} - -@event -func ApprovalForAll(owner: felt, operator: felt, approved: felt) { -} - -// -// Storage -// - -@storage_var -func ERC721_name() -> (name: felt) { -} - -@storage_var -func ERC721_symbol() -> (symbol: felt) { -} - -@storage_var -func ERC721_owners(token_id: Uint256) -> (owner: felt) { -} - -@storage_var -func ERC721_balances(account: felt) -> (balance: Uint256) { -} - -@storage_var -func ERC721_token_approvals(token_id: Uint256) -> (approved: felt) { -} - -@storage_var -func ERC721_operator_approvals(owner: felt, operator: felt) -> (approved: felt) { -} - -@storage_var -func ERC721_token_uri(token_id: Uint256) -> (token_uri: felt) { -} - -namespace ERC721 { - // - // Constructor - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt - ) { - ERC721_name.write(name); - ERC721_symbol.write(symbol); - ERC165.register_interface(IERC721_ID); - ERC165.register_interface(IERC721_METADATA_ID); - return (); - } - - // - // Getters - // - - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC721_name.read(); - } - - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - symbol: felt - ) { - return ERC721_symbol.read(); - } - - func balance_of{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt - ) -> (balance: Uint256) { - with_attr error_message("ERC721: balance query for the zero address") { - assert_not_zero(owner); - } - return ERC721_balances.read(owner); - } - - func owner_of{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - token_id: Uint256 - ) -> (owner: felt) { - with_attr error_message("ERC721: token_id is not a valid Uint256") { - uint256_check(token_id); - } - let (owner) = ERC721_owners.read(token_id); - with_attr error_message("ERC721: owner query for nonexistent token") { - assert_not_zero(owner); - } - return (owner=owner); - } - - func get_approved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - token_id: Uint256 - ) -> (approved: felt) { - with_attr error_message("ERC721: token_id is not a valid Uint256") { - uint256_check(token_id); - } - let exists = _exists(token_id); - with_attr error_message("ERC721: approved query for nonexistent token") { - assert exists = TRUE; - } - - return ERC721_token_approvals.read(token_id); - } - - func is_approved_for_all{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, operator: felt - ) -> (approved: felt) { - return ERC721_operator_approvals.read(owner, operator); - } - - func token_uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - token_id: Uint256 - ) -> (token_uri: felt) { - let exists = _exists(token_id); - with_attr error_message("ERC721_Metadata: URI query for nonexistent token") { - assert exists = TRUE; - } - - // if tokenURI is not set, it will return 0 - return ERC721_token_uri.read(token_id); - } - - // - // Externals - // - - func approve{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, token_id: Uint256 - ) { - with_attr error_mesage("ERC721: token_id is not a valid Uint256") { - uint256_check(token_id); - } - - // Checks caller is not zero address - let (caller) = get_caller_address(); - with_attr error_message("ERC721: cannot approve from the zero address") { - assert_not_zero(caller); - } - - // Ensures 'owner' does not equal 'to' - let (owner) = ERC721_owners.read(token_id); - with_attr error_message("ERC721: approval to current owner") { - assert_not_equal(owner, to); - } - - // Checks that either caller equals owner or - // caller isApprovedForAll on behalf of owner - if (caller == owner) { - _approve(to, token_id); - return (); - } else { - let (is_approved) = ERC721_operator_approvals.read(owner, caller); - with_attr error_message("ERC721: approve caller is not owner nor approved for all") { - assert_not_zero(is_approved); - } - _approve(to, token_id); - return (); - } - } - - func set_approval_for_all{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - operator: felt, approved: felt - ) { - // Ensures caller is neither zero address nor operator - let (caller) = get_caller_address(); - with_attr error_message("ERC721: either the caller or operator is the zero address") { - assert_not_zero(caller * operator); - } - // note this pattern as we'll frequently use it: - // instead of making an `assert_not_zero` call for each address - // we can always briefly write `assert_not_zero(a0 * a1 * ... * aN)`. - // This is because these addresses are field elements, - // meaning that a*0==0 for all a in the field, - // and a*b==0 implies that at least one of a,b are zero in the field - with_attr error_message("ERC721: approve to caller") { - assert_not_equal(caller, operator); - } - - // Make sure `approved` is a boolean (0 or 1) - with_attr error_message("ERC721: approved is not a Cairo boolean") { - assert approved * (1 - approved) = 0; - } - - ERC721_operator_approvals.write(owner=caller, operator=operator, value=approved); - ApprovalForAll.emit(caller, operator, approved); - return (); - } - - func transfer_from{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, token_id: Uint256 - ) { - alloc_locals; - with_attr error_message("ERC721: token_id is not a valid Uint256") { - uint256_check(token_id); - } - let (caller) = get_caller_address(); - let is_approved = _is_approved_or_owner(caller, token_id); - with_attr error_message( - "ERC721: either is not approved or the caller is the zero address") { - assert_not_zero(caller * is_approved); - } - // Note that if either `is_approved` or `caller` equals `0`, - // then this method should fail. - // The `caller` address and `is_approved` boolean are both field elements - // meaning that a*0==0 for all a in the field, - // therefore a*b==0 implies that at least one of a,b is zero in the field - - _transfer(from_, to, token_id); - return (); - } - - func safe_transfer_from{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, token_id: Uint256, data_len: felt, data: felt* - ) { - alloc_locals; - with_attr error_message("ERC721: token_id is not a valid Uint256") { - uint256_check(token_id); - } - let (caller) = get_caller_address(); - let is_approved = _is_approved_or_owner(caller, token_id); - with_attr error_message( - "ERC721: either is not approved or the caller is the zero address") { - assert_not_zero(caller * is_approved); - } - // Note that if either `is_approved` or `caller` equals `0`, - // then this method should fail. - // The `caller` address and `is_approved` boolean are both field elements - // meaning that a*0==0 for all a in the field, - // therefore a*b==0 implies that at least one of a,b is zero in the field - - _safe_transfer(from_, to, token_id, data_len, data); - return (); - } - - // - // Internals - // - - func assert_only_token_owner{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - token_id: Uint256 - ) { - uint256_check(token_id); - let (caller) = get_caller_address(); - let (owner) = owner_of(token_id); - // Note `owner_of` checks that the owner is not the zero address - with_attr error_message("ERC721: caller is not the token owner") { - assert caller = owner; - } - return (); - } - - func _is_approved_or_owner{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - spender: felt, token_id: Uint256 - ) -> felt { - alloc_locals; - - let exists = _exists(token_id); - with_attr error_message("ERC721: token id does not exist") { - assert exists = TRUE; - } - - let (owner) = owner_of(token_id); - if (owner == spender) { - return TRUE; - } - - let (approved_addr) = get_approved(token_id); - if (approved_addr == spender) { - return TRUE; - } - - let (is_operator) = is_approved_for_all(owner, spender); - if (is_operator == TRUE) { - return TRUE; - } - - return FALSE; - } - - func _exists{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - token_id: Uint256 - ) -> felt { - let (exists) = ERC721_owners.read(token_id); - if (exists == FALSE) { - return FALSE; - } - - return TRUE; - } - - func _approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, token_id: Uint256 - ) { - ERC721_token_approvals.write(token_id, to); - let (owner) = owner_of(token_id); - Approval.emit(owner, to, token_id); - return (); - } - - func _transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, to: felt, token_id: Uint256 - ) { - // ownerOf ensures 'from_' is not the zero address - let (owner) = owner_of(token_id); - with_attr error_message("ERC721: transfer from incorrect owner") { - assert owner = from_; - } - - with_attr error_message("ERC721: cannot transfer to the zero address") { - assert_not_zero(to); - } - - // Clear approvals - _approve(0, token_id); - - // Decrease owner balance - let (owner_bal) = ERC721_balances.read(from_); - let (new_balance: Uint256) = SafeUint256.sub_le(owner_bal, Uint256(1, 0)); - ERC721_balances.write(from_, new_balance); - - // Increase receiver balance - let (receiver_bal) = ERC721_balances.read(to); - let (new_balance: Uint256) = SafeUint256.add(receiver_bal, Uint256(1, 0)); - ERC721_balances.write(to, new_balance); - - // Update token_id owner - ERC721_owners.write(token_id, to); - Transfer.emit(from_, to, token_id); - return (); - } - - func _safe_transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, to: felt, token_id: Uint256, data_len: felt, data: felt* - ) { - _transfer(from_, to, token_id); - - let (success) = _check_onERC721Received(from_, to, token_id, data_len, data); - with_attr error_message("ERC721: transfer to non ERC721Receiver implementer") { - assert_not_zero(success); - } - return (); - } - - func _mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, token_id: Uint256 - ) { - with_attr error_message("ERC721: token_id is not a valid Uint256") { - uint256_check(token_id); - } - with_attr error_message("ERC721: cannot mint to the zero address") { - assert_not_zero(to); - } - - // Ensures token_id is unique - let exists = _exists(token_id); - with_attr error_message("ERC721: token already minted") { - assert exists = FALSE; - } - - let (balance: Uint256) = ERC721_balances.read(to); - let (new_balance: Uint256) = SafeUint256.add(balance, Uint256(1, 0)); - ERC721_balances.write(to, new_balance); - ERC721_owners.write(token_id, to); - Transfer.emit(0, to, token_id); - return (); - } - - func _safe_mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, token_id: Uint256, data_len: felt, data: felt* - ) { - with_attr error_message("ERC721: token_id is not a valid Uint256") { - uint256_check(token_id); - } - _mint(to, token_id); - - let (success) = _check_onERC721Received(0, to, token_id, data_len, data); - with_attr error_message("ERC721: transfer to non ERC721Receiver implementer") { - assert_not_zero(success); - } - return (); - } - - func _burn{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}(token_id: Uint256) { - alloc_locals; - with_attr error_message("ERC721: token_id is not a valid Uint256") { - uint256_check(token_id); - } - let (owner) = owner_of(token_id); - - // Clear approvals - _approve(0, token_id); - - // Decrease owner balance - let (balance: Uint256) = ERC721_balances.read(owner); - let (new_balance: Uint256) = SafeUint256.sub_le(balance, Uint256(1, 0)); - ERC721_balances.write(owner, new_balance); - - // Delete owner - ERC721_owners.write(token_id, 0); - Transfer.emit(owner, 0, token_id); - return (); - } - - func _set_token_uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - token_id: Uint256, token_uri: felt - ) { - uint256_check(token_id); - let exists = _exists(token_id); - with_attr error_message("ERC721_Metadata: set token URI for nonexistent token") { - assert exists = TRUE; - } - - ERC721_token_uri.write(token_id, token_uri); - return (); - } -} - -// -// Private -// - -func _check_onERC721Received{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, to: felt, token_id: Uint256, data_len: felt, data: felt* -) -> (success: felt) { - let (caller) = get_caller_address(); - let (is_supported) = IERC165.supportsInterface(to, IERC721_RECEIVER_ID); - if (is_supported == TRUE) { - let (selector) = IERC721Receiver.onERC721Received( - to, caller, from_, token_id, data_len, data - ); - - with_attr error_message("ERC721: transfer to non ERC721Receiver implementer") { - assert selector = IERC721_RECEIVER_ID; - } - return (success=TRUE); - } - - let (is_account) = IERC165.supportsInterface(to, IACCOUNT_ID); - return (success=is_account); -} diff --git a/src/openzeppelin/token/erc721/presets/ERC721MintableBurnable.cairo b/src/openzeppelin/token/erc721/presets/ERC721MintableBurnable.cairo deleted file mode 100644 index b66910951..000000000 --- a/src/openzeppelin/token/erc721/presets/ERC721MintableBurnable.cairo +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/presets/ERC721MintableBurnable.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.access.ownable.library import Ownable -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.token.erc721.library import ERC721 - -// -// Constructor -// - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, owner: felt -) { - ERC721.initializer(name, symbol); - Ownable.initializer(owner); - return (); -} - -// -// Getters -// - -@view -func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) -> (success: felt) { - return ERC165.supports_interface(interfaceId); -} - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC721.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC721.symbol(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> ( - balance: Uint256 -) { - return ERC721.balance_of(owner); -} - -@view -func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(tokenId: Uint256) -> ( - owner: felt -) { - return ERC721.owner_of(tokenId); -} - -@view -func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - tokenId: Uint256 -) -> (approved: felt) { - return ERC721.get_approved(tokenId); -} - -@view -func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, operator: felt -) -> (approved: felt) { - return ERC721.is_approved_for_all(owner, operator); -} - -@view -func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - tokenId: Uint256 -) -> (tokenURI: felt) { - let (tokenURI: felt) = ERC721.token_uri(tokenId); - return (tokenURI=tokenURI); -} - -@view -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - -// -// Externals -// - -@external -func approve{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256 -) { - ERC721.approve(to, tokenId); - return (); -} - -@external -func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - operator: felt, approved: felt -) { - ERC721.set_approval_for_all(operator, approved); - return (); -} - -@external -func transferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, tokenId: Uint256 -) { - ERC721.transfer_from(from_, to, tokenId); - return (); -} - -@external -func safeTransferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt* -) { - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data); - return (); -} - -@external -func mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256 -) { - Ownable.assert_only_owner(); - ERC721._mint(to, tokenId); - return (); -} - -@external -func burn{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}(tokenId: Uint256) { - ERC721.assert_only_token_owner(tokenId); - ERC721._burn(tokenId); - return (); -} - -@external -func setTokenURI{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - tokenId: Uint256, tokenURI: felt -) { - Ownable.assert_only_owner(); - ERC721._set_token_uri(tokenId, tokenURI); - return (); -} - -@external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - newOwner: felt -) { - Ownable.transfer_ownership(newOwner); - return (); -} - -@external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); -} diff --git a/src/openzeppelin/token/erc721/presets/ERC721MintablePausable.cairo b/src/openzeppelin/token/erc721/presets/ERC721MintablePausable.cairo deleted file mode 100644 index 6d9ca1b60..000000000 --- a/src/openzeppelin/token/erc721/presets/ERC721MintablePausable.cairo +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/presets/ERC721MintablePausable.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.access.ownable.library import Ownable -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.security.pausable.library import Pausable -from openzeppelin.token.erc721.library import ERC721 - -// -// Constructor -// - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, owner: felt -) { - ERC721.initializer(name, symbol); - Ownable.initializer(owner); - return (); -} - -// -// Getters -// - -@view -func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) -> (success: felt) { - return ERC165.supports_interface(interfaceId); -} - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC721.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC721.symbol(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> ( - balance: Uint256 -) { - return ERC721.balance_of(owner); -} - -@view -func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(tokenId: Uint256) -> ( - owner: felt -) { - return ERC721.owner_of(tokenId); -} - -@view -func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - tokenId: Uint256 -) -> (approved: felt) { - return ERC721.get_approved(tokenId); -} - -@view -func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, operator: felt -) -> (approved: felt) { - return ERC721.is_approved_for_all(owner, operator); -} - -@view -func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - tokenId: Uint256 -) -> (tokenURI: felt) { - let (tokenURI: felt) = ERC721.token_uri(tokenId); - return (tokenURI=tokenURI); -} - -@view -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - -@view -func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) { - return Pausable.is_paused(); -} - -// -// Externals -// - -@external -func approve{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256 -) { - Pausable.assert_not_paused(); - ERC721.approve(to, tokenId); - return (); -} - -@external -func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - operator: felt, approved: felt -) { - Pausable.assert_not_paused(); - ERC721.set_approval_for_all(operator, approved); - return (); -} - -@external -func transferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, tokenId: Uint256 -) { - Pausable.assert_not_paused(); - ERC721.transfer_from(from_, to, tokenId); - return (); -} - -@external -func safeTransferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt* -) { - Pausable.assert_not_paused(); - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data); - return (); -} - -@external -func mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256 -) { - Pausable.assert_not_paused(); - Ownable.assert_only_owner(); - ERC721._mint(to, tokenId); - return (); -} - -@external -func setTokenURI{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - tokenId: Uint256, tokenURI: felt -) { - Ownable.assert_only_owner(); - ERC721._set_token_uri(tokenId, tokenURI); - return (); -} - -@external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - newOwner: felt -) { - Ownable.transfer_ownership(newOwner); - return (); -} - -@external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); -} - -@external -func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.assert_only_owner(); - Pausable._pause(); - return (); -} - -@external -func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.assert_only_owner(); - Pausable._unpause(); - return (); -} diff --git a/src/openzeppelin/token/erc721/presets/utils/ERC721Holder.cairo b/src/openzeppelin/token/erc721/presets/utils/ERC721Holder.cairo deleted file mode 100644 index f29530a97..000000000 --- a/src/openzeppelin/token/erc721/presets/utils/ERC721Holder.cairo +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (token/erc721/presets/utils/ERC721Holder.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.utils.constants.library import IERC721_RECEIVER_ID - -from openzeppelin.introspection.erc165.library import ERC165 - -@view -func onERC721Received( - operator: felt, from_: felt, tokenId: Uint256, data_len: felt, data: felt* -) -> (selector: felt) { - return (selector=IERC721_RECEIVER_ID); -} - -@view -func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) -> (success: felt) { - return ERC165.supports_interface(interfaceId); -} - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - ERC165.register_interface(IERC721_RECEIVER_ID); - return (); -} diff --git a/src/openzeppelin/upgrades/library.cairo b/src/openzeppelin/upgrades/library.cairo deleted file mode 100644 index e94d9e9d7..000000000 --- a/src/openzeppelin/upgrades/library.cairo +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (upgrades/library.cairo) - -%lang starknet - -from starkware.starknet.common.syscalls import get_caller_address -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.bool import TRUE, FALSE -from starkware.cairo.common.math import assert_not_zero - -// -// Events -// - -@event -func Upgraded(implementation: felt) { -} - -@event -func AdminChanged(previousAdmin: felt, newAdmin: felt) { -} - -// -// Storage variables -// - -@storage_var -func Proxy_implementation_hash() -> (implementation: felt) { -} - -@storage_var -func Proxy_admin() -> (admin: felt) { -} - -@storage_var -func Proxy_initialized() -> (initialized: felt) { -} - -namespace Proxy { - // - // Initializer - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - proxy_admin: felt - ) { - let (initialized) = Proxy_initialized.read(); - with_attr error_message("Proxy: contract already initialized") { - assert initialized = FALSE; - } - - Proxy_initialized.write(TRUE); - _set_admin(proxy_admin); - return (); - } - - // - // Guards - // - - func assert_only_admin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - let (caller) = get_caller_address(); - let (admin) = Proxy_admin.read(); - with_attr error_message("Proxy: caller is not admin") { - assert admin = caller; - } - return (); - } - - // - // Getters - // - - func get_implementation_hash{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - ) -> (implementation: felt) { - return Proxy_implementation_hash.read(); - } - - func get_admin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - admin: felt - ) { - return Proxy_admin.read(); - } - - // - // Unprotected - // - - func _set_admin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_admin: felt - ) { - let (previous_admin) = get_admin(); - Proxy_admin.write(new_admin); - AdminChanged.emit(previous_admin, new_admin); - return (); - } - - // - // Upgrade - // - - func _set_implementation_hash{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_implementation: felt - ) { - with_attr error_message("Proxy: implementation hash cannot be zero") { - assert_not_zero(new_implementation); - } - - Proxy_implementation_hash.write(new_implementation); - Upgraded.emit(new_implementation); - return (); - } -} diff --git a/src/openzeppelin/upgrades/presets/Proxy.cairo b/src/openzeppelin/upgrades/presets/Proxy.cairo deleted file mode 100644 index b0360acf4..000000000 --- a/src/openzeppelin/upgrades/presets/Proxy.cairo +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (upgrades/presets/Proxy.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.starknet.common.syscalls import library_call, library_call_l1_handler - -from openzeppelin.upgrades.library import Proxy - -// @dev Cairo doesn't support native decoding like Solidity yet, -// that's why we pass three arguments for calldata instead of one -// @param implementation_hash the implementation contract hash -// @param selector the implementation initializer function selector -// @param calldata_len the calldata length for the initializer -// @param calldata an array of felt containing the raw calldata -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - implementation_hash: felt, selector: felt, - calldata_len: felt, calldata: felt* -) { - alloc_locals; - Proxy._set_implementation_hash(implementation_hash); - - if (selector != 0) { - // Initialize proxy from implementation - library_call( - class_hash=implementation_hash, - function_selector=selector, - calldata_size=calldata_len, - calldata=calldata, - ); - } - - return (); -} - -// -// Fallback functions -// - -@external -@raw_input -@raw_output -func __default__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - selector: felt, calldata_size: felt, calldata: felt* -) -> (retdata_size: felt, retdata: felt*) { - let (class_hash) = Proxy.get_implementation_hash(); - - let (retdata_size: felt, retdata: felt*) = library_call( - class_hash=class_hash, - function_selector=selector, - calldata_size=calldata_size, - calldata=calldata, - ); - return (retdata_size, retdata); -} - -@l1_handler -@raw_input -func __l1_default__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - selector: felt, calldata_size: felt, calldata: felt* -) { - let (class_hash) = Proxy.get_implementation_hash(); - - library_call_l1_handler( - class_hash=class_hash, - function_selector=selector, - calldata_size=calldata_size, - calldata=calldata, - ); - return (); -} diff --git a/src/openzeppelin/utils/constants/library.cairo b/src/openzeppelin/utils/constants/library.cairo deleted file mode 100644 index 29c10b6d8..000000000 --- a/src/openzeppelin/utils/constants/library.cairo +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (utils/constants/library.cairo) - -%lang starknet - -// -// Numbers -// - -const UINT8_MAX = 255; - -// -// Interface Ids -// - -// ERC165 -const IERC165_ID = 0x01ffc9a7; -const INVALID_ID = 0xffffffff; - -// Account -const IACCOUNT_ID = 0xa66bd575; - -// ERC721 -const IERC721_ID = 0x80ac58cd; -const IERC721_RECEIVER_ID = 0x150b7a02; -const IERC721_METADATA_ID = 0x5b5e139f; -const IERC721_ENUMERABLE_ID = 0x780e9d63; - -// ERC1155 -const IERC1155_ID = 0xd9b67a26; -const IERC1155_METADATA_ID = 0x0e89341c; -const IERC1155_RECEIVER_ID = 0x4e2312e0; -const ON_ERC1155_RECEIVED_SELECTOR = 0xf23a6e61; -const ON_ERC1155_BATCH_RECEIVED_SELECTOR = 0xbc197c81; - -// AccessControl -const IACCESSCONTROL_ID = 0x7965db0b; - -// -// Roles -// - -const DEFAULT_ADMIN_ROLE = 0; - -// -// Starknet -// - -const TRANSACTION_VERSION = 1; diff --git a/src/openzeppelin/utils/presets/UniversalDeployer.cairo b/src/openzeppelin/utils/presets/UniversalDeployer.cairo deleted file mode 100644 index a3eb80574..000000000 --- a/src/openzeppelin/utils/presets/UniversalDeployer.cairo +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (utils/presets/UniversalDeployer.cairo) - -%lang starknet - -from starkware.starknet.common.syscalls import get_caller_address, deploy -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.hash import hash2 -from starkware.cairo.common.bool import FALSE, TRUE - -@event -func ContractDeployed( - address: felt, - deployer: felt, - unique: felt, - classHash: felt, - calldata_len: felt, - calldata: felt*, - salt: felt -) { -} - -@external -func deployContract{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -}( - classHash: felt, - salt: felt, - unique: felt, - calldata_len: felt, - calldata: felt* -) -> (address: felt) { - alloc_locals; - let (deployer) = get_caller_address(); - - local _salt; - local from_zero; - if (unique == TRUE) { - let (unique_salt) = hash2{hash_ptr=pedersen_ptr}(deployer, salt); - _salt = unique_salt; - from_zero = FALSE; - tempvar _pedersen = pedersen_ptr; - } else { - _salt = salt; - from_zero = TRUE; - tempvar _pedersen = pedersen_ptr; - } - - let pedersen_ptr = _pedersen; - - let (address) = deploy( - class_hash=classHash, - contract_address_salt=_salt, - constructor_calldata_size=calldata_len, - constructor_calldata=calldata, - deploy_from_zero=from_zero, - ); - - ContractDeployed.emit( - address=address, - deployer=deployer, - unique=unique, - classHash=classHash, - calldata_len=calldata_len, - calldata=calldata, - salt=salt - ); - - return (address=address); -} diff --git a/tests/access/OwnableBaseSuite.py b/tests/access/OwnableBaseSuite.py deleted file mode 100644 index 63b513dd4..000000000 --- a/tests/access/OwnableBaseSuite.py +++ /dev/null @@ -1,65 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import ZERO_ADDRESS -from utils import assert_event_emitted - - -signer = MockSigner(123456789987654321) - - -class OwnableBase: - @pytest.mark.asyncio - async def test_constructor(self, contract_factory): - ownable, owner, *_ = contract_factory - expected = await ownable.owner().call() - assert expected.result.owner == owner.contract_address - - - @pytest.mark.asyncio - async def test_transferOwnership(self, contract_factory): - ownable, owner, *_ = contract_factory - new_owner = 123 - await signer.send_transaction(owner, ownable.contract_address, 'transferOwnership', [new_owner]) - executed_info = await ownable.owner().call() - assert executed_info.result == (new_owner,) - - - @pytest.mark.asyncio - async def test_transferOwnership_emits_event(self, contract_factory): - ownable, owner, *_ = contract_factory - new_owner = 123 - tx_exec_info = await signer.send_transaction(owner, ownable.contract_address, 'transferOwnership', [new_owner]) - - assert_event_emitted( - tx_exec_info, - from_address=ownable.contract_address, - name='OwnershipTransferred', - data=[ - owner.contract_address, - new_owner - ] - ) - - - @pytest.mark.asyncio - async def test_renounceOwnership(self, contract_factory): - ownable, owner, *_ = contract_factory - await signer.send_transaction(owner, ownable.contract_address, 'renounceOwnership', []) - executed_info = await ownable.owner().call() - assert executed_info.result == (ZERO_ADDRESS,) - - - @pytest.mark.asyncio - async def test_renounceOwnership_emits_event(self, contract_factory): - ownable, owner, *_ = contract_factory - tx_exec_info = await signer.send_transaction(owner, ownable.contract_address, 'renounceOwnership', []) - - assert_event_emitted( - tx_exec_info, - from_address=ownable.contract_address, - name='OwnershipTransferred', - data=[ - owner.contract_address, - ZERO_ADDRESS - ] - ) diff --git a/tests/access/test_AccessControl.py b/tests/access/test_AccessControl.py deleted file mode 100644 index e1f81fc08..000000000 --- a/tests/access/test_AccessControl.py +++ /dev/null @@ -1,231 +0,0 @@ -import pytest -from pathlib import Path -from signers import MockSigner -from nile.utils import TRUE, FALSE, assert_revert -from utils import ( - State, Account, assert_event_emitted, get_contract_class, cached_contract -) - -DEFAULT_ADMIN_ROLE = 0 -SOME_OTHER_ROLE = 42 -IACCESSCONTROL_ID = 0x7965db0b - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - return { - Path(key).stem: get_contract_class(key) - for key in [ - 'Account', - 'AccessControl', - ] - } - - -@pytest.fixture(scope='module') -async def accesscontrol_init(contract_classes): - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - accesscontrol = await starknet.deploy( - contract_class=contract_classes['AccessControl'], - constructor_calldata=[account1.contract_address] - ) - return starknet.state, accesscontrol, account1, account2 - - -@pytest.fixture -def accesscontrol_factory(contract_classes, accesscontrol_init): - state, accesscontrol, account1, account2 = accesscontrol_init - _state = state.copy() - accesscontrol = cached_contract( - _state, contract_classes['AccessControl'], accesscontrol) - account1 = cached_contract(_state, Account.get_class, account1) - account2 = cached_contract(_state, Account.get_class, account2) - return accesscontrol, account1, account2 - - -@pytest.mark.asyncio -async def test_initializer(accesscontrol_factory): - accesscontrol, _, _ = accesscontrol_factory - - execution_info = await accesscontrol.supportsInterface(IACCESSCONTROL_ID).execute() - assert execution_info.result == (TRUE,) - - -@ pytest.mark.asyncio -async def test_grant_role(accesscontrol_factory): - accesscontrol, account1, account2 = accesscontrol_factory - - tx_exec_info = await signer.send_transaction( - account1, - accesscontrol.contract_address, - 'grantRole', - [ - DEFAULT_ADMIN_ROLE, - account2.contract_address - ] - ) - - assert_event_emitted( - tx_exec_info, - from_address=accesscontrol.contract_address, - name='RoleGranted', - data=[ - DEFAULT_ADMIN_ROLE, # role - account2.contract_address, # account - account1.contract_address # sender - ] - ) - - expected = await accesscontrol.hasRole(DEFAULT_ADMIN_ROLE, account2.contract_address).execute() - assert expected.result.hasRole == TRUE - - -@ pytest.mark.asyncio -async def test_grant_role_unauthorized(accesscontrol_factory): - accesscontrol, _, account2 = accesscontrol_factory - - await assert_revert( - signer.send_transaction(account2, accesscontrol.contract_address, 'grantRole', [ - DEFAULT_ADMIN_ROLE, account2.contract_address]), - reverted_with="AccessControl: caller is missing role {}".format( - DEFAULT_ADMIN_ROLE) - ) - - -@ pytest.mark.asyncio -async def test_revoke_role(accesscontrol_factory): - accesscontrol, account1, account2 = accesscontrol_factory - - await signer.send_transaction(account1, accesscontrol.contract_address, 'grantRole', [DEFAULT_ADMIN_ROLE, account2.contract_address]) - - tx_exec_info = await signer.send_transaction(account2, accesscontrol.contract_address, 'revokeRole', [DEFAULT_ADMIN_ROLE, account1.contract_address]) - assert_event_emitted( - tx_exec_info, - from_address=accesscontrol.contract_address, - name='RoleRevoked', - data=[ - DEFAULT_ADMIN_ROLE, # role - account1.contract_address, # account - account2.contract_address # sender - ] - ) - expected = await accesscontrol.hasRole(DEFAULT_ADMIN_ROLE, account1.contract_address).execute() - assert expected.result.hasRole == FALSE - - -@ pytest.mark.asyncio -async def test_revoke_role_unauthorized(accesscontrol_factory): - accesscontrol, account1, account2 = accesscontrol_factory - - await assert_revert( - signer.send_transaction( - account2, - accesscontrol.contract_address, - 'revokeRole', - [ - DEFAULT_ADMIN_ROLE, - account1.contract_address - ] - ), - reverted_with="AccessControl: caller is missing role {}".format( - DEFAULT_ADMIN_ROLE - ) - ) - - -@ pytest.mark.asyncio -async def test_renounce_role(accesscontrol_factory): - accesscontrol, account1, _ = accesscontrol_factory - - tx_exec_info = await signer.send_transaction( - account1, - accesscontrol.contract_address, - 'renounceRole', - [ - DEFAULT_ADMIN_ROLE, - account1.contract_address - ] - ) - - assert_event_emitted( - tx_exec_info, - from_address=accesscontrol.contract_address, - name='RoleRevoked', - data=[ - DEFAULT_ADMIN_ROLE, # role - account1.contract_address, # account - account1.contract_address # sender - ] - ) - - expected = await accesscontrol.hasRole(DEFAULT_ADMIN_ROLE, account1.contract_address).execute() - assert expected.result.hasRole == FALSE - - -@ pytest.mark.asyncio -async def test_renounce_role_unauthorized(accesscontrol_factory): - accesscontrol, account1, account2 = accesscontrol_factory - - await assert_revert( - signer.send_transaction( - account1, - accesscontrol.contract_address, - 'renounceRole', - [ - DEFAULT_ADMIN_ROLE, - account2.contract_address - ] - ), - reverted_with="AccessControl: can only renounce roles for self" - ) - - -@ pytest.mark.asyncio -async def test_set_role_admin(accesscontrol_factory): - accesscontrol, account1, account2 = accesscontrol_factory - - tx_exec_info = await signer.send_transaction( - account1, - accesscontrol.contract_address, - 'setRoleAdmin', - [DEFAULT_ADMIN_ROLE, SOME_OTHER_ROLE] - ) - - assert_event_emitted( - tx_exec_info, - from_address=accesscontrol.contract_address, - name='RoleAdminChanged', - data=[ - DEFAULT_ADMIN_ROLE, # role - DEFAULT_ADMIN_ROLE, # previousAdminRole - SOME_OTHER_ROLE # newAdminRole - ] - ) - - expected = await accesscontrol.getRoleAdmin(DEFAULT_ADMIN_ROLE).execute() - assert expected.result.admin == SOME_OTHER_ROLE - - # test role admin cycle - await signer.send_transaction( - account1, - accesscontrol.contract_address, - 'grantRole', - [SOME_OTHER_ROLE, account2.contract_address] - ) - - expected = await accesscontrol.hasRole(SOME_OTHER_ROLE, account2.contract_address).execute() - assert expected.result.hasRole == TRUE - - await signer.send_transaction( - account2, - accesscontrol.contract_address, - 'revokeRole', - [DEFAULT_ADMIN_ROLE, account1.contract_address] - ) - - expected = await accesscontrol.hasRole(DEFAULT_ADMIN_ROLE, account1.contract_address).execute() - assert expected.result.hasRole == FALSE diff --git a/tests/access/test_Ownable.py b/tests/access/test_Ownable.py deleted file mode 100644 index d9541faef..000000000 --- a/tests/access/test_Ownable.py +++ /dev/null @@ -1,63 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import assert_revert -from utils import State, Account, get_contract_class, cached_contract -from OwnableBaseSuite import OwnableBase - - -signer = MockSigner(123456789987654321) - -@pytest.fixture(scope='module') -def contract_classes(): - return ( - Account.get_class, - get_contract_class('Ownable') - ) - - -@pytest.fixture(scope='module') -async def ownable_init(contract_classes): - account_cls, ownable_cls = contract_classes - starknet = await State.init() - owner = await Account.deploy(signer.public_key) - ownable = await starknet.deploy( - contract_class=ownable_cls, - constructor_calldata=[owner.contract_address] - ) - not_owner = await Account.deploy(signer.public_key) - return starknet.state, ownable, owner, not_owner - - -@pytest.fixture -def contract_factory(contract_classes, ownable_init): - account_cls, ownable_cls = contract_classes - state, ownable, owner, not_owner = ownable_init - _state = state.copy() - owner = cached_contract(_state, account_cls, owner) - ownable = cached_contract(_state, ownable_cls, ownable) - not_owner = cached_contract(_state, account_cls, not_owner) - return ownable, owner, not_owner - - -class TestOwnable(OwnableBase): - @pytest.mark.asyncio - async def test_contract_without_owner(self, contract_factory): - ownable, owner, _ = contract_factory - await signer.send_transaction(owner, ownable.contract_address, 'renounceOwnership', []) - - # Protected function should not be called from zero address - await assert_revert( - ownable.protected_function().execute(), - reverted_with="Ownable: caller is the zero address" - ) - - - @pytest.mark.asyncio - async def test_contract_caller_not_owner(self, contract_factory): - ownable, owner, not_owner = contract_factory - - # Protected function should only be called from owner - await assert_revert( - signer.send_transaction(not_owner, ownable.contract_address, 'protected_function', []), - reverted_with="Ownable: caller is not the owner" - ) diff --git a/tests/account/test_Account.py b/tests/account/test_Account.py deleted file mode 100644 index 67cae651c..000000000 --- a/tests/account/test_Account.py +++ /dev/null @@ -1,243 +0,0 @@ -import pytest -from signers import MockSigner, get_raw_invoke -from nile.utils import TRUE, assert_revert -from utils import get_contract_class, cached_contract, State, Account, IACCOUNT_ID - - -signer = MockSigner(123456789987654321) -other = MockSigner(987654321123456789) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - init_cls = get_contract_class("Initializable") - attacker_cls = get_contract_class("AccountReentrancy") - - return account_cls, init_cls, attacker_cls - - -@pytest.fixture(scope='module') -async def account_init(contract_classes): - _, init_cls, attacker_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - - initializable1 = await starknet.deploy( - contract_class=init_cls, - constructor_calldata=[], - ) - initializable2 = await starknet.deploy( - contract_class=init_cls, - constructor_calldata=[], - ) - attacker = await starknet.deploy( - contract_class=attacker_cls, - constructor_calldata=[], - ) - - return starknet.state, account1, account2, initializable1, initializable2, attacker - - -@pytest.fixture -def account_factory(contract_classes, account_init): - account_cls, init_cls, attacker_cls = contract_classes - state, account1, account2, initializable1, initializable2, attacker = account_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - initializable1 = cached_contract(_state, init_cls, initializable1) - initializable2 = cached_contract(_state, init_cls, initializable2) - attacker = cached_contract(_state, attacker_cls, attacker) - - return account1, account2, initializable1, initializable2, attacker - - -@pytest.mark.asyncio -async def test_counterfactual_deployment(account_factory): - account, *_ = account_factory - await signer.declare_class(account, "Account") - - execution_info = await signer.deploy_account(account.state, [signer.public_key]) - address = execution_info.validate_info.contract_address - - execution_info = await signer.send_transaction(account, address, 'getPublicKey', []) - assert execution_info.call_info.retdata[1] == signer.public_key - - -@pytest.mark.asyncio -async def test_constructor(account_factory): - account, *_ = account_factory - - execution_info = await account.getPublicKey().call() - assert execution_info.result == (signer.public_key,) - - execution_info = await account.supportsInterface(IACCOUNT_ID).call() - assert execution_info.result == (TRUE,) - - -@pytest.mark.asyncio -async def test_is_valid_signature(account_factory): - account, *_ = account_factory - hash = 0x23564 - signature = signer.sign(hash) - - execution_info = await account.isValidSignature(hash, signature).call() - assert execution_info.result == (TRUE,) - - # should revert if signature is not correct - await assert_revert( - account.isValidSignature(hash + 1, signature).call(), - reverted_with=( - f"Signature {tuple(signature)}, is invalid, with respect to the public key {signer.public_key}, " - f"and the message hash {hash + 1}." - ) - ) - - -@pytest.mark.asyncio -async def test_declare(account_factory): - account, *_ = account_factory - - # regular declare works - await signer.declare_class(account, "ERC20") - - # wrong signer fails - await assert_revert( - other.declare_class(account, "ERC20"), - reverted_with="is invalid, with respect to the public key" - ) - - -@pytest.mark.asyncio -async def test_execute(account_factory): - account, _, initializable, *_ = account_factory - - execution_info = await initializable.initialized().call() - assert execution_info.result == (0,) - - await signer.send_transaction(account, initializable.contract_address, 'initialize', []) - - execution_info = await initializable.initialized().call() - assert execution_info.result == (1,) - - # wrong signer fails - await assert_revert( - other.send_transaction(account, initializable.contract_address, 'initialize', []), - reverted_with="is invalid, with respect to the public key" - ) - - -@pytest.mark.asyncio -async def test_multicall(account_factory): - account, _, initializable_1, initializable_2, _ = account_factory - - execution_info = await initializable_1.initialized().call() - assert execution_info.result == (0,) - execution_info = await initializable_2.initialized().call() - assert execution_info.result == (0,) - - await signer.send_transactions( - account, - [ - (initializable_1.contract_address, 'initialize', []), - (initializable_2.contract_address, 'initialize', []) - ] - ) - - execution_info = await initializable_1.initialized().call() - assert execution_info.result == (1,) - execution_info = await initializable_2.initialized().call() - assert execution_info.result == (1,) - - -@pytest.mark.asyncio -async def test_return_value(account_factory): - account, _, initializable, *_ = account_factory - - # initialize, set `initialized = 1` - await signer.send_transaction(account, initializable.contract_address, 'initialize', []) - - read_info = await signer.send_transaction(account, initializable.contract_address, 'initialized', []) - call_info = await initializable.initialized().call() - (call_result, ) = call_info.result - assert read_info.call_info.retdata[1] == call_result # 1 - - -@ pytest.mark.asyncio -async def test_nonce(account_factory): - account, _, initializable, *_ = account_factory - - # bump nonce - await signer.send_transaction(account, initializable.contract_address, 'initialized', []) - - # get nonce - args = [(initializable.contract_address, 'initialized', [])] - raw_invocation = get_raw_invoke(account, args) - current_nonce = await raw_invocation.state.state.get_nonce_at(account.contract_address) - - # lower nonce - await assert_revert( - signer.send_transaction(account, initializable.contract_address, 'initialize', [], nonce=current_nonce - 1), - reverted_with="Invalid transaction nonce. Expected: {}, got: {}.".format( - current_nonce, current_nonce - 1 - ) - ) - - # higher nonce - await assert_revert( - signer.send_transaction(account, initializable.contract_address, 'initialize', [], nonce=current_nonce + 1), - reverted_with="Invalid transaction nonce. Expected: {}, got: {}.".format( - current_nonce, current_nonce + 1 - ) - ) - - # right nonce - await signer.send_transaction(account, initializable.contract_address, 'initialize', [], nonce=current_nonce) - - execution_info = await initializable.initialized().call() - assert execution_info.result == (1,) - - -@pytest.mark.asyncio -async def test_public_key_setter(account_factory): - account, *_ = account_factory - - execution_info = await account.getPublicKey().call() - assert execution_info.result == (signer.public_key,) - - # set new pubkey - await signer.send_transaction(account, account.contract_address, 'setPublicKey', [other.public_key]) - - execution_info = await account.getPublicKey().call() - assert execution_info.result == (other.public_key,) - - -@pytest.mark.asyncio -async def test_public_key_setter_different_account(account_factory): - account, bad_account, *_ = account_factory - - # set new pubkey - await assert_revert( - signer.send_transaction(bad_account, account.contract_address, 'setPublicKey', [other.public_key]), - reverted_with="Account: caller is not this account" - ) - - -@pytest.mark.asyncio -async def test_account_takeover_with_reentrant_call(account_factory): - account, _, _, _, attacker = account_factory - - await assert_revert( - signer.send_transaction( - account, attacker.contract_address, 'account_takeover', []), - reverted_with="Account: reentrant call" - ) - - execution_info = await account.getPublicKey().call() - assert execution_info.result == (signer.public_key,) - - -async def test_interface(): - assert get_contract_class("IAccount") diff --git a/tests/account/test_AddressRegistry.py b/tests/account/test_AddressRegistry.py deleted file mode 100644 index 0e202f86d..000000000 --- a/tests/account/test_AddressRegistry.py +++ /dev/null @@ -1,58 +0,0 @@ -import pytest -from signers import MockSigner -from utils import get_contract_class, cached_contract, State, Account - - -signer = MockSigner(123456789987654321) -L1_ADDRESS = 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984 -ANOTHER_ADDRESS = 0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f - -@pytest.fixture(scope='module') -async def registry_factory(): - # contract classes - registry_cls = get_contract_class("AddressRegistry") - account_cls = Account.get_class - - # deployments - starknet = await State.init() - account = await Account.deploy(signer.public_key) - registry = await starknet.deploy( - contract_class=registry_cls, - constructor_calldata=[] - ) - - # cache contracts - state = starknet.state.copy() - account = cached_contract(state, account_cls, account) - registry = cached_contract(state, registry_cls, registry) - - return account, registry - - -@pytest.mark.asyncio -async def test_set_address(registry_factory): - account, registry = registry_factory - - await signer.send_transaction( - account, registry.contract_address, 'set_L1_address', [L1_ADDRESS] - ) - execution_info = await registry.get_L1_address(account.contract_address).call() - assert execution_info.result == (L1_ADDRESS,) - - -@pytest.mark.asyncio -async def test_update_address(registry_factory): - account, registry = registry_factory - - await signer.send_transaction( - account, registry.contract_address, 'set_L1_address', [L1_ADDRESS] - ) - execution_info = await registry.get_L1_address(account.contract_address).call() - assert execution_info.result == (L1_ADDRESS,) - - # set new address - await signer.send_transaction( - account, registry.contract_address, 'set_L1_address', [ANOTHER_ADDRESS] - ) - execution_info = await registry.get_L1_address(account.contract_address).call() - assert execution_info.result == (ANOTHER_ADDRESS,) diff --git a/tests/account/test_EthAccount.py b/tests/account/test_EthAccount.py deleted file mode 100644 index 9c1aada21..000000000 --- a/tests/account/test_EthAccount.py +++ /dev/null @@ -1,240 +0,0 @@ -import pytest -from nile.utils import assert_revert, TRUE, FALSE -from utils import get_contract_class, cached_contract, State, IACCOUNT_ID -from signers import MockEthSigner, get_raw_invoke - -private_key = b'\x01' * 32 -signer = MockEthSigner(b'\x01' * 32) -other = MockEthSigner(b'\x02' * 32) - - -@pytest.fixture(scope='module') -def contract_defs(): - account_cls = get_contract_class('EthAccount') - init_cls = get_contract_class("Initializable") - attacker_cls = get_contract_class("AccountReentrancy") - - return account_cls, init_cls, attacker_cls - - -@pytest.fixture(scope='module') -async def account_init(contract_defs): - account_cls, init_cls, attacker_cls = contract_defs - starknet = await State.init() - - account1 = await starknet.deploy( - contract_class=account_cls, - constructor_calldata=[signer.eth_address] - ) - account2 = await starknet.deploy( - contract_class=account_cls, - constructor_calldata=[signer.eth_address] - ) - initializable1 = await starknet.deploy( - contract_class=init_cls, - constructor_calldata=[], - ) - initializable2 = await starknet.deploy( - contract_class=init_cls, - constructor_calldata=[], - ) - attacker = await starknet.deploy( - contract_class=attacker_cls, - constructor_calldata=[], - ) - - return starknet.state, account1, account2, initializable1, initializable2, attacker - - -@pytest.fixture -def account_factory(contract_defs, account_init): - account_cls, init_cls, attacker_cls = contract_defs - state, account1, account2, initializable1, initializable2, attacker = account_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - initializable1 = cached_contract(_state, init_cls, initializable1) - initializable2 = cached_contract(_state, init_cls, initializable2) - attacker = cached_contract(_state, attacker_cls, attacker) - - return account1, account2, initializable1, initializable2, attacker - - -@pytest.mark.asyncio -async def test_counterfactual_deployment(account_factory): - account, *_ = account_factory - await signer.declare_class(account, "EthAccount") - - execution_info = await signer.deploy_account(account.state, [signer.eth_address]) - address = execution_info.validate_info.contract_address - - execution_info = await signer.send_transaction(account, address, 'getEthAddress', []) - assert execution_info.call_info.retdata[1] == signer.eth_address - - -@pytest.mark.asyncio -async def test_constructor(account_factory): - account, *_ = account_factory - - execution_info = await account.getEthAddress().call() - assert execution_info.result == (signer.eth_address,) - - execution_info = await account.supportsInterface(IACCOUNT_ID).call() - assert execution_info.result == (TRUE,) - - -@pytest.mark.asyncio -async def test_is_valid_signature(account_factory): - account, *_ = account_factory - hash = 0x23564 - signature = signer.sign(hash) - - execution_info = await account.isValidSignature(hash, signature).call() - assert execution_info.result == (TRUE,) - - # should revert if signature is not correct - await assert_revert( - account.isValidSignature(hash + 1, signature).call(), - reverted_with="Invalid signature" - ) - - -@pytest.mark.asyncio -async def test_declare(account_factory): - account, *_ = account_factory - - # regular declare works - await signer.declare_class(account, "ERC20") - - # wrong signer fails - await assert_revert( - other.declare_class(account, "ERC20"), - reverted_with="Invalid signature" - ) - - -@pytest.mark.asyncio -async def test_execute(account_factory): - account, _, initializable, *_ = account_factory - - execution_info = await initializable.initialized().call() - assert execution_info.result == (FALSE,) - - await signer.send_transaction(account, initializable.contract_address, 'initialize', []) - - execution_info = await initializable.initialized().call() - assert execution_info.result == (TRUE,) - - # wrong signer fails - await assert_revert( - other.send_transaction(account, initializable.contract_address, 'initialize', []), - reverted_with="Invalid signature" - ) - - -@pytest.mark.asyncio -async def test_multicall(account_factory): - account, _, initializable_1, initializable_2, _ = account_factory - - execution_info = await initializable_1.initialized().call() - assert execution_info.result == (FALSE,) - execution_info = await initializable_2.initialized().call() - assert execution_info.result == (FALSE,) - - await signer.send_transactions( - account, - [ - (initializable_1.contract_address, 'initialize', []), - (initializable_2.contract_address, 'initialize', []) - ] - ) - - execution_info = await initializable_1.initialized().call() - assert execution_info.result == (TRUE,) - execution_info = await initializable_2.initialized().call() - assert execution_info.result == (TRUE,) - - -@pytest.mark.asyncio -async def test_return_value(account_factory): - account, _, initializable, *_ = account_factory - - # initialize, set `initialized = 1` - await signer.send_transaction(account, initializable.contract_address, 'initialize', []) - - read_info = await signer.send_transaction(account, initializable.contract_address, 'initialized', []) - call_info = await initializable.initialized().call() - (call_result, ) = call_info.result - assert read_info.call_info.retdata[1] == call_result # 1 - - -@ pytest.mark.asyncio -async def test_nonce(account_factory): - account, _, initializable, *_ = account_factory - - # bump nonce - await signer.send_transaction(account, initializable.contract_address, 'initialized', []) - - args = [(initializable.contract_address, 'initialized', [])] - raw_invocation = get_raw_invoke(account, args) - current_nonce = await raw_invocation.state.state.get_nonce_at(account.contract_address) - - # lower nonce - await assert_revert( - signer.send_transaction(account, initializable.contract_address, 'initialize', [], current_nonce - 1), - reverted_with="Invalid transaction nonce. Expected: {}, got: {}.".format( - current_nonce, current_nonce - 1 - ) - ) - - # higher nonce - await assert_revert( - signer.send_transaction(account, initializable.contract_address, 'initialize', [], current_nonce + 1), - reverted_with="Invalid transaction nonce. Expected: {}, got: {}.".format( - current_nonce, current_nonce + 1 - ) - ) - - # right nonce - await signer.send_transaction(account, initializable.contract_address, 'initialize', [], current_nonce) - - execution_info = await initializable.initialized().call() - assert execution_info.result == (TRUE,) - - -@pytest.mark.asyncio -async def test_eth_address_setter(account_factory): - account, *_ = account_factory - - execution_info = await account.getEthAddress().call() - assert execution_info.result == (signer.eth_address,) - - # set new pubkey - await signer.send_transaction(account, account.contract_address, 'setEthAddress', [other.eth_address]) - - execution_info = await account.getEthAddress().call() - assert execution_info.result == (other.eth_address,) - - -@pytest.mark.asyncio -async def test_eth_address_setter_different_account(account_factory): - account, bad_account, *_ = account_factory - - # set new pubkey - await assert_revert( - signer.send_transaction(bad_account, account.contract_address, 'setEthAddress', [signer.eth_address]), - reverted_with="Account: caller is not this account" - ) - - -@pytest.mark.asyncio -async def test_account_takeover_with_reentrant_call(account_factory): - account, _, _, _, attacker = account_factory - - await assert_revert( - signer.send_transaction(account, attacker.contract_address, 'account_takeover', []), - reverted_with="Account: reentrant call" - ) - - execution_info = await account.getEthAddress().call() - assert execution_info.result == (signer.eth_address,) diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 56a1af737..000000000 --- a/tests/conftest.py +++ /dev/null @@ -1,6 +0,0 @@ -import pytest -import asyncio - -@pytest.fixture(scope='module') -def event_loop(): - return asyncio.new_event_loop() diff --git a/tests/introspection/test_ERC165.py b/tests/introspection/test_ERC165.py deleted file mode 100644 index 52a8962a8..000000000 --- a/tests/introspection/test_ERC165.py +++ /dev/null @@ -1,68 +0,0 @@ -import pytest -from nile.utils import assert_revert, TRUE, FALSE -from utils import ( - get_contract_class, - cached_contract, - State -) - - -# interface ids -ERC165_ID = 0x01ffc9a7 -INVALID_ID = 0xffffffff -OTHER_ID = 0x12345678 - - -@pytest.fixture -async def erc165_factory(): - # class - erc165_cls = get_contract_class("tests/mocks/ERC165.cairo", is_path=True) - - # deployment - starknet = await State.init() - erc165 = await starknet.deploy(contract_class=erc165_cls) - - # cache - state = starknet.state.copy() - erc165 = cached_contract(state, erc165_cls, erc165) - return erc165 - - -@pytest.mark.asyncio -async def test_165_interface(erc165_factory): - erc165 = erc165_factory - - execution_info = await erc165.supportsInterface(ERC165_ID).call() - assert execution_info.result == (TRUE,) - - -@pytest.mark.asyncio -async def test_invalid_id(erc165_factory): - erc165 = erc165_factory - - execution_info = await erc165.supportsInterface(INVALID_ID).call() - assert execution_info.result == (FALSE,) - - -@pytest.mark.asyncio -async def test_register_interface(erc165_factory): - erc165 = erc165_factory - - execution_info = await erc165.supportsInterface(OTHER_ID).call() - assert execution_info.result == (FALSE,) - - # register interface - await erc165.registerInterface(OTHER_ID).execute() - - execution_info = await erc165.supportsInterface(OTHER_ID).call() - assert execution_info.result == (TRUE,) - - -@pytest.mark.asyncio -async def test_register_invalid_interface(erc165_factory): - erc165 = erc165_factory - - await assert_revert( - erc165.registerInterface(INVALID_ID).execute(), - reverted_with="ERC165: invalid interface id" - ) diff --git a/tests/mocks/AccessControl.cairo b/tests/mocks/AccessControl.cairo deleted file mode 100644 index b0edacfc1..000000000 --- a/tests/mocks/AccessControl.cairo +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.starknet.common.syscalls import get_caller_address -from openzeppelin.access.accesscontrol.library import AccessControl -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(admin: felt) { - AccessControl.initializer(); - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin); - return (); -} - -@view -func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt -) -> (hasRole: felt) { - let (hasRole) = AccessControl.has_role(role, user); - return (hasRole=hasRole); -} - -@view -func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(role: felt) -> ( - admin: felt -) { - return AccessControl.get_role_admin(role); -} - -@external -func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt -) { - AccessControl.grant_role(role, user); - return (); -} - -@external -func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt -) { - AccessControl.revoke_role(role, user); - return (); -} - -@external -func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, user: felt -) { - AccessControl.renounce_role(role, user); - return (); -} - -// ONLY FOR MOCKS, DON'T EXPOSE IN PRODUCTION -@external -func setRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - role: felt, admin: felt -) { - AccessControl._set_role_admin(role, admin); - return (); -} - -@view -func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) -> (success: felt) { - return ERC165.supports_interface(interfaceId); -} diff --git a/tests/mocks/AccountReentrancy.cairo b/tests/mocks/AccountReentrancy.cairo deleted file mode 100644 index ed03f78b9..000000000 --- a/tests/mocks/AccountReentrancy.cairo +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.starknet.common.syscalls import ( - call_contract, - get_caller_address, -) -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin - -from starkware.cairo.common.alloc import alloc - -const EXECUTE = 617075754465154585683856897856256838130216341506379215893724690153393808813; -const SET_PUBLIC_KEY = 332268845949430430346835224631316185987738351560356300584998172574125127129; - -@external -func account_takeover{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - alloc_locals; - let (caller) = get_caller_address(); - let (call_calldata: felt*) = alloc(); - - // call_array - assert call_calldata[0] = 1; - assert call_calldata[1] = caller; - assert call_calldata[2] = SET_PUBLIC_KEY; - assert call_calldata[3] = 0; - assert call_calldata[4] = 1; - - // calldata - assert call_calldata[5] = 1; - // new public key - assert call_calldata[6] = 123; - - - call_contract( - contract_address=caller, function_selector=EXECUTE, calldata_size=7, calldata=call_calldata - ); - - return (); -} diff --git a/tests/mocks/ERC1155Mock.cairo b/tests/mocks/ERC1155Mock.cairo deleted file mode 100644 index 17cbe5504..000000000 --- a/tests/mocks/ERC1155Mock.cairo +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT - -// This mock is to test functions from the ERC1155 library -// that are not exposed in any preset like `setURI` - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.token.erc1155.library import ERC1155 - - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - uri: felt, owner: felt -) { - ERC1155.initializer(uri); - return (); -} - -@view -func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(id: Uint256) -> ( - uri: felt -) { - return ERC1155.uri(id); -} - - -@external -func setURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(uri: felt) { - ERC1155._set_uri(uri); - return (); -} diff --git a/tests/mocks/ERC165.cairo b/tests/mocks/ERC165.cairo deleted file mode 100644 index 8771eac32..000000000 --- a/tests/mocks/ERC165.cairo +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin - -from openzeppelin.introspection.erc165.library import ERC165 - -@view -func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) -> (success: felt) { - return ERC165.supports_interface(interfaceId); -} - -@external -func registerInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) { - ERC165.register_interface(interfaceId); - return (); -} diff --git a/tests/mocks/ERC721SafeMintableMock.cairo b/tests/mocks/ERC721SafeMintableMock.cairo deleted file mode 100644 index a854dc10f..000000000 --- a/tests/mocks/ERC721SafeMintableMock.cairo +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.token.erc721.library import ERC721 -from openzeppelin.introspection.erc165.library import ERC165 -from openzeppelin.access.ownable.library import Ownable - -// -// Constructor -// - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, owner: felt -) { - ERC721.initializer(name, symbol); - Ownable.initializer(owner); - return (); -} - -// -// Getters -// - -@view -func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - interfaceId: felt -) -> (success: felt) { - return ERC165.supports_interface(interfaceId); -} - -@view -func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { - return ERC721.name(); -} - -@view -func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { - return ERC721.symbol(); -} - -@view -func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> ( - balance: Uint256 -) { - return ERC721.balance_of(owner); -} - -@view -func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(tokenId: Uint256) -> ( - owner: felt -) { - return ERC721.owner_of(tokenId); -} - -@view -func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - tokenId: Uint256 -) -> (approved: felt) { - return ERC721.get_approved(tokenId); -} - -@view -func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - owner: felt, operator: felt -) -> (approved: felt) { - return ERC721.is_approved_for_all(owner, operator); -} - -@view -func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - tokenId: Uint256 -) -> (tokenURI: felt) { - let (tokenURI: felt) = ERC721.token_uri(tokenId); - return (tokenURI=tokenURI); -} - -@view -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - -// -// Externals -// - -@external -func approve{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256 -) { - ERC721.approve(to, tokenId); - return (); -} - -@external -func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - operator: felt, approved: felt -) { - ERC721.set_approval_for_all(operator, approved); - return (); -} - -@external -func transferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, tokenId: Uint256 -) { - ERC721.transfer_from(from_, to, tokenId); - return (); -} - -@external -func safeTransferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt* -) { - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data); - return (); -} - -@external -func mint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256 -) { - Ownable.assert_only_owner(); - ERC721._mint(to, tokenId); - return (); -} - -@external -func safeMint{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - to: felt, tokenId: Uint256, data_len: felt, data: felt* -) { - Ownable.assert_only_owner(); - ERC721._safe_mint(to, tokenId, data_len, data); - return (); -} - -@external -func setTokenURI{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( - tokenId: Uint256, tokenURI: felt -) { - Ownable.assert_only_owner(); - ERC721._set_token_uri(tokenId, tokenURI); - return (); -} - -@external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - newOwner: felt -) { - Ownable.transfer_ownership(newOwner); - return (); -} - -@external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); -} diff --git a/tests/mocks/Initializable.cairo b/tests/mocks/Initializable.cairo deleted file mode 100644 index 7cddc5fc8..000000000 --- a/tests/mocks/Initializable.cairo +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin - -from openzeppelin.security.initializable.library import Initializable - -@view -func initialized{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (initialized: felt) { - return Initializable.initialized(); -} - -@external -func initialize{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Initializable.initialize(); - return (); -} diff --git a/tests/mocks/Ownable.cairo b/tests/mocks/Ownable.cairo deleted file mode 100644 index 04902e0ad..000000000 --- a/tests/mocks/Ownable.cairo +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.starknet.common.syscalls import get_caller_address -from openzeppelin.access.ownable.library import Ownable -from starkware.cairo.common.bool import TRUE - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) { - Ownable.initializer(owner); - return (); -} - -@external -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - -@external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_owner: felt -) { - Ownable.transfer_ownership(new_owner); - return (); -} - -@external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); -} - -@external -func protected_function{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - success: felt -) { - Ownable.assert_only_owner(); - return (success=TRUE); -} diff --git a/tests/mocks/Pausable.cairo b/tests/mocks/Pausable.cairo deleted file mode 100644 index cbe7be839..000000000 --- a/tests/mocks/Pausable.cairo +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.starknet.common.syscalls import get_caller_address -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.bool import TRUE, FALSE - -from openzeppelin.security.pausable.library import Pausable - -@storage_var -func drastic_measure_taken() -> (success: felt) { -} - -@storage_var -func counter() -> (count: felt) { -} - -@view -func isPaused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - paused: felt -) { - return Pausable.is_paused(); -} - -@view -func getCount{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (count: felt) { - return counter.read(); -} - -@view -func getDrasticMeasureTaken{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - success: felt -) { - return drastic_measure_taken.read(); -} - -@external -func normalProcess{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Pausable.assert_not_paused(); - - let (currentCount) = counter.read(); - counter.write(currentCount + 1); - return (); -} - -@external -func drasticMeasure{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Pausable.assert_paused(); - - drastic_measure_taken.write(TRUE); - return (); -} - -@external -func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Pausable._pause(); - return (); -} - -@external -func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Pausable._unpause(); - return (); -} diff --git a/tests/mocks/ProxiableImplementation.cairo b/tests/mocks/ProxiableImplementation.cairo deleted file mode 100644 index 9e5118879..000000000 --- a/tests/mocks/ProxiableImplementation.cairo +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin - -from openzeppelin.upgrades.library import Proxy - -// -// Storage -// - -@storage_var -func value() -> (val: felt) { -} - -// -// Initializer -// - -@external -func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - proxy_admin: felt -) { - Proxy.initializer(proxy_admin); - return (); -} - -// -// Getters -// - -@view -func getValue{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (val: felt) { - return value.read(); -} - -@view -func getAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - admin: felt -) { - return Proxy.get_admin(); -} - -// -// Setters -// - -@external -func setValue{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(val: felt) { - value.write(val); - return (); -} - -@external -func setAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(address: felt) { - Proxy.assert_only_admin(); - Proxy._set_admin(address); - return (); -} diff --git a/tests/mocks/ReentrancyAttackerMock.cairo b/tests/mocks/ReentrancyAttackerMock.cairo deleted file mode 100644 index bda88116e..000000000 --- a/tests/mocks/ReentrancyAttackerMock.cairo +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.starknet.common.syscalls import get_caller_address - -@contract_interface -namespace IReentrancyGuard { - func callback() { - } -} - -@external -func call_sender{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - let (caller) = get_caller_address(); - IReentrancyGuard.callback(contract_address=caller); - return (); -} diff --git a/tests/mocks/ReentrancyMock.cairo b/tests/mocks/ReentrancyMock.cairo deleted file mode 100644 index 2c029af78..000000000 --- a/tests/mocks/ReentrancyMock.cairo +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.math_cmp import is_le -from starkware.cairo.common.bool import TRUE -from starkware.starknet.common.syscalls import get_contract_address - -from openzeppelin.security.reentrancyguard.library import ReentrancyGuard - -@contract_interface -namespace IReentrancyGuardAttacker { - func call_sender() { - } -} - -@contract_interface -namespace IReentrancyGuard { - func count_this_recursive(n: felt) { - } -} - -@storage_var -func counter() -> (count: felt) { -} - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - initial_number: felt -) { - counter.write(initial_number); - return (); -} - -@view -func current_count{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - count: felt -) { - return counter.read(); -} - -@external -func callback{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - ReentrancyGuard.start(); - _count(); - ReentrancyGuard.end(); - return (); -} - -@external -func count_local_recursive{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - n: felt -) { - alloc_locals; - ReentrancyGuard.start(); - let greater_zero = is_le(1, n); - if (greater_zero == TRUE) { - _count(); - count_local_recursive(n - 1); - tempvar syscall_ptr = syscall_ptr; - tempvar pedersen_ptr = pedersen_ptr; - tempvar range_check_ptr = range_check_ptr; - } else { - tempvar syscall_ptr = syscall_ptr; - tempvar pedersen_ptr = pedersen_ptr; - tempvar range_check_ptr = range_check_ptr; - } - ReentrancyGuard.end(); - return (); -} - -@external -func count_this_recursive{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - n: felt -) { - alloc_locals; - ReentrancyGuard.start(); - let greater_zero = is_le(1, n); - if (greater_zero == TRUE) { - _count(); - let (contract_address) = get_contract_address(); - IReentrancyGuard.count_this_recursive(contract_address=contract_address, n=n - 1); - tempvar syscall_ptr = syscall_ptr; - tempvar pedersen_ptr = pedersen_ptr; - tempvar range_check_ptr = range_check_ptr; - } else { - tempvar syscall_ptr = syscall_ptr; - tempvar pedersen_ptr = pedersen_ptr; - tempvar range_check_ptr = range_check_ptr; - } - ReentrancyGuard.end(); - return (); -} - -@external -func count_and_call{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - attacker: felt -) { - ReentrancyGuard.start(); - _count(); - IReentrancyGuardAttacker.call_sender(attacker); - ReentrancyGuard.end(); - return (); -} - -func _count{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - let (current_count) = counter.read(); - counter.write(current_count + 1); - return (); -} diff --git a/tests/mocks/SafeMathMock.cairo b/tests/mocks/SafeMathMock.cairo deleted file mode 100644 index 51efa8ec9..000000000 --- a/tests/mocks/SafeMathMock.cairo +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin -from starkware.cairo.common.uint256 import Uint256 - -from openzeppelin.security.safemath.library import SafeUint256 - -@view -func uint256_add{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256) { - return SafeUint256.add(a, b); -} - -@view -func uint256_sub_le{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256) { - return SafeUint256.sub_le(a, b); -} - -@view -func uint256_sub_lt{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256) { - return SafeUint256.sub_lt(a, b); -} - -@view -func uint256_mul{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256) { - return SafeUint256.mul(a, b); -} - -@view -func uint256_div{range_check_ptr}(a: Uint256, b: Uint256) -> (c: Uint256, rem: Uint256) { - return SafeUint256.div_rem(a, b); -} diff --git a/tests/mocks/UpgradesMockV1.cairo b/tests/mocks/UpgradesMockV1.cairo deleted file mode 100644 index 3ca050412..000000000 --- a/tests/mocks/UpgradesMockV1.cairo +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin - -from openzeppelin.upgrades.library import Proxy, Proxy_initialized - -// -// Storage -// - -@storage_var -func value_1() -> (val: felt) { -} - -// -// Initializer -// - -@external -func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - proxy_admin: felt -) { - Proxy.initializer(proxy_admin); - return (); -} - -@view -func initialized{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}() --> (initialized: felt) { - let (initialized) = Proxy_initialized.read(); - return (initialized=initialized); -} - -// -// Upgrades -// - -@external -func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_implementation: felt -) { - Proxy.assert_only_admin(); - Proxy._set_implementation_hash(new_implementation); - return (); -} - -// -// Getters -// - -@view -func getValue1{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (val: felt) { - return value_1.read(); -} - -// -// Setters -// - -@external -func setValue1{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(val: felt) { - value_1.write(val); - return (); -} diff --git a/tests/mocks/UpgradesMockV2.cairo b/tests/mocks/UpgradesMockV2.cairo deleted file mode 100644 index 78b49ced2..000000000 --- a/tests/mocks/UpgradesMockV2.cairo +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: MIT - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin - -from openzeppelin.upgrades.library import Proxy - -// -// Storage -// - -@storage_var -func value_1() -> (val: felt) { -} - -@storage_var -func value_2() -> (val: felt) { -} - -// -// Initializer -// - -@external -func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - proxy_admin: felt -) { - Proxy.initializer(proxy_admin); - return (); -} - -// -// Upgrades -// - -@external -func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_implementation: felt -) { - Proxy.assert_only_admin(); - Proxy._set_implementation_hash(new_implementation); - return (); -} - -// -// Getters -// - -@view -func getValue1{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (val: felt) { - return value_1.read(); -} - -@view -func getValue2{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (val: felt) { - return value_2.read(); -} - -@view -func getImplementationHash{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - implementation: felt -) { - return Proxy.get_implementation_hash(); -} - -@view -func getAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (admin: felt) { - return Proxy.get_admin(); -} - -// -// Setters -// - -@external -func setValue1{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(val: felt) { - value_1.write(val); - return (); -} - -@external -func setValue2{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(val: felt) { - value_2.write(val); - return (); -} - -@external -func setAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(new_admin: felt) { - Proxy.assert_only_admin(); - Proxy._set_admin(new_admin); - return (); -} diff --git a/tests/security/test_initializable.py b/tests/security/test_initializable.py deleted file mode 100644 index 602a0bf77..000000000 --- a/tests/security/test_initializable.py +++ /dev/null @@ -1,24 +0,0 @@ -import pytest -from nile.utils import TRUE, FALSE, assert_revert -from utils import get_contract_class, State - - -@pytest.mark.asyncio -async def test_initializer(): - starknet = await State.init() - initializable = await starknet.deploy( - contract_class=get_contract_class("Initializable") - ) - expected = await initializable.initialized().call() - assert expected.result == (FALSE,) - - await initializable.initialize().execute() - - expected = await initializable.initialized().call() - assert expected.result == (TRUE,) - - # second initialize invocation should revert - await assert_revert( - initializable.initialize().execute(), - reverted_with="Initializable: contract already initialized" - ) diff --git a/tests/security/test_pausable.py b/tests/security/test_pausable.py deleted file mode 100644 index a7e391ff4..000000000 --- a/tests/security/test_pausable.py +++ /dev/null @@ -1,146 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import TRUE, FALSE, assert_revert -from utils import ( - get_contract_class, cached_contract, assert_event_emitted, State, Account -) - - -signer = MockSigner(12345678987654321) - -@pytest.fixture -async def pausable_factory(): - # class - pausable_cls = get_contract_class("Pausable") - account_cls = Account.get_class - - # deploy - starknet = await State.init() - account = await Account.deploy(signer.public_key) - pausable = await starknet.deploy( - contract_class=pausable_cls, - constructor_calldata=[] - ) - state = starknet.state.copy() - - # cache - pausable = cached_contract(state, pausable_cls, pausable) - account = cached_contract(state, account_cls, account) - - return pausable, account - - -@pytest.mark.asyncio -async def test_pausable_when_unpaused(pausable_factory): - contract, _ = pausable_factory - - execution_info = await contract.isPaused().call() - assert execution_info.result.paused == FALSE - - execution_info = await contract.getCount().call() - assert execution_info.result.count == 0 - - # check that function executes when unpaused - await contract.normalProcess().execute() - - execution_info = await contract.getCount().call() - assert execution_info.result.count == 1 - - await assert_revert( - contract.drasticMeasure().execute(), - reverted_with="Pausable: not paused" - ) - -@pytest.mark.asyncio -async def test_pausable_when_paused(pausable_factory): - contract, _ = pausable_factory - - execution_info = await contract.isPaused().call() - assert execution_info.result.paused == FALSE - - # pause - await contract.pause().execute() - - execution_info = await contract.isPaused().call() - assert execution_info.result.paused == TRUE - - await assert_revert( - contract.normalProcess().execute(), - reverted_with="Pausable: paused" - ) - - execution_info = await contract.getDrasticMeasureTaken().call() - assert execution_info.result.success == FALSE - - # drastic measure - await contract.drasticMeasure().execute() - - execution_info = await contract.getDrasticMeasureTaken().call() - assert execution_info.result.success == TRUE - - # unpause - await contract.unpause().execute() - - execution_info = await contract.isPaused().call() - assert execution_info.result.paused == FALSE - - # check normal process after unpausing - await contract.normalProcess().execute() - - execution_info = await contract.getCount().call() - assert execution_info.result.count == 1 - - await assert_revert( - contract.drasticMeasure().execute(), - reverted_with="Pausable: not paused" - ) - -@pytest.mark.asyncio -async def test_pausable_pause_when_paused(pausable_factory): - contract, _ = pausable_factory - - # pause - await contract.pause().execute() - - # re-pause - await assert_revert( - contract.pause().execute(), - reverted_with="Pausable: paused" - ) - - # unpause - await contract.unpause().execute() - - # re-unpause - await assert_revert( - contract.unpause().execute(), - reverted_with="Pausable: not paused" - ) - -@pytest.mark.asyncio -async def test_pausable_emits_events(pausable_factory): - contract, account = pausable_factory - - # pause - tx_exec_info = await signer.send_transaction( - account, contract.contract_address, 'pause', [] - ) - - assert_event_emitted( - tx_exec_info, - from_address=contract.contract_address, - name='Paused', - data=[account.contract_address] - ) - - # unpause - tx_exec_info = await signer.send_transaction( - account, contract.contract_address, 'unpause', [] - ) - - assert_event_emitted( - tx_exec_info, - from_address=contract.contract_address, - name='Unpaused', - data=[account.contract_address] - ) diff --git a/tests/security/test_reentrancy.py b/tests/security/test_reentrancy.py deleted file mode 100644 index 8c096fe9d..000000000 --- a/tests/security/test_reentrancy.py +++ /dev/null @@ -1,60 +0,0 @@ -import pytest -from nile.utils import assert_revert -from utils import get_contract_class, State - -INITIAL_COUNTER = 0 - - -@pytest.fixture(scope='module') -async def reentrancy_mock(): - starknet = await State.init() - contract = await starknet.deploy( - contract_class=get_contract_class("ReentrancyMock"), - constructor_calldata=[INITIAL_COUNTER] - ) - - return contract, starknet - - -@pytest.mark.asyncio -async def test_reentrancy_guard_deploy(reentrancy_mock): - contract, _ = reentrancy_mock - response = await contract.current_count().call() - - assert response.result == (INITIAL_COUNTER,) - - -@pytest.mark.asyncio -async def test_reentrancy_guard_remote_callback(reentrancy_mock): - contract, starknet = reentrancy_mock - attacker = await starknet.deploy("tests/mocks/ReentrancyAttackerMock.cairo") - # should not allow remote callback - await assert_revert( - contract.count_and_call(attacker.contract_address).execute(), - reverted_with="ReentrancyGuard: reentrant call" - ) - - -@pytest.mark.asyncio -async def test_reentrancy_guard_local_recursion(reentrancy_mock): - contract, _ = reentrancy_mock - # should not allow local recursion - await assert_revert( - contract.count_local_recursive(10).execute(), - reverted_with="ReentrancyGuard: reentrant call" - ) - # should not allow indirect local recursion - await assert_revert( - contract.count_this_recursive(10).execute(), - reverted_with="ReentrancyGuard: reentrant call" - ) - - -@pytest.mark.asyncio -async def test_reentrancy_guard(reentrancy_mock): - contract, _ = reentrancy_mock - # should allow non reentrant call - await contract.callback().execute() - response = await contract.current_count().call() - - assert response.result == (1,) diff --git a/tests/security/test_safemath.py b/tests/security/test_safemath.py deleted file mode 100644 index f551eb47f..000000000 --- a/tests/security/test_safemath.py +++ /dev/null @@ -1,206 +0,0 @@ -import pytest -from nile.utils import ( - MAX_UINT256, assert_revert, add_uint, sub_uint, - mul_uint, div_rem_uint, to_uint -) -from utils import get_contract_class, State - - -@pytest.fixture(scope='module') -async def safemath_mock(): - starknet = await State.init() - safemath = await starknet.deploy( - contract_class=get_contract_class("SafeMathMock") - ) - - return safemath - - -@pytest.mark.asyncio -async def test_add(safemath_mock): - safemath = safemath_mock - - a = to_uint(56789) - b = to_uint(1234) - c = add_uint(a, b) - - execution_info = await safemath.uint256_add(a, b).execute() - assert execution_info.result == (c,) - - -@pytest.mark.asyncio -async def test_add_overflow(safemath_mock): - safemath = safemath_mock - - a = MAX_UINT256 - b = to_uint(1) - - await assert_revert( - safemath.uint256_add(a, b).execute(), - reverted_with="SafeUint256: addition overflow" - ) - - -@pytest.mark.asyncio -async def test_sub_lt(safemath_mock): - safemath = safemath_mock - - a = to_uint(56789) - b = to_uint(1234) - c = sub_uint(a, b) - - execution_info = await safemath.uint256_sub_lt(a, b).execute() - assert execution_info.result == (c,) - - -@pytest.mark.asyncio -async def test_sub_lt_equal(safemath_mock): - safemath = safemath_mock - - a = MAX_UINT256 - b = MAX_UINT256 - - await assert_revert( - safemath.uint256_sub_lt(a, b).execute(), - reverted_with="SafeUint256: subtraction overflow or the difference equals zero" - ) - - -@pytest.mark.asyncio -async def test_sub_lt_overflow(safemath_mock): - safemath = safemath_mock - - a = to_uint(1234) - b = to_uint(56789) - - await assert_revert( - safemath.uint256_sub_lt(a, b).execute(), - reverted_with="SafeUint256: subtraction overflow or the difference equals zero" - ) - - -@pytest.mark.asyncio -async def test_sub_le(safemath_mock): - safemath = safemath_mock - - a = to_uint(56789) - b = to_uint(1234) - c = sub_uint(a, b) - - execution_info = await safemath.uint256_sub_le(a, b).execute() - assert execution_info.result == (c,) - - -@pytest.mark.asyncio -async def test_sub_le_equal(safemath_mock): - safemath = safemath_mock - - a = MAX_UINT256 - b = MAX_UINT256 - c = sub_uint(a, b) - - execution_info = await safemath.uint256_sub_le(a, b).execute() - assert execution_info.result == (c,) - - -@pytest.mark.asyncio -async def test_sub_le_overflow(safemath_mock): - safemath = safemath_mock - - a = to_uint(1234) - b = to_uint(56789) - - await assert_revert( - safemath.uint256_sub_le(a, b).execute(), - reverted_with="SafeUint256: subtraction overflow" - ) - await assert_revert(safemath.uint256_sub_le(a, b).execute()) - - -@pytest.mark.asyncio -async def test_mul(safemath_mock): - safemath = safemath_mock - - a = to_uint(1234) - b = to_uint(56789) - c = mul_uint(a, b) - - execution_info = await safemath.uint256_mul(a, b).execute() - assert execution_info.result == (c,) - - -@pytest.mark.asyncio -async def test_mul_zero(safemath_mock): - safemath = safemath_mock - - a = to_uint(0) - b = to_uint(56789) - c = to_uint(0) - - execution_info = await safemath.uint256_mul(a, b).execute() - assert execution_info.result == (c,) - - execution_info = await safemath.uint256_mul(b, a).execute() - assert execution_info.result == (c,) - - -@pytest.mark.asyncio -async def test_mul_overflow(safemath_mock): - safemath = safemath_mock - - a = MAX_UINT256 - b = to_uint(2) - - await assert_revert( - safemath.uint256_mul(a, b).execute(), - reverted_with="SafeUint256: multiplication overflow" - ) - - -@pytest.mark.asyncio -async def test_div(safemath_mock): - safemath = safemath_mock - - a = to_uint(56789) - b = to_uint(56789) - (c, r) = div_rem_uint(a, b) - - execution_info = await safemath.uint256_div(a, b).execute() - assert execution_info.result == (c, r) - - -@pytest.mark.asyncio -async def test_div_zero_dividend(safemath_mock): - safemath = safemath_mock - - a = to_uint(0) - b = to_uint(56789) - (c, r) = div_rem_uint(a, b) - - execution_info = await safemath.uint256_div(a, b).execute() - assert execution_info.result == (c, r) - - -@pytest.mark.asyncio -async def test_div_zero_divisor(safemath_mock): - safemath = safemath_mock - - a = to_uint(56789) - b = to_uint(0) - - await assert_revert( - safemath.uint256_div(a, b).execute(), - reverted_with="SafeUint256: divisor cannot be zero" - ) - - -@pytest.mark.asyncio -async def test_div_uneven_division(safemath_mock): - safemath = safemath_mock - - a = to_uint(7000) - b = to_uint(5678) - (c, r) = div_rem_uint(a, b) - - execution_info = await safemath.uint256_div(a, b).execute() - assert execution_info.result == (c, r) diff --git a/tests/signers.py b/tests/signers.py deleted file mode 100644 index ca614f4e6..000000000 --- a/tests/signers.py +++ /dev/null @@ -1,215 +0,0 @@ -from typing import Tuple -from starkware.starknet.core.os.transaction_hash.transaction_hash import TransactionHashPrefix -from starkware.starknet.core.os.contract_address.contract_address import ( - calculate_contract_address_from_hash, -) -from starkware.starknet.definitions.general_config import StarknetChainId -from starkware.starknet.services.api.gateway.transaction import InvokeFunction, DeployAccount -from starkware.starknet.business_logic.transaction.objects import InternalTransaction, InternalDeclare, TransactionExecutionInfo -from nile.signer import Signer, from_call_to_call_array, get_transaction_hash, TRANSACTION_VERSION -from nile.utils import to_uint -from utils import get_class_hash, get_contract_class -import eth_keys - - -class BaseSigner(): - async def send_transaction(self, account, to, selector_name, calldata, nonce=None, max_fee=0): - return await self.send_transactions(account, [(to, selector_name, calldata)], nonce, max_fee) - - async def send_transactions( - self, - account, - calls, - nonce=None, - max_fee=0 - ) -> TransactionExecutionInfo: - raw_invocation = get_raw_invoke(account, calls) - state = raw_invocation.state - - if nonce is None: - nonce = await state.state.get_nonce_at(account.contract_address) - - transaction_hash = get_transaction_hash( - prefix=TransactionHashPrefix.INVOKE, - account=account.contract_address, - calldata=raw_invocation.calldata, - version=TRANSACTION_VERSION, - chain_id=StarknetChainId.TESTNET.value, - nonce=nonce, - max_fee=max_fee, - ) - - signature = self.sign(transaction_hash) - - external_tx = InvokeFunction( - contract_address=account.contract_address, - calldata=raw_invocation.calldata, - entry_point_selector=None, - signature=signature, - max_fee=max_fee, - version=TRANSACTION_VERSION, - nonce=nonce, - ) - - tx = InternalTransaction.from_external( - external_tx=external_tx, general_config=state.general_config - ) - execution_info = await state.execute_tx(tx=tx) - return execution_info - - async def declare_class( - self, - account, - contract_name, - nonce=None, - max_fee=0, - ) -> Tuple[int, TransactionExecutionInfo]: - state = account.state - - if nonce is None: - nonce = await state.state.get_nonce_at(contract_address=account.contract_address) - - contract_class = get_contract_class(contract_name) - class_hash = get_class_hash(contract_name) - - transaction_hash = get_transaction_hash( - prefix=TransactionHashPrefix.DECLARE, - account=account.contract_address, - calldata=[class_hash], - nonce=nonce, - version=TRANSACTION_VERSION, - max_fee=max_fee, - chain_id=StarknetChainId.TESTNET.value - ) - - signature = self.sign(transaction_hash) - - tx = InternalDeclare.create( - sender_address=account.contract_address, - contract_class=contract_class, - chain_id=StarknetChainId.TESTNET.value, - max_fee=max_fee, - version=TRANSACTION_VERSION, - nonce=nonce, - signature=signature, - ) - - execution_info = await state.execute_tx(tx=tx) - - await state.state.set_contract_class( - class_hash=tx.class_hash, - contract_class=contract_class - ) - return class_hash, execution_info - - async def deploy_account( - self, - state, - calldata, - salt=0, - nonce=0, - max_fee=0, - ) -> TransactionExecutionInfo: - account_address = calculate_contract_address_from_hash( - salt=salt, - class_hash=self.class_hash, - constructor_calldata=calldata, - deployer_address=0 - ) - - transaction_hash = get_transaction_hash( - prefix=TransactionHashPrefix.DEPLOY_ACCOUNT, - account=account_address, - calldata=[self.class_hash, salt, *calldata], - nonce=nonce, - version=TRANSACTION_VERSION, - max_fee=max_fee, - chain_id=StarknetChainId.TESTNET.value - ) - - signature = self.sign(transaction_hash) - - external_tx = DeployAccount( - class_hash=self.class_hash, - contract_address_salt=salt, - constructor_calldata=calldata, - signature=signature, - max_fee=max_fee, - version=TRANSACTION_VERSION, - nonce=nonce, - ) - - tx = InternalTransaction.from_external( - external_tx=external_tx, general_config=state.general_config - ) - - execution_info = await state.execute_tx(tx=tx) - return execution_info - -class MockSigner(BaseSigner): - """ - Utility for sending signed transactions to an Account on Starknet. - - Parameters - ---------- - - private_key : int - - Examples - --------- - Constructing a MockSigner object - - >>> signer = MockSigner(1234) - - Sending a transaction - - >>> await signer.send_transaction( - account, contract_address, 'contract_method', [arg_1] - ) - - Sending multiple transactions - - >>> await signer.send_transactions( - account, [ - (contract_address, 'contract_method', [arg_1]), - (contract_address, 'another_method', [arg_1, arg_2]) - ] - ) - - """ - def __init__(self, private_key): - self.signer = Signer(private_key) - self.public_key = self.signer.public_key - self.class_hash = get_class_hash("Account") - - def sign(self, transaction_hash): - sig_r, sig_s = self.signer.sign(transaction_hash) - return [sig_r, sig_s] - - -class MockEthSigner(BaseSigner): - """ - Utility for sending signed transactions to an Account on Starknet, like MockSigner, but using a secp256k1 signature. - Parameters - ---------- - private_key : int - - """ - def __init__(self, private_key): - self.signer = eth_keys.keys.PrivateKey(private_key) - self.eth_address = int(self.signer.public_key.to_checksum_address(), 0) - self.class_hash = get_class_hash("EthAccount") - - def sign(self, transaction_hash): - signature = self.signer.sign_msg_hash( - (transaction_hash).to_bytes(32, byteorder="big")) - sig_r = to_uint(signature.r) - sig_s = to_uint(signature.s) - return [signature.v, *sig_r, *sig_s] - - -def get_raw_invoke(sender, calls): - """Return raw invoke, remove when test framework supports `invoke`.""" - call_array, calldata = from_call_to_call_array(calls) - raw_invocation = sender.__execute__(call_array, calldata) - return raw_invocation diff --git a/tests/test_signers.py b/tests/test_signers.py deleted file mode 100644 index 82e343436..000000000 --- a/tests/test_signers.py +++ /dev/null @@ -1,72 +0,0 @@ -import pytest - -from signers import MockSigner -from utils import ( - State, - Account, - get_contract_class, - cached_contract, - FALSE, - TRUE, -) - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - deployer_cls = get_contract_class('UniversalDeployer') - - return account_cls, deployer_cls - - -@pytest.fixture(scope='module') -async def deployer_init(contract_classes): - _, deployer_cls = contract_classes - starknet = await State.init() - account = await Account.deploy(signer.public_key) - deployer = await starknet.deploy(contract_class=deployer_cls) - return ( - starknet.state, - account, - deployer - ) - - -@pytest.fixture -def deployer_factory(contract_classes, deployer_init): - account_cls, deployer_cls = contract_classes - state, account, deployer = deployer_init - _state = state.copy() - _account = cached_contract(_state, account_cls, account) - deployer = cached_contract(_state, deployer_cls, deployer) - - return _account, deployer - - -@pytest.mark.asyncio -async def test_signer_declare_class(deployer_factory): - account, deployer = deployer_factory - salt = 1234567875432 # random value - unique = 0 - calldata = [] - - # declare contract class - class_hash, _ = await signer.declare_class(account, "Initializable") - - # deploy contract - params = [class_hash, salt, unique, len(calldata), *calldata] - deploy_exec_info = await signer.send_transaction(account, deployer.contract_address, 'deployContract', params) - deployed_address = deploy_exec_info.call_info.retdata[1] - - # test deployment - tx_exec_info = await signer.send_transaction(account, deployed_address, 'initialized', []) - is_initialized = tx_exec_info.call_info.retdata[1] - assert is_initialized == FALSE - - await signer.send_transaction(account, deployed_address, 'initialize', []) - - tx_exec_info = await signer.send_transaction(account, deployed_address, 'initialized', []) - is_initialized = tx_exec_info.call_info.retdata[1] - assert is_initialized == TRUE diff --git a/tests/token/erc1155/ERC1155BaseSuite.py b/tests/token/erc1155/ERC1155BaseSuite.py deleted file mode 100644 index 76e02f650..000000000 --- a/tests/token/erc1155/ERC1155BaseSuite.py +++ /dev/null @@ -1,811 +0,0 @@ -import pytest -from signers import MockSigner -from utils import assert_event_emitted - -from nile.utils import ( - MAX_UINT256, ZERO_ADDRESS, INVALID_UINT256, TRUE, FALSE, - to_uint, add_uint, sub_uint, assert_revert, str_to_felt -) - -signer = MockSigner(123456789987654321) - -# -# Helpers -# - - -def to_uint_array(arr): - return list(map(to_uint, arr)) - - -def prepare_calldata(arr): - """Flatten an array of tuples or an array of ints.""" - # [5, 5, 5] => [3, 5, 5, 5] - # [(1, 2), (3, 4)] => [2, 1, 2, 3, 4] - res = [len(arr)] - if res[0] == 0: - return res - if type(arr[0]) == int: - return res + arr - if type(arr[0]) == tuple: - for elem in arr: - res += [*elem] - return res - raise Exception - -# -# Constants -# - -NOT_BOOLEAN = 3 -ACCOUNT = 123 -TOKEN_ID = to_uint(111) -MINT_VALUE = to_uint(1000) -TRANSFER_VALUE = to_uint(500) - -ACCOUNTS = [123, 234, 345] -TOKEN_IDS = [TOKEN_ID, to_uint(222), to_uint(333)] -MINT_VALUES = [MINT_VALUE, to_uint(2000), to_uint(3000)] -TRANSFER_VALUES = [TRANSFER_VALUE, to_uint(1000), to_uint(1500)] -TRANSFER_DIFFERENCES = [sub_uint(m, t) - for m, t in zip(MINT_VALUES, TRANSFER_VALUES)] -MAX_UINT_VALUES = [to_uint(1), MAX_UINT256, to_uint(1)] -INVALID_VALUES = [to_uint(1), (MAX_UINT256[0]+1, MAX_UINT256[1]), to_uint(1)] -INVALID_IDS = [to_uint(111),INVALID_UINT256,to_uint(333)] - -DEFAULT_URI = str_to_felt('mock://mytoken.v1') -NEW_URI = str_to_felt('mock://mytoken.v2') - -DATA = 0 -REJECT_DATA = [1, 0] - -IERC165_ID = int('0x01ffc9a7', 16) -IERC1155_ID = int('0xd9b67a26', 16) -IERC1155_MetadataURI = int('0x0e89341c', 16) -ERC165_UNSUPPORTED = int('0xffffffff', 16) -UNSUPPORTED_ID = int('0xaabbccdd', 16) - -SUPPORTED_INTERFACES = [IERC165_ID, IERC1155_ID, IERC1155_MetadataURI] -UNSUPPORTED_INTERFACES = [ERC165_UNSUPPORTED, UNSUPPORTED_ID] - - -class ERC1155Base: - # - # Constructor - # - - - @pytest.mark.asyncio - async def test_constructor(self, contract_factory): - erc1155, _, _, _ = contract_factory - - execution_info = await erc1155.uri(TOKEN_ID).execute() - assert execution_info.result.uri == DEFAULT_URI - - # - # ERC165 - # - - - @pytest.mark.asyncio - @pytest.mark.parametrize("supported_id", SUPPORTED_INTERFACES) - async def test_supports_interface(self, contract_factory, supported_id): - erc1155, _, _, _ = contract_factory - - execution_info = await erc1155.supportsInterface(supported_id).execute() - assert execution_info.result.success == TRUE - - - @pytest.mark.asyncio - @pytest.mark.parametrize("unsupported_id", UNSUPPORTED_INTERFACES) - async def test_supports_interface_unsupported(self, contract_factory, unsupported_id): - erc1155, _, _, _ = contract_factory - - execution_info = await erc1155.supportsInterface(unsupported_id).execute() - assert execution_info.result.success == FALSE - - # - # Set/Get approval - # - - - @pytest.mark.asyncio - async def test_set_approval_for_all(self, contract_factory): - erc1155, account, _, _ = contract_factory - - approver = account.contract_address - - # Set approval - await signer.send_transaction( - account, erc1155.contract_address, 'setApprovalForAll', - [ACCOUNT, TRUE] - ) - - execution_info = await erc1155.isApprovedForAll( - approver, ACCOUNT).execute() - - assert execution_info.result.approved == TRUE - - # Unset approval - await signer.send_transaction( - account, erc1155.contract_address, 'setApprovalForAll', - [ACCOUNT, FALSE] - ) - - execution_info = await erc1155.isApprovedForAll( - approver, ACCOUNT).execute() - - assert execution_info.result.approved == FALSE - - - @pytest.mark.asyncio - @pytest.mark.parametrize("approval", [TRUE, FALSE]) - async def test_set_approval_for_all_emits_event(self, contract_factory, approval): - erc1155, account, _, _ = contract_factory - - execution_info = await signer.send_transaction( - account, erc1155.contract_address, 'setApprovalForAll', - [ACCOUNT, approval] - ) - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='ApprovalForAll', - data=[ - account.contract_address, - ACCOUNT, - approval - ] - ) - - - @pytest.mark.asyncio - async def test_set_approval_for_all_non_boolean(self, contract_factory): - erc1155, account, _, _ = contract_factory - - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'setApprovalForAll', - [ACCOUNT, NOT_BOOLEAN]), - "ERC1155: approval is not boolean") - - - @pytest.mark.asyncio - async def test_set_approval_for_all_self(self, contract_factory): - erc1155, account, _, _ = contract_factory - - approvee = account.contract_address - - # Set approval - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'setApprovalForAll', - [approvee, TRUE]), - "ERC1155: setting approval status for self") - - - @pytest.mark.asyncio - async def test_set_approval_for_all_zero_address(self, contract_factory): - erc1155, account, _, _ = contract_factory - - # Set approval - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'setApprovalForAll', - [ZERO_ADDRESS, TRUE]), - "ERC1155: setting approval status for zero address") - - # - # Balance getters - # - - - @pytest.mark.asyncio - async def test_balance_of(self, minted_factory): - erc1155, _, account, _ = minted_factory - - user = account.contract_address - - execution_info = await erc1155.balanceOf(user, TOKEN_ID).execute() - assert execution_info.result.balance == MINT_VALUE - - - @pytest.mark.asyncio - async def test_balance_of_zero_address(self, contract_factory): - erc1155, _, _, _ = contract_factory - - await assert_revert( - erc1155.balanceOf(ZERO_ADDRESS, TOKEN_ID).execute(), - "ERC1155: address zero is not a valid owner") - - - @pytest.mark.asyncio - async def test_balance_of_invalid_id(self, contract_factory): - erc1155, _, _, _ = contract_factory - - await assert_revert( - erc1155.balanceOf(ACCOUNT, INVALID_UINT256).execute(), - "ERC1155: token_id is not a valid Uint256") - - - @pytest.mark.asyncio - async def test_balance_of_batch(self, minted_factory): - erc1155, _, account, _ = minted_factory - - accounts = [account.contract_address]*3 - - execution_info = await erc1155.balanceOfBatch(accounts, TOKEN_IDS).execute() - assert execution_info.result.balances == MINT_VALUES - - - @pytest.mark.asyncio - async def test_balance_of_batch_zero_address(self, contract_factory): - erc1155, _, _, _ = contract_factory - accounts = [ACCOUNT, ZERO_ADDRESS, ACCOUNT] - - await assert_revert( - erc1155.balanceOfBatch(accounts, TOKEN_IDS).execute(), - "ERC1155: address zero is not a valid owner") - - - @pytest.mark.asyncio - async def test_balance_of_batch_invalid_id(self, contract_factory): - erc1155, _, _, _ = contract_factory - - accounts = [ACCOUNT]*3 - - await assert_revert( - erc1155.balanceOfBatch(accounts, INVALID_IDS).execute(), - "ERC1155: token_id is not a valid Uint256") - - - @pytest.mark.asyncio - @pytest.mark.parametrize( - "accounts,ids", - [(ACCOUNTS[:2], TOKEN_IDS), (ACCOUNTS, TOKEN_IDS[:2])]) - async def test_balance_of_batch_uneven_arrays(self, contract_factory, accounts, ids): - erc1155, _, _, _ = contract_factory - - await assert_revert( - erc1155.balanceOfBatch(accounts, ids).execute(), - "ERC1155: accounts and ids length mismatch") - - # - # Transfer - # - - - @pytest.mark.asyncio - async def test_safe_transfer_from(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *TRANSFER_VALUE, DATA]) - - execution_info = await erc1155.balanceOf(sender, TOKEN_ID).execute() - assert execution_info.result.balance == sub_uint( - MINT_VALUE, TRANSFER_VALUE) - - execution_info = await erc1155.balanceOf(recipient, TOKEN_ID).execute() - assert execution_info.result.balance == TRANSFER_VALUE - - - @pytest.mark.asyncio - async def test_safe_transfer_from_emits_event(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - - execution_info = await signer.send_transaction( - account2, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *TRANSFER_VALUE, DATA]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferSingle', - data=[ - sender, # operator - sender, # from - recipient, # to - *TOKEN_ID, - *TRANSFER_VALUE - ] - ) - - - @pytest.mark.asyncio - async def test_safe_transfer_from_approved(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - operator = account1.contract_address - sender = account2.contract_address - recipient = account1.contract_address - - # account2 approves account1 - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, TRUE]) - - # account sends transaction - await signer.send_transaction( - account1, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *TRANSFER_VALUE, DATA]) - - execution_info = await erc1155.balanceOf(sender, TOKEN_ID).execute() - assert execution_info.result.balance == sub_uint( - MINT_VALUE, TRANSFER_VALUE) - - execution_info = await erc1155.balanceOf(recipient, TOKEN_ID).execute() - assert execution_info.result.balance == TRANSFER_VALUE - - - @pytest.mark.asyncio - async def test_safe_transfer_from_approved_emits_event(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - operator = account1.contract_address - sender = account2.contract_address - recipient = account1.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, TRUE]) - - # account1/operator sends transaction - execution_info = await signer.send_transaction( - account1, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *TRANSFER_VALUE, DATA]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferSingle', - data=[ - operator, # operator - sender, # from - recipient, # to - *TOKEN_ID, - *TRANSFER_VALUE - ] - ) - - - @pytest.mark.asyncio - async def test_safe_transfer_from_invalid_value(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - sender = account.contract_address - recipient = owner.contract_address - - # mint max uint to avoid possible insufficient balance error - await signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [sender, *TOKEN_ID, *MAX_UINT256, DATA]) - - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *INVALID_UINT256, DATA]), - "ERC1155: value is not a valid Uint256" - ) - - - @pytest.mark.asyncio - async def test_safe_transfer_from_invalid_id(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - sender = account.contract_address - recipient = owner.contract_address - - # transfer 0 value of invalid id to avoid - # insufficient balance error - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *INVALID_UINT256, *to_uint(0), DATA]), - "ERC1155: token_id is not a valid Uint256" - ) - - - @pytest.mark.asyncio - async def test_safe_transfer_from_insufficient_balance(self, minted_factory): - erc1155, account, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account.contract_address - - transfer_value = add_uint(MINT_VALUES[0], to_uint(1)) - - await assert_revert( - signer.send_transaction( - account2, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *transfer_value, DATA]), - "ERC1155: insufficient balance for transfer" - ) - - - @pytest.mark.asyncio - async def test_safe_transfer_from_unapproved(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - - await assert_revert(signer.send_transaction( - account1, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *TRANSFER_VALUE, DATA]), - "ERC1155: caller is not owner nor approved") - - - @pytest.mark.asyncio - async def test_safe_transfer_from_to_zero_address(self, minted_factory): - erc1155, _, account, _ = minted_factory - - sender = account.contract_address - - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'safeTransferFrom', - [sender, ZERO_ADDRESS, *TOKEN_ID, *TRANSFER_VALUE, DATA]), - "ERC1155: transfer to the zero address") - - - @pytest.mark.asyncio - async def test_safe_transfer_from_overflow(self, minted_factory): - erc1155, owner, account, _ = minted_factory - - sender = account.contract_address - recipient = owner.contract_address - - # Bring recipient's balance to max possible - await signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *TOKEN_ID, *MAX_UINT256, DATA]) - - # Issuing recipient any more should revert due to overflow - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *to_uint(1), DATA]), - "ERC1155: balance overflow") - - - @pytest.mark.asyncio - async def test_safe_transfer_from_to_receiver(self, minted_factory): - erc1155, _, account2, receiver = minted_factory - - sender = account2.contract_address - recipient = receiver.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *TRANSFER_VALUE, DATA]) - - execution_info = await erc1155.balanceOf(recipient, TOKEN_ID).execute() - assert execution_info.result.balance == TRANSFER_VALUE - - - @pytest.mark.asyncio - async def test_safe_transfer_from_to_receiver_rejection(self, minted_factory): - erc1155, _, account2, receiver = minted_factory - - sender = account2.contract_address - recipient = receiver.contract_address - - await assert_revert(signer.send_transaction( - account2, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *TRANSFER_VALUE, *REJECT_DATA]), - "ERC1155: ERC1155Receiver rejected tokens") - - - @pytest.mark.asyncio - async def test_safe_transfer_from_to_non_receiver(self, minted_factory): - erc1155, _, account, _ = minted_factory - - sender = account.contract_address - recipient = erc1155.contract_address - - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'safeTransferFrom', - [sender, recipient, *TOKEN_ID, *TRANSFER_VALUE, DATA]), - "ERC1155: transfer to non-ERC1155Receiver implementer") - - - # - # Batch Transfers - # - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), DATA - ]) - - execution_info = await erc1155.balanceOfBatch( - [sender]*3+[recipient]*3, TOKEN_IDS*2).execute() - assert execution_info.result.balances[:3] == TRANSFER_DIFFERENCES - assert execution_info.result.balances[3:] == TRANSFER_VALUES - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_emits_event(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - - execution_info = await signer.send_transaction( - account2, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), DATA - ]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferBatch', - data=[ - sender, # operator - sender, # from - recipient, # to - *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), - ] - ) - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_approved(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - operator = account1.contract_address - recipient = account1.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, TRUE]) - - await signer.send_transaction( - account1, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), DATA - ]) - - execution_info = await erc1155.balanceOfBatch( - [sender]*3+[recipient]*3, TOKEN_IDS*2).execute() - assert execution_info.result.balances[:3] == TRANSFER_DIFFERENCES - assert execution_info.result.balances[3:] == TRANSFER_VALUES - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_approved_emits_event(self, - minted_factory): - erc1155, account1, account2, receiver = minted_factory - - sender = account2.contract_address - operator = account1.contract_address - recipient = receiver.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, TRUE]) - - execution_info = await signer.send_transaction( - account1, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), DATA - ]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferBatch', - data=[ - operator, # operator - sender, # from - recipient, # to - *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), - ] - ) - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_invalid_value(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - sender = account.contract_address - recipient = owner.contract_address - - await signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [sender, *prepare_calldata(TOKEN_IDS), *prepare_calldata(MAX_UINT_VALUES), DATA]) - - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(INVALID_VALUES), DATA - ]), - "ERC1155: value is not a valid Uint256") - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_invalid_id(self, minted_factory): - erc1155, owner, account, _ = minted_factory - - sender = account.contract_address - recipient = owner.contract_address - transfer_values = [to_uint(0)]*3 - - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(INVALID_IDS), - *prepare_calldata(transfer_values), DATA - ]), - "ERC1155: token_id is not a valid Uint256") - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_insufficient_balance(self, - minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - - values = values = MINT_VALUES.copy() - values[1] = add_uint(values[1], to_uint(1)) - - await assert_revert(signer.send_transaction( - account2, erc1155.contract_address, 'safeBatchTransferFrom', - [sender, recipient, *prepare_calldata(TOKEN_IDS), *prepare_calldata(values), DATA]), - "ERC1155: insufficient balance for transfer") - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_unapproved(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - - await assert_revert(signer.send_transaction( - account1, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), DATA - ]), - "ERC1155: caller is not owner nor approved") - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_to_zero_address(self, - minted_factory): - erc1155, _, account, _ = minted_factory - - sender = account.contract_address - - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, ZERO_ADDRESS, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), DATA - ]), - "ERC1155: transfer to the zero address") - - - @pytest.mark.asyncio - @pytest.mark.parametrize( - "values,token_ids", - [ - (TRANSFER_VALUES[:2], TOKEN_IDS), - (TRANSFER_VALUES, TOKEN_IDS[:2]) - ] - ) - async def test_safe_batch_transfer_from_uneven_arrays(self, - minted_factory, values, token_ids): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - - await assert_revert(signer.send_transaction( - account2, erc1155.contract_address, 'safeBatchTransferFrom', - [sender, recipient, *prepare_calldata(token_ids), *prepare_calldata(values), DATA]), - "ERC1155: ids and values length mismatch") - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_overflow(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - sender = account2.contract_address - recipient = account1.contract_address - transfer_values = to_uint_array([0, 1, 0]) - - # Bring 1 recipient's balance to max possible - await signer.send_transaction( - account1, erc1155.contract_address, 'mintBatch', - [recipient, *prepare_calldata(TOKEN_IDS), *prepare_calldata(MAX_UINT_VALUES), DATA] - ) - - # Issuing recipient any more on just 1 token_id - # should revert due to overflow - await assert_revert(signer.send_transaction( - account2, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(transfer_values), DATA - ]), - "ERC1155: balance overflow") - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_to_receiver(self, minted_factory): - erc1155, _, account2, receiver = minted_factory - - sender = account2.contract_address - recipient = receiver.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), DATA - ]) - - execution_info = await erc1155.balanceOfBatch( - [sender]*3+[recipient]*3, TOKEN_IDS*2).execute() - assert execution_info.result.balances[:3] == TRANSFER_DIFFERENCES - assert execution_info.result.balances[3:] == TRANSFER_VALUES - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_to_receiver_rejection(self, - minted_factory): - erc1155, _, account2, receiver = minted_factory - - sender = account2.contract_address - recipient = receiver.contract_address - - await assert_revert(signer.send_transaction( - account2, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), *REJECT_DATA - ]), - "ERC1155: ERC1155Receiver rejected tokens") - - - @pytest.mark.asyncio - async def test_safe_batch_transfer_from_to_non_receiver(self, - minted_factory): - erc1155, _, account, _ = minted_factory - - sender = account.contract_address - recipient = erc1155.contract_address - - await assert_revert(signer.send_transaction( - account, erc1155.contract_address, 'safeBatchTransferFrom', - [ - sender, recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(TRANSFER_VALUES), DATA - ]), - "ERC1155: transfer to non-ERC1155Receiver implementer") diff --git a/tests/token/erc1155/test_ERC1155Internals.py b/tests/token/erc1155/test_ERC1155Internals.py deleted file mode 100644 index a706598cf..000000000 --- a/tests/token/erc1155/test_ERC1155Internals.py +++ /dev/null @@ -1,67 +0,0 @@ -import pytest -from signers import MockSigner -from utils import State, Account, get_contract_class, cached_contract - -from ERC1155BaseSuite import TOKEN_ID, NEW_URI, DEFAULT_URI - -signer = MockSigner(123456789987654321) - - -# -# Fixtures -# - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc1155_cls = get_contract_class('ERC1155Mock') - return account_cls, erc1155_cls - - -@pytest.fixture(scope='module') -async def erc1155_init(contract_classes): - _, erc1155_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc1155 = await starknet.deploy( - contract_class=erc1155_cls, - constructor_calldata=[DEFAULT_URI, account1.contract_address] - ) - return ( - starknet.state, - account1, - account2, - erc1155, - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc1155_init): - account_cls, erc1155_cls = contract_classes - state, account1, account2, erc1155 = erc1155_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc1155 = cached_contract(_state, erc1155_cls, erc1155) - return erc1155, account1, account2 - - -class TestERC1155Internals(): - # - # Set URI - # - - - @pytest.mark.asyncio - async def test_set_uri(self, contract_factory): - erc1155, owner, _ = contract_factory - - await signer.send_transaction( - owner, erc1155.contract_address, 'setURI', - [NEW_URI] - ) - - execution_info = await erc1155.uri(TOKEN_ID).execute() - assert execution_info.result.uri == NEW_URI diff --git a/tests/token/erc1155/test_ERC1155MintableBurnable.py b/tests/token/erc1155/test_ERC1155MintableBurnable.py deleted file mode 100644 index 5f548d394..000000000 --- a/tests/token/erc1155/test_ERC1155MintableBurnable.py +++ /dev/null @@ -1,723 +0,0 @@ -import pytest -from signers import MockSigner -from utils import State, Account, get_contract_class, cached_contract, assert_event_emitted - -from access.OwnableBaseSuite import OwnableBase -from ERC1155BaseSuite import ( - ERC1155Base, to_uint_array, prepare_calldata, - TOKEN_ID, MINT_VALUE, - MINT_VALUE,TOKEN_IDS, - MINT_VALUES, MAX_UINT_VALUES, - INVALID_VALUES, INVALID_IDS, - DATA, REJECT_DATA, DEFAULT_URI -) - -from nile.utils import ( - MAX_UINT256, ZERO_ADDRESS, INVALID_UINT256, TRUE, FALSE, - to_uint, add_uint, sub_uint, assert_revert -) - -signer = MockSigner(123456789987654321) - -# -# Constants -# -BURN_value = to_uint(500) -BURN_VALUES = [BURN_value, to_uint(1000), to_uint(1500)] -BURN_DIFFERENCES = [sub_uint(m, b) for m, b in zip(MINT_VALUES, BURN_VALUES)] - -# -# Fixtures -# - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc1155_cls = get_contract_class('ERC1155MintableBurnable') - receiver_cls = get_contract_class('ERC1155Holder') - return account_cls, erc1155_cls, receiver_cls - - -@pytest.fixture(scope='module') -async def erc1155_init(contract_classes): - _, erc1155_cls, receiver_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc1155 = await starknet.deploy( - contract_class=erc1155_cls, - constructor_calldata=[DEFAULT_URI, account1.contract_address] - ) - receiver = await starknet.deploy( - contract_class=receiver_cls - ) - return ( - starknet.state, - account1, - account2, - erc1155, - receiver - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc1155_init): - account_cls, erc1155_cls, receiver_cls = contract_classes - state, account1, account2, erc1155, receiver = erc1155_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc1155 = cached_contract(_state, erc1155_cls, erc1155) - receiver = cached_contract(_state, receiver_cls, receiver) - return erc1155, account1, account2, receiver - - -@pytest.fixture -async def minted_factory(contract_classes, erc1155_init): - account_cls, erc1155_cls, receiver_cls = contract_classes - state, owner, account, erc1155, receiver = erc1155_init - _state = state.copy() - owner = cached_contract(_state, account_cls, owner) - account = cached_contract(_state, account_cls, account) - erc1155 = cached_contract(_state, erc1155_cls, erc1155) - receiver = cached_contract(_state, receiver_cls, receiver) - await signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [ - account.contract_address, # to - *prepare_calldata(TOKEN_IDS), # ids - *prepare_calldata(MINT_VALUES), # values - DATA - ] - ) - return erc1155, owner, account, receiver - - - -class TestERC1155MintableBurnable(ERC1155Base, OwnableBase): - # - # Minting - # - - @pytest.mark.asyncio - async def test_mint(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - await signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *TOKEN_ID, *MINT_VALUE, DATA]) - - execution_info = await erc1155.balanceOf(recipient, TOKEN_ID).execute() - assert execution_info.result.balance == MINT_VALUE - - - @pytest.mark.asyncio - async def test_mint_emits_event(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - execution_info = await signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *TOKEN_ID, *MINT_VALUE, DATA]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferSingle', - data=[ - owner.contract_address, # operator - ZERO_ADDRESS, # from - recipient, # to - *TOKEN_ID, - *MINT_VALUE - ] - ) - - - @pytest.mark.asyncio - async def test_mint_to_zero_address(self, contract_factory): - erc1155, owner, _, _ = contract_factory - - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [ZERO_ADDRESS, *TOKEN_ID, *MINT_VALUE, DATA]), - "ERC1155: mint to the zero address") - - - @pytest.mark.asyncio - async def test_mint_overflow(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - # Bring recipient's balance to max possible - await signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *TOKEN_ID, *MAX_UINT256, DATA]) - - # Issuing recipient any more should revert due to overflow - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *TOKEN_ID, *to_uint(1), DATA]), - "ERC1155: balance overflow") - - - @pytest.mark.asyncio - @pytest.mark.parametrize( - "value,token_id,error", - [ - (MINT_VALUE, INVALID_UINT256, - "ERC1155: token_id is not a valid Uint256"), - (INVALID_UINT256, TOKEN_ID, - "ERC1155: value is not a valid Uint256") - ] - ) - async def test_mint_invalid_uint(self, contract_factory, value, token_id, error): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *token_id, *value, DATA]), - error) - - - @pytest.mark.asyncio - async def test_mint_receiver(self, contract_factory): - erc1155, owner, _, receiver = contract_factory - - recipient = receiver.contract_address - - await signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *TOKEN_ID, *MINT_VALUE, DATA]) - - execution_info = await erc1155.balanceOf( - recipient, TOKEN_ID).execute() - assert execution_info.result.balance == MINT_VALUE - - - @pytest.mark.asyncio - async def test_mint_receiver_rejection(self, contract_factory): - erc1155, owner, _, receiver = contract_factory - - recipient = receiver.contract_address - - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *TOKEN_ID, *MINT_VALUE, *REJECT_DATA]), - "ERC1155: ERC1155Receiver rejected tokens") - - - @pytest.mark.asyncio - async def test_mint_to_unsafe_contract(self, contract_factory): - erc1155, owner, _, _ = contract_factory - - recipient = erc1155.contract_address - - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [recipient, *TOKEN_ID, *MINT_VALUE, DATA]), - "ERC1155: transfer to non-ERC1155Receiver implementer") - - # - # Burning - # - - - @pytest.mark.asyncio - async def test_burn(self, minted_factory): - erc1155, _, account, _ = minted_factory - - subject = account.contract_address - - await signer.send_transaction( - account, erc1155.contract_address, 'burn', - [subject, *TOKEN_ID, *BURN_value]) - - execution_info = await erc1155.balanceOf(subject, TOKEN_ID).execute() - assert execution_info.result.balance == sub_uint(MINT_VALUE, BURN_value) - - - @pytest.mark.asyncio - async def test_burn_emits_event(self, minted_factory): - erc1155, _, account, _ = minted_factory - - subject = account.contract_address - - execution_info = await signer.send_transaction( - account, erc1155.contract_address, 'burn', - [subject, *TOKEN_ID, *BURN_value]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferSingle', - data=[ - subject, # operator - subject, # from - ZERO_ADDRESS, # to - *TOKEN_ID, - *BURN_value - ] - ) - - - @pytest.mark.asyncio - async def test_burn_approved(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - operator = account1.contract_address - subject = account2.contract_address - - # account2 approves account - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, TRUE]) - - await signer.send_transaction( - account1, erc1155.contract_address, 'burn', - [subject, *TOKEN_ID, *BURN_value]) - - execution_info = await erc1155.balanceOf(subject, TOKEN_ID).execute() - assert execution_info.result.balance == sub_uint(MINT_VALUE, BURN_value) - - - @pytest.mark.asyncio - async def test_burn_approved_emits_event(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - operator = account1.contract_address - subject = account2.contract_address - - # account2 approves account - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, TRUE] - ) - - execution_info = await signer.send_transaction( - account1, erc1155.contract_address, 'burn', - [subject, *TOKEN_ID, *BURN_value] - ) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferSingle', - data=[ - operator, # operator - subject, # from - ZERO_ADDRESS, # to - *TOKEN_ID, - *BURN_value - ] - ) - - - @pytest.mark.asyncio - async def test_burn_insufficient_balance(self, minted_factory): - erc1155, _, account, _ = minted_factory - - subject = account.contract_address - burn_value = add_uint(MINT_VALUE, to_uint(1)) - - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'burn', - [subject, *TOKEN_ID, *burn_value]), - "ERC1155: burn value exceeds balance") - - - @pytest.mark.asyncio - async def test_burn_invalid_value(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - burner = account.contract_address - - # mint max possible to avoid insufficient balance - await signer.send_transaction( - owner, erc1155.contract_address, 'mint', - [burner, *TOKEN_ID, *MAX_UINT256, DATA]) - - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'burn', - [burner, *TOKEN_ID, *INVALID_UINT256]), - "ERC1155: value is not a valid Uint256") - - - @pytest.mark.asyncio - async def test_burn_invalid_id(self, minted_factory): - erc1155, _, account, _ = minted_factory - - burner = account.contract_address - - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'burn', - [burner, *INVALID_UINT256, *to_uint(0)]), - "ERC1155: token_id is not a valid Uint256") - - - # - # Batch Minting - # - - - @pytest.mark.asyncio - async def test_mint_batch(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - await signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [recipient, *prepare_calldata(TOKEN_IDS), *prepare_calldata(MINT_VALUES), DATA]) - - execution_info = await erc1155.balanceOfBatch( - [recipient]*3, TOKEN_IDS).execute() - assert execution_info.result.balances == MINT_VALUES - - - @pytest.mark.asyncio - async def test_mint_batch_emits_event(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - execution_info = await signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [recipient, *prepare_calldata(TOKEN_IDS), *prepare_calldata(MINT_VALUES), DATA]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferBatch', - data=[ - owner.contract_address, # operator - ZERO_ADDRESS, # from - recipient, # to - *prepare_calldata(TOKEN_IDS), - *prepare_calldata(MINT_VALUES), - ] - ) - - - @pytest.mark.asyncio - async def test_mint_batch_to_zero_address(self, contract_factory): - erc1155, owner, _, _ = contract_factory - - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [ZERO_ADDRESS, *prepare_calldata(TOKEN_IDS), *prepare_calldata(MINT_VALUES), DATA]), - "ERC1155: mint to the zero address") - - - @pytest.mark.asyncio - async def test_mint_batch_overflow(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - # Bring recipient's balance to max possible - await signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [recipient, *prepare_calldata(TOKEN_IDS), *prepare_calldata(MAX_UINT_VALUES), DATA]) - - # Issuing recipient any more on just 1 token_id - # should revert due to overflow - values = to_uint_array([0, 1, 0]) - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [recipient, *prepare_calldata(TOKEN_IDS), *prepare_calldata(values), DATA]), - "ERC1155: balance overflow") - - - @pytest.mark.asyncio - @pytest.mark.parametrize( - "values,token_ids,error", - [ - (INVALID_VALUES, TOKEN_IDS, "ERC1155: value is not a valid Uint256"), - (MINT_VALUES, INVALID_IDS, "ERC1155: token_id is not a valid Uint256") - ]) - async def test_mint_batch_invalid_uint(self, contract_factory, values, token_ids, error): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [recipient, *prepare_calldata(token_ids), *prepare_calldata(values), DATA]), - error) - - - @pytest.mark.asyncio - @pytest.mark.parametrize( - "values,token_ids", - [ - (MINT_VALUES[:2], TOKEN_IDS), - (MINT_VALUES, TOKEN_IDS[:2]) - ]) - async def test_mint_batch_uneven_arrays(self, contract_factory, values, token_ids): - erc1155, owner, account, _ = contract_factory - - recipient = account.contract_address - - await assert_revert( - signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [recipient, *prepare_calldata(token_ids), *prepare_calldata(values), DATA]), - "ERC1155: ids and values length mismatch") - - - @pytest.mark.asyncio - async def test_mint_batch_to_receiver(self, contract_factory): - erc1155, owner, _, receiver = contract_factory - - recipient = receiver.contract_address - - await signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [ - recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(MINT_VALUES), DATA - ]) - - execution_info = await erc1155.balanceOfBatch( - [recipient]*3, TOKEN_IDS).execute() - assert execution_info.result.balances == MINT_VALUES - - - @pytest.mark.asyncio - async def test_mint_batch_to_receiver_rejection(self, contract_factory): - erc1155, owner, _, receiver = contract_factory - - recipient = receiver.contract_address - - await assert_revert(signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [ - recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(MINT_VALUES), *REJECT_DATA - ]), - "ERC1155: ERC1155Receiver rejected tokens") - - - @pytest.mark.asyncio - async def test_mint_batch_to_non_receiver(self, contract_factory): - erc1155, owner, _, _ = contract_factory - - recipient = erc1155.contract_address - - await assert_revert(signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [ - recipient, *prepare_calldata(TOKEN_IDS), - *prepare_calldata(MINT_VALUES), DATA - ]), - "ERC1155: transfer to non-ERC1155Receiver implementer") - - # - # Batch Burning - # - - - @pytest.mark.asyncio - async def test_burn_batch(self, minted_factory): - erc1155, _, account, _ = minted_factory - - burner = account.contract_address - - await signer.send_transaction( - account, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(TOKEN_IDS), *prepare_calldata(BURN_VALUES)]) - - execution_info = await erc1155.balanceOfBatch( - [burner]*3, TOKEN_IDS).execute() - assert execution_info.result.balances == BURN_DIFFERENCES - - - @pytest.mark.asyncio - async def test_burn_batch_emits_event(self, minted_factory): - erc1155, _, account, _ = minted_factory - - burner = account.contract_address - - execution_info = await signer.send_transaction( - account, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(TOKEN_IDS), *prepare_calldata(BURN_VALUES)]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferBatch', - data=[ - burner, # operator - burner, # from - ZERO_ADDRESS, # to - *prepare_calldata(TOKEN_IDS), - *prepare_calldata(BURN_VALUES), - ] - ) - - - @pytest.mark.asyncio - async def test_burn_batch_from_approved(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - burner = account2.contract_address - operator = account1.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, TRUE]) - - await signer.send_transaction( - account1, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(TOKEN_IDS), *prepare_calldata(BURN_VALUES)]) - - execution_info = await erc1155.balanceOfBatch( - [burner]*3, TOKEN_IDS).execute() - assert execution_info.result.balances == BURN_DIFFERENCES - - - @pytest.mark.asyncio - async def test_burn_batch_from_approved_emits_event(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - burner = account2.contract_address - operator = account1.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, TRUE]) - - execution_info = await signer.send_transaction( - account1, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(TOKEN_IDS), *prepare_calldata(BURN_VALUES)]) - - assert_event_emitted( - execution_info, - from_address=erc1155.contract_address, - name='TransferBatch', - data=[ - operator, # operator - burner, # from - ZERO_ADDRESS, # to - *prepare_calldata(TOKEN_IDS), - *prepare_calldata(BURN_VALUES), - ] - ) - - - @pytest.mark.asyncio - async def test_burn_batch_from_unapproved(self, minted_factory): - erc1155, account1, account2, _ = minted_factory - - burner = account2.contract_address - operator = account1.contract_address - - await signer.send_transaction( - account2, erc1155.contract_address, 'setApprovalForAll', - [operator, FALSE]) - - await assert_revert(signer.send_transaction( - account1, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(TOKEN_IDS), *prepare_calldata(BURN_VALUES)]), - "ERC1155: caller is not owner nor approved") - - - @pytest.mark.asyncio - async def test_burn_batch_from_zero_address(self, minted_factory): - erc1155, _, _, _ = minted_factory - - values = [to_uint(0)]*3 - - # Attempt to burn nothing (since cannot mint non_zero balance to burn) - # note invoking this way (without signer) gives caller address of 0 - await assert_revert( - erc1155.burnBatch(ZERO_ADDRESS, TOKEN_IDS, values).execute(), - "ERC1155: burn from the zero address") - - - @pytest.mark.asyncio - async def test_burn_batch_insufficent_balance(self, minted_factory): - erc1155, _, account, _ = minted_factory - - burner = account.contract_address - values = MINT_VALUES.copy() - values[1] = add_uint(values[1], to_uint(1)) - - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(TOKEN_IDS), *prepare_calldata(values)]), - "ERC1155: burn value exceeds balance") - - - @pytest.mark.asyncio - async def test_burn_batch_invalid_value(self, contract_factory): - erc1155, owner, account, _ = contract_factory - - burner = account.contract_address - - # mint max possible to avoid insufficient balance - await signer.send_transaction( - owner, erc1155.contract_address, 'mintBatch', - [burner, *prepare_calldata(TOKEN_IDS), *prepare_calldata(MAX_UINT_VALUES), 0]) - - # attempt passing an invalid uint in batch - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(TOKEN_IDS), *prepare_calldata(INVALID_VALUES)]), - "ERC1155: value is not a valid Uint256") - - - @pytest.mark.asyncio - async def test_burn_batch_invalid_id(self, minted_factory): - erc1155, _, account, _ = minted_factory - - burner = account.contract_address - burn_values = [to_uint(0)]*3 - - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(INVALID_IDS), *prepare_calldata(burn_values)]), - "ERC1155: token_id is not a valid Uint256") - - - @pytest.mark.asyncio - @pytest.mark.parametrize( - "values,token_ids", - [ - (BURN_VALUES[:2], TOKEN_IDS), - (BURN_VALUES, TOKEN_IDS[:2]) - ] - ) - async def test_burn_batch_uneven_arrays(self, - minted_factory, values, token_ids): - erc1155, _, account, _ = minted_factory - - burner = account.contract_address - - await assert_revert( - signer.send_transaction( - account, erc1155.contract_address, 'burnBatch', - [burner, *prepare_calldata(token_ids), *prepare_calldata(values)]), - "ERC1155: ids and values length mismatch") diff --git a/tests/token/erc20/ERC20BaseSuite.py b/tests/token/erc20/ERC20BaseSuite.py deleted file mode 100644 index 69d4c6386..000000000 --- a/tests/token/erc20/ERC20BaseSuite.py +++ /dev/null @@ -1,714 +0,0 @@ -import pytest - -from signers import MockSigner -from nile.utils import ( - to_uint, add_uint, sub_uint, str_to_felt, MAX_UINT256, ZERO_ADDRESS, - INVALID_UINT256, TRUE, assert_revert -) -from utils import ( - assert_event_emitted, assert_events_emitted, contract_path, State, get_cairo_path -) - - -signer = MockSigner(123456789987654321) - -# testing vars -NAME = str_to_felt("Token") -SYMBOL = str_to_felt("TKN") -DECIMALS = 18 -RECIPIENT = 123 -INIT_SUPPLY = to_uint(1000) -AMOUNT = to_uint(200) -UINT_ONE = to_uint(1) -UINT_ZERO = to_uint(0) - - - -class ERC20Base: - # - # Constructor - # - - @pytest.mark.asyncio - async def test_constructor(self, contract_factory): - erc20, account, _ = contract_factory - - # balanceOf recipient - execution_info = await erc20.balanceOf(account.contract_address).execute() - assert execution_info.result.balance == INIT_SUPPLY - - # totalSupply - execution_info = await erc20.totalSupply().execute() - assert execution_info.result.totalSupply == INIT_SUPPLY - - - @pytest.mark.asyncio - async def test_constructor_exceed_max_decimals(self, contract_factory): - _, account, _ = contract_factory - - bad_decimals = 2**8 + 1 - - starknet = await State.init() - await assert_revert( - starknet.deploy( - contract_path("openzeppelin/token/erc20/presets/ERC20.cairo"), - constructor_calldata=[ - NAME, - SYMBOL, - bad_decimals, - *INIT_SUPPLY, - account.contract_address - ], - cairo_path=get_cairo_path() - ), - reverted_with="ERC20: decimals exceed 2^8" - ) - - - @pytest.mark.asyncio - async def test_name(self, contract_factory): - erc20, _, _ = contract_factory - execution_info = await erc20.name().execute() - assert execution_info.result.name == NAME - - - @pytest.mark.asyncio - async def test_symbol(self, contract_factory): - erc20, _, _ = contract_factory - execution_info = await erc20.symbol().execute() - assert execution_info.result.symbol == SYMBOL - - - @pytest.mark.asyncio - async def test_decimals(self, contract_factory): - erc20, _, _ = contract_factory - execution_info = await erc20.decimals().execute() - assert execution_info.result.decimals == DECIMALS - - - # - # approve - # - - - @pytest.mark.asyncio - async def test_approve(self, contract_factory): - erc20, account, spender = contract_factory - - # check spender's allowance starts at zero - - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == UINT_ZERO - - # set approval - return_bool = await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - assert return_bool.call_info.retdata[1] == TRUE - - # check spender's allowance - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == AMOUNT - - - - @pytest.mark.asyncio - async def test_approve_emits_event(self, contract_factory): - erc20, account, spender = contract_factory - - tx_exec_info = await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ]) - - assert_event_emitted( - tx_exec_info, - from_address=erc20.contract_address, - name='Approval', - data=[ - account.contract_address, - spender.contract_address, - *AMOUNT - ] - ) - - - @pytest.mark.asyncio - async def test_approve_from_zero_address(self, contract_factory): - erc20, _, spender = contract_factory - - # Without using an account abstraction, the caller address - # (get_caller_address) is zero - await assert_revert( - erc20.approve(spender.contract_address, AMOUNT).execute(), - reverted_with="ERC20: cannot approve from the zero address" - ) - - - @pytest.mark.asyncio - async def test_approve_to_zero_address(self, contract_factory): - erc20, account, _ = contract_factory - - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'approve', [ - ZERO_ADDRESS, - *UINT_ONE - ]), - reverted_with="ERC20: cannot approve to the zero address" - ) - - - @pytest.mark.asyncio - async def test_approve_invalid_uint256(self, contract_factory): - erc20, account, spender = contract_factory - - await assert_revert( - signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *INVALID_UINT256 - ]), - reverted_with="ERC20: amount is not a valid Uint256" - ) - - - # - # transfer - # - - - @pytest.mark.asyncio - async def test_transfer(self, contract_factory): - erc20, account, _ = contract_factory - - # check original totalSupply - execution_info = await erc20.balanceOf(account.contract_address).execute() - assert execution_info.result.balance == INIT_SUPPLY - - # check recipient original balance - execution_info = await erc20.balanceOf(RECIPIENT).execute() - assert execution_info.result.balance == UINT_ZERO - - # transfer - return_bool = await signer.send_transaction( - account, erc20.contract_address, 'transfer', [ - RECIPIENT, - *AMOUNT - ] - ) - assert return_bool.call_info.retdata[1] == TRUE - - # check account balance - execution_info = await erc20.balanceOf(account.contract_address).execute() - assert execution_info.result.balance == sub_uint(INIT_SUPPLY, AMOUNT) - - # check recipient balance - execution_info = await erc20.balanceOf(RECIPIENT).execute() - assert execution_info.result.balance == AMOUNT - - # check totalSupply - execution_info = await erc20.totalSupply().execute() - assert execution_info.result.totalSupply == INIT_SUPPLY - - - @pytest.mark.asyncio - async def test_transfer_emits_event(self, contract_factory): - erc20, account, _ = contract_factory - - tx_exec_info = await signer.send_transaction( - account, erc20.contract_address, 'transfer', [ - RECIPIENT, - *AMOUNT - ]) - - assert_event_emitted( - tx_exec_info, - from_address=erc20.contract_address, - name='Transfer', - data=[ - account.contract_address, - RECIPIENT, - *AMOUNT - ] - ) - - - @pytest.mark.asyncio - async def test_transfer_not_enough_balance(self, contract_factory): - erc20, account, _ = contract_factory - - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'transfer', [ - RECIPIENT, - *add_uint(INIT_SUPPLY, UINT_ONE) - ]), - reverted_with="ERC20: transfer amount exceeds balance" - ) - - - @pytest.mark.asyncio - async def test_transfer_to_zero_address(self, contract_factory): - erc20, account, _ = contract_factory - - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'transfer', [ - ZERO_ADDRESS, - *UINT_ONE - ]), - reverted_with="ERC20: cannot transfer to the zero address" - ) - - - @pytest.mark.asyncio - async def test_transfer_from_zero_address(self, contract_factory): - erc20, _, _ = contract_factory - - # Without using an account abstraction, the caller address - # (get_caller_address) is zero - await assert_revert( - erc20.transfer(RECIPIENT, UINT_ONE).execute(), - reverted_with="ERC20: cannot transfer from the zero address" - ) - - - @pytest.mark.asyncio - async def test_transfer_invalid_uint256(self, contract_factory): - erc20, account, _ = contract_factory - - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'transfer', [ - RECIPIENT, - *INVALID_UINT256 - ]), - reverted_with="ERC20: amount is not a valid Uint256" - ) - - - # - # transferFrom - # - - - @pytest.mark.asyncio - async def test_transferFrom(self, contract_factory): - erc20, account, spender = contract_factory - - # approve - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - # transferFrom - return_bool = await signer.send_transaction( - spender, erc20.contract_address, 'transferFrom', [ - account.contract_address, - RECIPIENT, - *AMOUNT - ] - ) - assert return_bool.call_info.retdata[1] == TRUE - - # check account balance - execution_info = await erc20.balanceOf(account.contract_address).execute() - assert execution_info.result.balance == sub_uint(INIT_SUPPLY, AMOUNT) - - # check recipient balance - execution_info = await erc20.balanceOf(RECIPIENT).execute() - assert execution_info.result.balance == AMOUNT - - # check spender allowance after tx - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == UINT_ZERO - - - @pytest.mark.asyncio - async def test_transferFrom_emits_event(self, contract_factory): - erc20, account, spender = contract_factory - - # approve - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ]) - - # transferFrom - tx_exec_info = await signer.send_transaction( - spender, erc20.contract_address, 'transferFrom', [ - account.contract_address, - RECIPIENT, - *AMOUNT - ]) - - # check events - assert_events_emitted( - tx_exec_info, - [ - [0, erc20.contract_address, 'Approval', [ - account.contract_address, spender.contract_address, *UINT_ZERO]], - [1, erc20.contract_address, 'Transfer', [ - account.contract_address, RECIPIENT, *AMOUNT]] - ] - ) - - - async def test_transferFrom_doesnt_consume_infinite_allowance(self, contract_factory): - erc20, account, spender = contract_factory - - # approve - await signer.send_transaction(account, erc20.contract_address, 'approve', [spender.contract_address, *MAX_UINT256]) - - # check approval - execution_info_1 = await erc20.allowance(account.contract_address, spender.contract_address).call() - assert execution_info_1.result.remaining == MAX_UINT256 - - # transferFrom - await signer.send_transaction( - spender, erc20.contract_address, 'transferFrom', [ - account.contract_address, - RECIPIENT, - *AMOUNT - ]) - - # re-check approval - execution_info_2 = await erc20.allowance(account.contract_address, spender.contract_address).call() - assert execution_info_2.result.remaining == MAX_UINT256 - - - @pytest.mark.asyncio - async def test_transferFrom_greater_than_allowance(self, contract_factory): - erc20, account, spender = contract_factory - # we use the same signer to control the main and the spender accounts - # this is ok since they're still two different accounts - - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - - fail_amount = add_uint(AMOUNT, UINT_ONE) - - # increasing the transfer amount above allowance - await assert_revert(signer.send_transaction( - spender, erc20.contract_address, 'transferFrom', [ - account.contract_address, - RECIPIENT, - *fail_amount - ]), - reverted_with="ERC20: insufficient allowance" - ) - - - @pytest.mark.asyncio - async def test_transferFrom_from_zero_address(self, contract_factory): - erc20, _, spender = contract_factory - - await assert_revert(signer.send_transaction( - spender, erc20.contract_address, 'transferFrom', [ - ZERO_ADDRESS, - RECIPIENT, - *AMOUNT - ]), - reverted_with="ERC20: insufficient allowance" - ) - - - @pytest.mark.asyncio - async def test_transferFrom_to_zero_address(self, contract_factory): - erc20, account, spender = contract_factory - - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *UINT_ONE - ] - ) - - await assert_revert(signer.send_transaction( - spender, erc20.contract_address, 'transferFrom', [ - account.contract_address, - ZERO_ADDRESS, - *UINT_ONE - ]), - reverted_with="ERC20: cannot transfer to the zero address" - ) - - - # - # increaseAllowance - # - - - @pytest.mark.asyncio - async def test_increaseAllowance(self, contract_factory): - erc20, account, spender = contract_factory - - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == UINT_ZERO - - # set approve - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - - # check allowance - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == AMOUNT - - # increase allowance - return_bool = await signer.send_transaction( - account, erc20.contract_address, 'increaseAllowance', [ - spender.contract_address, - *AMOUNT - ] - ) - assert return_bool.call_info.retdata[1] == TRUE - - # check spender's allowance increased - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == add_uint(AMOUNT, AMOUNT) - - - @pytest.mark.asyncio - async def test_increaseAllowance_emits_event(self, contract_factory): - erc20, account, spender = contract_factory - - # set approve - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ]) - - # increase allowance - tx_exec_info = await signer.send_transaction( - account, erc20.contract_address, 'increaseAllowance', [ - spender.contract_address, - *AMOUNT - ]) - - new_allowance = add_uint(AMOUNT, AMOUNT) - - assert_event_emitted( - tx_exec_info, - from_address=erc20.contract_address, - name='Approval', - data=[ - account.contract_address, - spender.contract_address, - *new_allowance - ] - ) - - - @pytest.mark.asyncio - async def test_increaseAllowance_overflow(self, contract_factory): - erc20, account, spender = contract_factory - - # approve max - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *MAX_UINT256 - ] - ) - - # overflow_amount adds (1, 0) to (2**128 - 1, 2**128 - 1) - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'increaseAllowance', [ - spender.contract_address, - *UINT_ONE - ]), - reverted_with="ERC20: allowance overflow" - ) - - - @pytest.mark.asyncio - async def test_increaseAllowance_to_zero_address(self, contract_factory): - erc20, account, spender = contract_factory - - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'increaseAllowance', [ - ZERO_ADDRESS, - *AMOUNT - ]) - ) - - - @pytest.mark.asyncio - async def test_increaseAllowance_from_zero_address(self, contract_factory): - erc20, account, spender = contract_factory - - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - - await assert_revert( - erc20.increaseAllowance(RECIPIENT, AMOUNT).execute() - ) - - - # - # decreaseAllowance - # - - - @pytest.mark.asyncio - async def test_decreaseAllowance(self, contract_factory): - erc20, account, spender = contract_factory - - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == UINT_ZERO - - # set approve - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == AMOUNT - - # decrease allowance - return_bool = await signer.send_transaction( - account, erc20.contract_address, 'decreaseAllowance', [ - spender.contract_address, - *UINT_ONE - ] - ) - assert return_bool.call_info.retdata[1] == TRUE - - new_allowance = sub_uint(AMOUNT, UINT_ONE) - - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == new_allowance - - - @pytest.mark.asyncio - async def test_decreaseAllowance_emits_event(self, contract_factory): - erc20, account, spender = contract_factory - - # set approve - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *INIT_SUPPLY - ]) - - # decrease allowance - tx_exec_info = await signer.send_transaction( - account, erc20.contract_address, 'decreaseAllowance', [ - spender.contract_address, - *AMOUNT - ]) - - new_allowance = sub_uint(INIT_SUPPLY, AMOUNT) - - assert_event_emitted( - tx_exec_info, - from_address=erc20.contract_address, - name='Approval', - data=[ - account.contract_address, - spender.contract_address, - *new_allowance - ] - ) - - - @pytest.mark.asyncio - async def test_decreaseAllowance_overflow(self, contract_factory): - erc20, account, spender = contract_factory - - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - - execution_info = await erc20.allowance(account.contract_address, spender.contract_address).execute() - assert execution_info.result.remaining == AMOUNT - - allowance_plus_one = add_uint(AMOUNT, UINT_ONE) - - # increasing the decreased allowance amount by more than the spender's allowance - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'decreaseAllowance', [ - spender.contract_address, - *allowance_plus_one - ]), - reverted_with="ERC20: allowance below zero" - ) - - - @pytest.mark.asyncio - async def test_decreaseAllowance_to_zero_address(self, contract_factory): - erc20, account, spender = contract_factory - - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'decreaseAllowance', [ - ZERO_ADDRESS, - *AMOUNT - ]) - ) - - - @pytest.mark.asyncio - async def test_decreaseAllowance_from_zero_address(self, contract_factory): - erc20, account, spender = contract_factory - - await signer.send_transaction( - account, erc20.contract_address, 'approve', [ - spender.contract_address, - *AMOUNT - ] - ) - - await assert_revert( - erc20.decreaseAllowance(RECIPIENT, AMOUNT).execute() - ) - - - @pytest.mark.asyncio - async def test_decreaseAllowance_invalid_uint256(self, contract_factory): - erc20, account, spender = contract_factory - - await assert_revert( - signer.send_transaction( - account, erc20.contract_address, 'decreaseAllowance', [ - spender.contract_address, - *INVALID_UINT256 - ]), - reverted_with="ERC20: subtracted_value is not a valid Uint256" - ) diff --git a/tests/token/erc20/test_ERC20.py b/tests/token/erc20/test_ERC20.py deleted file mode 100644 index a196a7f31..000000000 --- a/tests/token/erc20/test_ERC20.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest -from signers import MockSigner -from utils import get_contract_class, cached_contract, State, Account -from ERC20BaseSuite import ERC20Base, NAME, SYMBOL, DECIMALS, INIT_SUPPLY - - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc20_cls = get_contract_class('ERC20') - - return account_cls, erc20_cls - - -@pytest.fixture(scope='module') -async def erc20_init(contract_classes): - account_cls, erc20_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc20 = await starknet.deploy( - contract_class=erc20_cls, - constructor_calldata=[ - NAME, - SYMBOL, - DECIMALS, - *INIT_SUPPLY, - account1.contract_address, # recipient - ] - ) - return ( - starknet.state, - account1, - account2, - erc20 - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc20_init): - account_cls, erc20_cls = contract_classes - state, account1, account2, erc20 = erc20_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc20 = cached_contract(_state, erc20_cls, erc20) - return erc20, account1, account2 - - -class TestERC20(ERC20Base): - pass diff --git a/tests/token/erc20/test_ERC20Burnable.py b/tests/token/erc20/test_ERC20Burnable.py deleted file mode 100644 index a15fba3a6..000000000 --- a/tests/token/erc20/test_ERC20Burnable.py +++ /dev/null @@ -1,216 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import ( - add_uint, sub_uint, ZERO_ADDRESS, INVALID_UINT256, assert_revert, -) -from utils import ( - get_contract_class, cached_contract, assert_events_emitted, - assert_event_emitted, State, Account -) -from ERC20BaseSuite import ( - ERC20Base, NAME, SYMBOL, DECIMALS, INIT_SUPPLY, AMOUNT, UINT_ONE, UINT_ZERO -) - - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc20_cls = get_contract_class('ERC20Burnable') - - return account_cls, erc20_cls - - -@pytest.fixture(scope='module') -async def erc20_init(contract_classes): - _, erc20_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc20 = await starknet.deploy( - contract_class=erc20_cls, - constructor_calldata=[ - NAME, - SYMBOL, - DECIMALS, - *INIT_SUPPLY, - account1.contract_address, # recipient - ] - ) - return ( - starknet.state, - account1, - account2, - erc20 - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc20_init): - account_cls, erc20_cls = contract_classes - state, account1, account2, erc20 = erc20_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc20 = cached_contract(_state, erc20_cls, erc20) - - return erc20, account1, account2 - - -class TestERC20Burnable(ERC20Base): - # - # burn - # - - @pytest.mark.asyncio - async def test_burn(self, contract_factory): - erc20, account, _ = contract_factory - - await signer.send_transaction( - account, erc20.contract_address, 'burn', [ - *AMOUNT - ]) - - new_balance = sub_uint(INIT_SUPPLY, AMOUNT) - - execution_info = await erc20.balanceOf(account.contract_address).execute() - assert execution_info.result.balance == new_balance - - - @pytest.mark.asyncio - async def test_burn_emits_event(self, contract_factory): - erc20, account, _ = contract_factory - - tx_exec_info = await signer.send_transaction( - account, erc20.contract_address, 'burn', [ - *AMOUNT - ]) - - assert_event_emitted( - tx_exec_info, - from_address=erc20.contract_address, - name='Transfer', - data=[ - account.contract_address, - ZERO_ADDRESS, - *AMOUNT - ] - ) - - - @pytest.mark.asyncio - async def test_burn_not_enough_balance(self, contract_factory): - erc20, account, _ = contract_factory - - balance_plus_one = add_uint(INIT_SUPPLY, UINT_ONE) - - await assert_revert(signer.send_transaction( - account, erc20.contract_address, 'burn', [ - *balance_plus_one - ]), - reverted_with="ERC20: burn amount exceeds balance" - ) - - - @pytest.mark.asyncio - async def test_burn_from_zero_address(self, contract_factory): - erc20, _, _ = contract_factory - - await assert_revert( - erc20.burn(UINT_ONE).execute(), - reverted_with="ERC20: cannot burn from the zero address" - ) - - - @pytest.mark.asyncio - async def test_burn_invalid_uint256(self, contract_factory): - erc20, _, _ = contract_factory - - await assert_revert( - erc20.burn(INVALID_UINT256).execute(), - reverted_with="ERC20: amount is not a valid Uint256" - ) - - - @pytest.mark.asyncio - async def test_burn_from(self, contract_factory): - erc20, account1, account2 = contract_factory - - await signer.send_transaction( - account1, erc20.contract_address, 'increaseAllowance', [ - account2.contract_address, - *AMOUNT - ]) - - await signer.send_transaction( - account2, erc20.contract_address, 'burnFrom', [ - account1.contract_address, - *AMOUNT - ]) - - new_balance = sub_uint(INIT_SUPPLY, AMOUNT) - - execution_info = await erc20.balanceOf(account1.contract_address).execute() - assert execution_info.result.balance == new_balance - - - @pytest.mark.asyncio - async def test_burn_from_emits_event(self, contract_factory): - erc20, account1, account2 = contract_factory - - await signer.send_transaction( - account1, erc20.contract_address, 'increaseAllowance', [ - account2.contract_address, - *AMOUNT - ]) - - tx_exec_info = await signer.send_transaction( - account2, erc20.contract_address, 'burnFrom', [ - account1.contract_address, - *AMOUNT - ]) - - # events - assert_events_emitted( - tx_exec_info, - [ - [0, erc20.contract_address, 'Approval', [ - account1.contract_address, account2.contract_address, *UINT_ZERO]], - [1, erc20.contract_address, 'Transfer', [ - account1.contract_address, ZERO_ADDRESS, *AMOUNT]] - ] - ) - - - @pytest.mark.asyncio - async def test_burn_from_over_allowance(self, contract_factory): - erc20, account1, account2 = contract_factory - - await signer.send_transaction( - account1, erc20.contract_address, 'increaseAllowance', [ - account2.contract_address, - *AMOUNT - ]) - - await assert_revert(signer.send_transaction( - account2, erc20.contract_address, 'burnFrom', [ - account1.contract_address, - *INIT_SUPPLY - ]), - reverted_with="ERC20: insufficient allowance" - ) - - - @pytest.mark.asyncio - async def test_burn_from_no_allowance(self, contract_factory): - erc20, account1, account2 = contract_factory - - await assert_revert(signer.send_transaction( - account2, erc20.contract_address, 'burnFrom', [ - account1.contract_address, - *AMOUNT - ]), - reverted_with="ERC20: insufficient allowance" - ) diff --git a/tests/token/erc20/test_ERC20Mintable.py b/tests/token/erc20/test_ERC20Mintable.py deleted file mode 100644 index efdd5c49d..000000000 --- a/tests/token/erc20/test_ERC20Mintable.py +++ /dev/null @@ -1,152 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import ( - add_uint, sub_uint, MAX_UINT256, ZERO_ADDRESS, INVALID_UINT256, assert_revert -) -from utils import ( - get_contract_class, cached_contract, assert_event_emitted, State, Account -) -from ERC20BaseSuite import ERC20Base, NAME, SYMBOL, DECIMALS, INIT_SUPPLY, UINT_ONE -from access.OwnableBaseSuite import OwnableBase - - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc20_cls = get_contract_class('ERC20Mintable') - - return account_cls, erc20_cls - - -@pytest.fixture(scope='module') -async def erc20_init(contract_classes): - account_cls, erc20_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc20 = await starknet.deploy( - contract_class=erc20_cls, - constructor_calldata=[ - NAME, - SYMBOL, - DECIMALS, - *INIT_SUPPLY, - account1.contract_address, # recipient - account1.contract_address # owner - ] - ) - return ( - starknet.state, - account1, - account2, - erc20, - ) - -@pytest.fixture -def contract_factory(contract_classes, erc20_init): - account_cls, erc20_cls = contract_classes - state, account1, account2, erc20 = erc20_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc20 = cached_contract(_state, erc20_cls, erc20) - - return erc20, account1, account2 - - -class TestERC20Mintable(ERC20Base, OwnableBase): - # - # mint - # - - @pytest.mark.asyncio - async def test_mint(self, contract_factory): - erc20, account, _ = contract_factory - - await signer.send_transaction( - account, erc20.contract_address, 'mint', [ - account.contract_address, - *UINT_ONE - ]) - - # check new supply - execution_info = await erc20.totalSupply().execute() - new_supply = execution_info.result.totalSupply - assert new_supply == add_uint(INIT_SUPPLY, UINT_ONE) - - - @pytest.mark.asyncio - async def test_mint_emits_event(self, contract_factory): - erc20, account, _ = contract_factory - - tx_exec_info = await signer.send_transaction( - account, erc20.contract_address, 'mint', [ - account.contract_address, - *UINT_ONE - ]) - - assert_event_emitted( - tx_exec_info, - from_address=erc20.contract_address, - name='Transfer', - data=[ - ZERO_ADDRESS, - account.contract_address, - *UINT_ONE - ] - ) - - - @pytest.mark.asyncio - async def test_mint_to_zero_address(self, contract_factory): - erc20, account, _ = contract_factory - - await assert_revert(signer.send_transaction( - account, - erc20.contract_address, - 'mint', - [ZERO_ADDRESS, *UINT_ONE] - ), - reverted_with="ERC20: cannot mint to the zero address" - ) - - - @pytest.mark.asyncio - async def test_mint_overflow(self, contract_factory): - erc20, account, recipient = contract_factory - # pass_amount subtracts the already minted supply from MAX_UINT256 in order for - # the minted supply to equal MAX_UINT256 - # (2**128 - 1, 2**128 - 1) - pass_amount = sub_uint(MAX_UINT256, INIT_SUPPLY) - - await signer.send_transaction( - account, erc20.contract_address, 'mint', [ - recipient.contract_address, - *pass_amount - ]) - - # totalSupply is MAX_UINT256 therefore adding (1, 0) should fail - await assert_revert( - signer.send_transaction( - account, erc20.contract_address, 'mint', [ - recipient.contract_address, - *UINT_ONE - ]), - reverted_with="ERC20: mint overflow" - ) - - - @pytest.mark.asyncio - async def test_mint_invalid_uint256(self, contract_factory): - erc20, account, recipient = contract_factory - - await assert_revert(signer.send_transaction( - account, - erc20.contract_address, - 'mint', - [recipient.contract_address, *INVALID_UINT256]), - reverted_with="ERC20: amount is not a valid Uint256" - ) diff --git a/tests/token/erc20/test_ERC20Pausable.py b/tests/token/erc20/test_ERC20Pausable.py deleted file mode 100644 index 3cb3c71e6..000000000 --- a/tests/token/erc20/test_ERC20Pausable.py +++ /dev/null @@ -1,194 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import TRUE, FALSE, assert_revert -from utils import ( - get_contract_class, cached_contract, State, Account -) -from ERC20BaseSuite import ERC20Base, NAME, SYMBOL, DECIMALS, INIT_SUPPLY, AMOUNT -from access.OwnableBaseSuite import OwnableBase - - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc20_cls = get_contract_class('ERC20Pausable') - - return account_cls, erc20_cls - - -@pytest.fixture(scope='module') -async def erc20_init(contract_classes): - _, erc20_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc20 = await starknet.deploy( - contract_class=erc20_cls, - constructor_calldata=[ - NAME, - SYMBOL, - DECIMALS, - *INIT_SUPPLY, - account1.contract_address, # recipient - account1.contract_address # owner - ] - ) - return ( - starknet.state, - account1, - account2, - erc20 - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc20_init): - account_cls, erc20_cls = contract_classes - state, account1, account2, erc20 = erc20_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc20 = cached_contract(_state, erc20_cls, erc20) - - return erc20, account1, account2 - - -class TestPausable(ERC20Base, OwnableBase): - # - # pause - # - - @pytest.mark.asyncio - async def test_constructor(self, contract_factory): - erc20, _, _ = contract_factory - - execution_info = await erc20.paused().execute() - assert execution_info.result.paused == FALSE - - - @pytest.mark.asyncio - async def test_pause(self, contract_factory): - erc20, owner, other = contract_factory - - await signer.send_transaction(owner, erc20.contract_address, 'pause', []) - - execution_info = await erc20.paused().execute() - assert execution_info.result.paused == TRUE - - await assert_revert(signer.send_transaction( - owner, - erc20.contract_address, - 'transfer', - [other.contract_address, *AMOUNT] - ), - reverted_with="Pausable: paused" - ) - - await assert_revert(signer.send_transaction( - owner, - erc20.contract_address, - 'transferFrom', - [other.contract_address, other.contract_address, *AMOUNT] - ), - reverted_with="Pausable: paused" - ) - - await assert_revert(signer.send_transaction( - owner, - erc20.contract_address, - 'approve', - [other.contract_address, *AMOUNT] - ), - reverted_with="Pausable: paused" - ) - - await assert_revert(signer.send_transaction( - owner, - erc20.contract_address, - 'increaseAllowance', - [other.contract_address, *AMOUNT] - ), - reverted_with="Pausable: paused" - ) - - await assert_revert(signer.send_transaction( - owner, - erc20.contract_address, - 'decreaseAllowance', - [other.contract_address, *AMOUNT] - ), - reverted_with="Pausable: paused" - ) - - - @pytest.mark.asyncio - async def test_unpause(self, contract_factory): - erc20, owner, other = contract_factory - - await signer.send_transaction(owner, erc20.contract_address, 'pause', []) - await signer.send_transaction(owner, erc20.contract_address, 'unpause', []) - - execution_info = await erc20.paused().execute() - assert execution_info.result.paused == FALSE - - success = await signer.send_transaction( - owner, - erc20.contract_address, - 'transfer', - [other.contract_address, *AMOUNT] - ) - assert success.call_info.retdata[1] == TRUE - - success = await signer.send_transaction( - owner, - erc20.contract_address, - 'approve', - [other.contract_address, *AMOUNT] - ) - assert success.call_info.retdata[1] == TRUE - - success = await signer.send_transaction( - other, - erc20.contract_address, - 'transferFrom', - [owner.contract_address, other.contract_address, *AMOUNT] - ) - assert success.call_info.retdata[1] == TRUE - - success = await signer.send_transaction( - owner, - erc20.contract_address, - 'increaseAllowance', - [other.contract_address, *AMOUNT] - ) - assert success.call_info.retdata[1] == TRUE - - success = await signer.send_transaction( - owner, - erc20.contract_address, - 'decreaseAllowance', - [other.contract_address, *AMOUNT] - ) - assert success.call_info.retdata[1] == TRUE - - - @pytest.mark.asyncio - async def test_only_owner(self, contract_factory): - erc20, _, other = contract_factory - - await assert_revert( - signer.send_transaction( - other, erc20.contract_address, 'pause', [] - ), - reverted_with="Ownable: caller is not the owner" - ) - - await assert_revert( - signer.send_transaction( - other, erc20.contract_address, 'unpause', [] - ), - reverted_with="Ownable: caller is not the owner" - ) diff --git a/tests/token/erc20/test_ERC20Upgradeable.py b/tests/token/erc20/test_ERC20Upgradeable.py deleted file mode 100644 index cf3713640..000000000 --- a/tests/token/erc20/test_ERC20Upgradeable.py +++ /dev/null @@ -1,179 +0,0 @@ -import pytest -from starkware.starknet.public.abi import get_selector_from_name -from signers import MockSigner -from nile.utils import to_uint, sub_uint, str_to_felt, assert_revert, TRUE -from utils import get_contract_class, cached_contract, State, Account - - -signer = MockSigner(123456789987654321) - -USER = 999 -INIT_SUPPLY = to_uint(1000) -AMOUNT = to_uint(250) -NAME = str_to_felt('Upgradeable Token') -SYMBOL = str_to_felt('UTKN') -DECIMALS = 18 - - -class TestERC20Upgradeable: - @pytest.fixture(scope='module') - def contract_classes(self): - account_cls = Account.get_class - token_cls = get_contract_class('ERC20Upgradeable') - proxy_cls = get_contract_class('Proxy') - - return account_cls, token_cls, proxy_cls - - - @pytest.fixture(scope='module') - async def token_init(self, contract_classes): - account_cls, token_cls, proxy_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - token_v1 = await starknet.declare( - contract_class=token_cls, - ) - token_v2 = await starknet.declare( - contract_class=token_cls, - ) - selector = get_selector_from_name('initializer') - params = [ - NAME, # name - SYMBOL, # symbol - DECIMALS, # decimals - *INIT_SUPPLY, # initial supply - account1.contract_address, # recipient - account1.contract_address # admin - ] - proxy = await starknet.deploy( - contract_class=proxy_cls, - constructor_calldata=[ - token_v1.class_hash, - selector, - len(params), - *params - ] - ) - return ( - starknet.state, - account1, - account2, - token_v1, - token_v2, - proxy - ) - - - @pytest.fixture - def token_factory(self, contract_classes, token_init): - account_cls, _, proxy_cls = contract_classes - state, account1, account2, token_v1, token_v2, proxy = token_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - proxy = cached_contract(_state, proxy_cls, proxy) - - return account1, account2, proxy, token_v1, token_v2 - - - @pytest.mark.asyncio - async def test_constructor(self, token_factory): - admin, _, proxy, *_ = token_factory - - execution_info = await signer.send_transactions( - admin, - [ - (proxy.contract_address, 'name', []), - (proxy.contract_address, 'symbol', []), - (proxy.contract_address, 'decimals', []), - (proxy.contract_address, 'totalSupply', []) - ] - ) - - # check values - expected = [5, NAME, SYMBOL, DECIMALS, *INIT_SUPPLY] - assert execution_info.call_info.retdata == expected - - - @pytest.mark.asyncio - async def test_upgrade(self, token_factory): - admin, _, proxy, _, token_v2 = token_factory - - # transfer - await signer.send_transaction( - admin, proxy.contract_address, 'transfer', [USER, *AMOUNT] - ) - - # upgrade - await signer.send_transaction( - admin, proxy.contract_address, 'upgrade', [token_v2.class_hash] - ) - - # fetch values - execution_info = await signer.send_transactions( - admin, - [ - (proxy.contract_address, 'balanceOf', [admin.contract_address]), - (proxy.contract_address, 'balanceOf', [USER]), - (proxy.contract_address, 'totalSupply', []) - ] - ) - - expected = [ - 6, # number of return values - *sub_uint(INIT_SUPPLY, AMOUNT), # balanceOf admin - *AMOUNT, # balanceOf USER - *INIT_SUPPLY # totalSupply - ] - - assert execution_info.call_info.retdata == expected - - - @pytest.mark.asyncio - async def test_upgrade_from_nonadmin(self, token_factory): - admin, non_admin, proxy, _, token_v2 = token_factory - - # should revert - await assert_revert(signer.send_transaction( - non_admin, proxy.contract_address, 'upgrade', [token_v2.class_hash]), - reverted_with="Proxy: caller is not admin" - ) - - # should upgrade from admin - await signer.send_transaction( - admin, proxy.contract_address, 'upgrade', [token_v2.class_hash] - ) - - - @pytest.mark.asyncio - async def test_upgrade_transferFrom(self, token_factory): - admin, non_admin, proxy, _, _ = token_factory - - # approve - await signer.send_transaction( - admin, proxy.contract_address, 'approve', [ - non_admin.contract_address, - *AMOUNT - ] - ) - - # transferFrom - return_bool = await signer.send_transaction( - non_admin, proxy.contract_address, 'transferFrom', [ - admin.contract_address, - non_admin.contract_address, - *AMOUNT - ] - ) - assert return_bool.call_info.retdata[1] == TRUE - - # should fail - await assert_revert(signer.send_transaction( - non_admin, proxy.contract_address, 'transferFrom', [ - admin.contract_address, - non_admin.contract_address, - *AMOUNT - ] - ) - ) diff --git a/tests/token/erc721/ERC721BaseSuite.py b/tests/token/erc721/ERC721BaseSuite.py deleted file mode 100644 index 551c00743..000000000 --- a/tests/token/erc721/ERC721BaseSuite.py +++ /dev/null @@ -1,924 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import ( - str_to_felt, ZERO_ADDRESS, TRUE, FALSE, assert_revert, INVALID_UINT256, - to_uint, sub_uint, add_uint -) -from utils import ( - assert_event_emitted, assert_events_emitted, -) - - -signer = MockSigner(123456789987654321) - -NAME = str_to_felt("Non-fungible Token") -SYMBOL = str_to_felt("NFT") -NONEXISTENT_TOKEN = to_uint(999) -# random token IDs -TOKENS = [to_uint(5042), to_uint(793)] -# test token -TOKEN = TOKENS[0] -# random user address -RECIPIENT = 555 -# random data (mimicking bytes in Solidity) -DATA = [0x42, 0x89, 0x55] -# random URIs -SAMPLE_URI_1 = str_to_felt('mock://mytoken.v1') -SAMPLE_URI_2 = str_to_felt('mock://mytoken.v2') - -# selector ids -IERC165_ID = 0x01ffc9a7 -IERC721_ID = 0x80ac58cd -IERC721_METADATA_ID = 0x5b5e139f -INVALID_ID = 0xffffffff -UNSUPPORTED_ID = 0xabcd1234 - - -class ERC721Base: - # - # constructor - # - - @pytest.mark.asyncio - async def test_constructor(self, contract_factory): - erc721, _, _, _, _ = contract_factory - execution_info = await erc721.name().execute() - assert execution_info.result == (NAME,) - - execution_info = await erc721.symbol().execute() - assert execution_info.result == (SYMBOL,) - # - # supportsInterface - # - - @pytest.mark.asyncio - @pytest.mark.parametrize('interface_id, result', [ - [IERC165_ID, TRUE], - [IERC721_ID, TRUE], - [IERC721_METADATA_ID, TRUE], - [INVALID_ID, FALSE], - [UNSUPPORTED_ID, FALSE], - ]) - async def test_supportsInterface(self, contract_factory, interface_id, result): - erc721, _, _, _, _ = contract_factory - - execution_info = await erc721.supportsInterface(interface_id).execute() - assert execution_info.result == (result,) - - - # - # balanceOf - # - - - @pytest.mark.asyncio - async def test_balanceOf(self, contract_factory): - erc721, account, _, _, _ = contract_factory - - # mint tokens to account - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *token] - ) - - execution_info = await erc721.balanceOf(account.contract_address).execute() - n_tokens = len(TOKENS) - assert execution_info.result == (to_uint(n_tokens),) - - # user should have zero tokens - execution_info = await erc721.balanceOf(RECIPIENT).execute() - assert execution_info.result == (to_uint(0),) - - - @pytest.mark.asyncio - async def test_balanceOf_zero_address(self, contract_factory): - erc721, account, _, _, _ = contract_factory - - # mint tokens to account - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *TOKEN] - ) - - # should revert when querying zero address - await assert_revert( - erc721.balanceOf(ZERO_ADDRESS).execute(), - reverted_with="ERC721: balance query for the zero address" - ) - - - # - # ownerOf - # - - - @pytest.mark.asyncio - async def test_ownerOf(self, contract_factory): - erc721, account, _, _, _ = contract_factory - - # mint tokens to account - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *token] - ) - - # should return account's address - execution_info = await erc721.ownerOf(token).execute() - assert execution_info.result == (account.contract_address,) - - - @pytest.mark.asyncio - async def test_ownerOf_nonexistent_token(self, contract_factory): - erc721, account, _, _, _ = contract_factory - - # mint token to account - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *TOKEN] - ) - - # should revert when querying nonexistent token - await assert_revert( - erc721.ownerOf(NONEXISTENT_TOKEN).execute(), - reverted_with="ERC721: owner query for nonexistent token" - ) - - - @pytest.mark.asyncio - async def test_ownerOf_invalid_uint256(self, contract_factory): - erc721, _, _, _, _ = contract_factory - - # should revert when querying nonexistent token - await assert_revert( - erc721.ownerOf(INVALID_UINT256).execute(), - reverted_with="ERC721: token_id is not a valid Uint256" - ) - - - # - # approve - # - - - @pytest.mark.asyncio - async def test_approve(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - await signer.send_transaction( - account, erc721.contract_address, 'approve', [ - spender.contract_address, *TOKEN] - ) - - execution_info = await erc721.getApproved(TOKEN).execute() - assert execution_info.result == (spender.contract_address,) - - - @pytest.mark.asyncio - async def test_approve_emits_event(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - # mint token to account - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'approve', [ - spender.contract_address, - *TOKEN - ] - ) - - assert_event_emitted( - tx_exec_info, - from_address=erc721.contract_address, - name='Approval', - data=[ - account.contract_address, - spender.contract_address, - *TOKEN - ] - ) - - - @pytest.mark.asyncio - async def test_approve_on_setApprovalForAll(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - # set approval_for_all from account to spender - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, TRUE] - ) - - # approve spender to spend account's token to recipient - await signer.send_transaction( - spender, erc721.contract_address, 'approve', [ - RECIPIENT, *TOKEN] - ) - - execution_info = await erc721.getApproved(TOKEN).execute() - assert execution_info.result == (RECIPIENT,) - - - @pytest.mark.asyncio - async def test_approve_from_zero_address(self, erc721_minted): - erc721, _, spender, *_ = erc721_minted - - # Without using an account abstraction, the caller address - # (get_caller_address) is zero - await assert_revert( - erc721.approve( - spender.contract_address, TOKEN).execute(), - reverted_with="ERC721: cannot approve from the zero address" - ) - - - @pytest.mark.asyncio - async def test_approve_owner_is_recipient(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # should fail when owner is the same as address-to-be-approved - await assert_revert( - signer.send_transaction( - account, erc721.contract_address, 'approve', [ - account.contract_address, - *TOKEN - ]), - reverted_with="ERC721: approval to current owner" - ) - - - @pytest.mark.asyncio - async def test_approve_not_owner_or_operator(self, contract_factory): - erc721, account, spender, _, _ = contract_factory - - # mint to recipient — NOT account - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - RECIPIENT, *TOKEN] - ) - - # 'approve' should fail since recipient owns token - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'approve', [ - spender.contract_address, - *TOKEN - ]), - reverted_with="ERC721: approve caller is not owner nor approved for all" - ) - - - @pytest.mark.asyncio - async def test_approve_on_already_approved(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - # first approval - await signer.send_transaction( - account, erc721.contract_address, 'approve', [ - spender.contract_address, *TOKEN] - ) - - # repeat approval - await signer.send_transaction( - account, erc721.contract_address, 'approve', [ - spender.contract_address, *TOKEN] - ) - - # check that approval does not change - execution_info = await erc721.getApproved(TOKEN).execute() - assert execution_info.result == (spender.contract_address,) - - - @pytest.mark.asyncio - async def test_getApproved_nonexistent_token(self, erc721_minted): - erc721, *_ = erc721_minted - - await assert_revert( - erc721.getApproved(NONEXISTENT_TOKEN).execute(), - reverted_with="ERC721: approved query for nonexistent token" - ) - - - @pytest.mark.asyncio - async def test_getApproved_invalid_uint256(self, erc721_minted): - erc721, *_ = erc721_minted - - await assert_revert( - erc721.getApproved(INVALID_UINT256).execute(), - reverted_with="ERC721: token_id is not a valid Uint256" - ) - - - # - # setApprovalForAll - # - - - @pytest.mark.asyncio - async def test_setApprovalForAll(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, TRUE] - ) - - execution_info = await erc721.isApprovedForAll( - account.contract_address, spender.contract_address).execute() - assert execution_info.result == (TRUE,) - - - @pytest.mark.asyncio - async def test_setApprovalForAll_emits_event(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, TRUE] - ) - - assert_event_emitted( - tx_exec_info, - from_address=erc721.contract_address, - name='ApprovalForAll', - data=[ - account.contract_address, - spender.contract_address, - TRUE - ] - ) - - - @pytest.mark.asyncio - async def test_setApprovalForAll_when_operator_was_set_as_not_approved(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, FALSE] - ) - - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, TRUE] - ) - - execution_info = await erc721.isApprovedForAll( - account.contract_address, spender.contract_address).execute() - assert execution_info.result == (TRUE,) - - - @pytest.mark.asyncio - async def test_setApprovalForAll_with_invalid_bool_arg(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - not_bool = 2 - - await assert_revert( - signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, - not_bool - ]), - reverted_with="ERC721: approved is not a Cairo boolean") - - - @pytest.mark.asyncio - async def test_setApprovalForAll_owner_is_operator(self, erc721_minted): - erc721, account, *_ = erc721_minted - - await assert_revert( - signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - account.contract_address, - TRUE - ]), - reverted_with="ERC721: approve to caller" - ) - - - @pytest.mark.asyncio - async def test_setApprovalForAll_from_zero_address(self, erc721_minted): - erc721, account, *_ = erc721_minted - - await assert_revert( - erc721.setApprovalForAll(account.contract_address, TRUE).execute(), - reverted_with="ERC721: either the caller or operator is the zero address" - ) - - - @pytest.mark.asyncio - async def test_setApprovalForAll_operator_is_zero_address(self, erc721_minted): - erc721, account, *_ = erc721_minted - - await assert_revert( - signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - ZERO_ADDRESS, - TRUE - ]), - reverted_with="ERC721: either the caller or operator is the zero address" - ) - - - # - # transferFrom - # - - - @pytest.mark.asyncio - async def test_transferFrom_owner(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # get account's previous balance - execution_info = await erc721.balanceOf(account.contract_address).execute() - previous_balance = execution_info.result.balance - - # transfers token from account to recipient - await signer.send_transaction( - account, erc721.contract_address, 'transferFrom', [ - account.contract_address, RECIPIENT, *TOKEN] - ) - - # checks recipient balance - execution_info = await erc721.balanceOf(RECIPIENT).execute() - assert execution_info.result == (to_uint(1),) - - # checks account balance - execution_info = await erc721.balanceOf(account.contract_address).execute() - assert execution_info.result.balance == sub_uint( - previous_balance, to_uint(1)) - - # checks token has new owner - execution_info = await erc721.ownerOf(TOKEN).execute() - assert execution_info.result == (RECIPIENT,) - - # checks approval is cleared for token_id - execution_info = await erc721.getApproved(TOKEN).execute() - assert execution_info.result == (0,) - - - @pytest.mark.asyncio - async def test_transferFrom_emits_events(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - # setApprovalForAll - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, TRUE] - ) - - # spender transfers token from account to recipient - tx_exec_info = await signer.send_transaction( - spender, erc721.contract_address, 'transferFrom', [ - account.contract_address, - RECIPIENT, - *TOKEN - ] - ) - - # events - assert_events_emitted( - tx_exec_info, - [ - [0, erc721.contract_address, 'Approval', [ - account.contract_address, ZERO_ADDRESS, *TOKEN]], - [1, erc721.contract_address, 'Transfer', [ - account.contract_address, RECIPIENT, *TOKEN]] - ] - ) - - - @pytest.mark.asyncio - async def test_transferFrom_approved_user(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - # approve spender - await signer.send_transaction( - account, erc721.contract_address, 'approve', [ - spender.contract_address, *TOKEN] - ) - - # spender transfers token from account to recipient - await signer.send_transaction( - spender, erc721.contract_address, 'transferFrom', [ - account.contract_address, RECIPIENT, *TOKEN] - ) - - # checks user balance - execution_info = await erc721.balanceOf(RECIPIENT).execute() - assert execution_info.result == (to_uint(1),) - - - @pytest.mark.asyncio - async def test_transferFrom_operator(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - # setApprovalForAll - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, TRUE] - ) - - # spender transfers token from account to recipient - await signer.send_transaction( - spender, erc721.contract_address, 'transferFrom', [ - account.contract_address, RECIPIENT, *TOKEN] - ) - - # checks user balance - execution_info = await erc721.balanceOf(RECIPIENT).execute() - assert execution_info.result == (to_uint(1),) - - - @pytest.mark.asyncio - async def test_transferFrom_when_not_approved_or_owner(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - # setApprovalForAll to false - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, FALSE] - ) - - # should be rejected when not approved - await assert_revert(signer.send_transaction( - spender, erc721.contract_address, 'transferFrom', [ - account.contract_address, - RECIPIENT, - *TOKEN - ]), - reverted_with="ERC721: either is not approved or the caller is the zero address" - ) - - - @pytest.mark.asyncio - async def test_transferFrom_to_zero_address(self, erc721_minted): - erc721, account, spender, *_ = erc721_minted - - # setApprovalForAll - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, TRUE] - ) - - try: - # erc721 - await assert_revert(signer.send_transaction( - spender, erc721.contract_address, 'transferFrom', [ - account.contract_address, - ZERO_ADDRESS, - *TOKEN - ]), - reverted_with="ERC721: cannot transfer to the zero address" - ) - except AssertionError: - # erc721 enumerable - await assert_revert(signer.send_transaction( - spender, erc721.contract_address, 'transferFrom', [ - account.contract_address, - ZERO_ADDRESS, - *TOKEN - ]), - reverted_with="ERC721: balance query for the zero address" - ) - - - @pytest.mark.asyncio - async def test_transferFrom_invalid_uint256(self, erc721_minted): - erc721, account, *_ = erc721_minted - - await assert_revert( - signer.send_transaction( - account, erc721.contract_address, 'transferFrom', [ - account.contract_address, - RECIPIENT, - *INVALID_UINT256 - ]), - reverted_with="ERC721: token_id is not a valid Uint256" - ) - - - @pytest.mark.asyncio - async def test_transferFrom_from_zero_address(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # caller address is `0` when not using an account contract - await assert_revert( - erc721.transferFrom( - account.contract_address, - RECIPIENT, - TOKEN - ).execute(), - reverted_with="ERC721: either is not approved or the caller is the zero address" - ) - - - # - # safeTransferFrom - # - - - @pytest.mark.asyncio - async def test_safeTransferFrom(self, erc721_minted): - erc721, account, _, erc721_holder, _ = erc721_minted - - await signer.send_transaction( - account, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - erc721_holder.contract_address, - *TOKEN, - len(DATA), - *DATA - ] - ) - - # check balance - execution_info = await erc721.balanceOf(erc721_holder.contract_address).execute() - assert execution_info.result == (to_uint(1),) - - # check owner - execution_info = await erc721.ownerOf(TOKEN).execute() - assert execution_info.result == (erc721_holder.contract_address,) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_emits_events(self, erc721_minted): - erc721, account, _, erc721_holder, _ = erc721_minted - - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - erc721_holder.contract_address, - *TOKEN, - len(DATA), - *DATA - ] - ) - - - # events - assert_events_emitted( - tx_exec_info, - [ - [0, erc721.contract_address, 'Approval', [ - account.contract_address, ZERO_ADDRESS, *TOKEN]], - [1, erc721.contract_address, 'Transfer', [ - account.contract_address, erc721_holder.contract_address, *TOKEN]] - ] - ) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_from_approved(self, erc721_minted): - erc721, account, spender, erc721_holder, _ = erc721_minted - - execution_info = await erc721.balanceOf(erc721_holder.contract_address).execute() - previous_balance = execution_info.result.balance - - # approve spender - await signer.send_transaction( - account, erc721.contract_address, 'approve', [ - spender.contract_address, *TOKEN] - ) - - # spender transfers token from account to erc721_holder - await signer.send_transaction( - spender, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - erc721_holder.contract_address, - *TOKEN, - len(DATA), - *DATA - ] - ) - - # erc721_holder balance check - execution_info = await erc721.balanceOf(erc721_holder.contract_address).execute() - assert execution_info.result.balance == add_uint( - previous_balance, to_uint(1) - ) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_from_operator(self, erc721_minted): - erc721, account, spender, erc721_holder, _ = erc721_minted - - execution_info = await erc721.balanceOf(erc721_holder.contract_address).execute() - previous_balance = execution_info.result.balance - - # setApprovalForAll - await signer.send_transaction( - account, erc721.contract_address, 'setApprovalForAll', [ - spender.contract_address, TRUE] - ) - - # spender transfers token from account to erc721_holder - await signer.send_transaction( - spender, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - erc721_holder.contract_address, - *TOKEN, - len(DATA), - *DATA - ] - ) - - # erc721_holder balance check - execution_info = await erc721.balanceOf(erc721_holder.contract_address).execute() - assert execution_info.result.balance == add_uint( - previous_balance, to_uint(1) - ) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_when_not_approved_or_owner(self, erc721_minted): - erc721, account, spender, erc721_holder, _ = erc721_minted - - # should fail when not approved or owner - await assert_revert(signer.send_transaction( - spender, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - erc721_holder.contract_address, - *TOKEN, - len(DATA), - *DATA - ]), - reverted_with="ERC721: either is not approved or the caller is the zero address" - ) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_to_zero_address(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # to zero address should be rejected - try: - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - ZERO_ADDRESS, - *TOKEN, - len(DATA), - *DATA - ]), - reverted_with="ERC721: cannot transfer to the zero address" - ) - except AssertionError: - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - ZERO_ADDRESS, - *TOKEN, - len(DATA), - *DATA - ]), - reverted_with="ERC721: balance query for the zero address" - ) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_from_zero_address(self, erc721_minted): - erc721, account, _, erc721_holder, _ = erc721_minted - - # caller address is `0` when not using an account contract - await assert_revert( - erc721.safeTransferFrom( - account.contract_address, - erc721_holder.contract_address, - TOKEN, - DATA - ).execute(), - reverted_with="ERC721: either is not approved or the caller is the zero address" - ) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_to_unsupported_contract(self, erc721_minted): - erc721, account, _, _, unsupported = erc721_minted - - await assert_revert( - signer.send_transaction( - account, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - unsupported.contract_address, - *TOKEN, - len(DATA), - *DATA, - ]) - ) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_to_account(self, erc721_minted): - erc721, account, account2, *_ = erc721_minted - - await signer.send_transaction( - account, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - account2.contract_address, - *TOKEN, - len(DATA), - *DATA - ] - ) - - # check balance - execution_info = await erc721.balanceOf(account2.contract_address).execute() - assert execution_info.result == (to_uint(1),) - - # check owner - execution_info = await erc721.ownerOf(TOKEN).execute() - assert execution_info.result == (account2.contract_address,) - - - @pytest.mark.asyncio - async def test_safeTransferFrom_invalid_uint256(self, erc721_minted): - erc721, account, _, erc721_holder, _ = erc721_minted - - await assert_revert( - signer.send_transaction( - account, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - erc721_holder.contract_address, - *INVALID_UINT256, - len(DATA), - *DATA - ]), - reverted_with="ERC721: token_id is not a valid Uint256" - ) - - - # - # tokenURI - # - - - @pytest.mark.asyncio - async def test_tokenURI(self, erc721_minted): - erc721, account, *_ = erc721_minted - - token_1 = TOKENS[0] - token_2 = TOKENS[1] - - # should be zero when tokenURI is not set - execution_info = await erc721.tokenURI(token_1).execute() - assert execution_info.result == (0,) - - # setTokenURI for token_1 - await signer.send_transaction( - account, erc721.contract_address, 'setTokenURI', [ - *token_1, - SAMPLE_URI_1 - ] - ) - - execution_info = await erc721.tokenURI(token_1).execute() - assert execution_info.result == (SAMPLE_URI_1,) - - # setTokenURI for token_2 - await signer.send_transaction( - account, erc721.contract_address, 'setTokenURI', [ - *token_2, - SAMPLE_URI_2 - ] - ) - - execution_info = await erc721.tokenURI(token_2).execute() - assert execution_info.result == (SAMPLE_URI_2,) - - - @pytest.mark.asyncio - async def test_tokenURI_should_revert_for_nonexistent_token(self, erc721_minted): - erc721, *_ = erc721_minted - - # should revert for nonexistent token - await assert_revert( - erc721.tokenURI(NONEXISTENT_TOKEN).execute(), - reverted_with="ERC721_Metadata: URI query for nonexistent token" - ) - - - @pytest.mark.asyncio - async def test_setTokenURI_from_not_owner(self, erc721_minted): - erc721, _, not_owner, *_ = erc721_minted - - await assert_revert(signer.send_transaction( - not_owner, erc721.contract_address, 'setTokenURI', [ - *TOKEN, - SAMPLE_URI_1 - ]), - reverted_with="Ownable: caller is not the owner" - ) - - - @pytest.mark.asyncio - async def test_setTokenURI_for_nonexistent_token(self, erc721_minted): - erc721, account, *_ = erc721_minted - - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'setTokenURI', [ - *NONEXISTENT_TOKEN, - SAMPLE_URI_1 - ]), - reverted_with="ERC721_Metadata: set token URI for nonexistent token" - ) diff --git a/tests/token/erc721/test_ERC721EnumerableMintableBurnable.py b/tests/token/erc721/test_ERC721EnumerableMintableBurnable.py deleted file mode 100644 index 5ee789508..000000000 --- a/tests/token/erc721/test_ERC721EnumerableMintableBurnable.py +++ /dev/null @@ -1,514 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import ( - MAX_UINT256, ZERO_ADDRESS, TRUE, assert_revert, to_uint, sub_uint, add_uint -) -from utils import ( - get_contract_class, cached_contract, assert_event_emitted, - assert_events_emitted, State, Account -) -from ERC721BaseSuite import ( - ERC721Base, NAME, SYMBOL, NONEXISTENT_TOKEN, DATA, RECIPIENT -) -from access.OwnableBaseSuite import OwnableBase - - -signer = MockSigner(123456789987654321) - - -# random token IDs -TOKENS = [ - to_uint(5042), to_uint(793), to_uint(321), MAX_UINT256, to_uint(8) -] -TOKEN = TOKENS[0] -# total tokens as uint -TOTAL_TOKENS = to_uint(len(TOKENS)) -# selector id -ENUMERABLE_INTERFACE_ID = 0x780e9d63 - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc721_cls = get_contract_class('ERC721EnumerableMintableBurnable') - erc721_holder_cls = get_contract_class('ERC721Holder') - unsupported_cls = get_contract_class('Initializable') - - return account_cls, erc721_cls, erc721_holder_cls, unsupported_cls - - -@pytest.fixture(scope='module') -async def erc721_init(contract_classes): - account_cls, erc721_cls, erc721_holder_cls, unsupported_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc721 = await starknet.deploy( - contract_class=erc721_cls, - constructor_calldata=[ - NAME, # name - SYMBOL, # symbol - account1.contract_address # owner - ] - ) - erc721_holder = await starknet.deploy( - contract_class=erc721_holder_cls, - constructor_calldata=[] - ) - unsupported = await starknet.deploy( - contract_class=unsupported_cls, - constructor_calldata=[] - ) - return ( - starknet.state, - account1, - account2, - erc721, - erc721_holder, - unsupported, - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc721_init): - account_cls, erc721_cls, erc721_holder_cls, unsupported_cls = contract_classes - state, account1, account2, erc721, erc721_holder, unsupported = erc721_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc721 = cached_contract(_state, erc721_cls, erc721) - erc721_holder = cached_contract(_state, erc721_holder_cls, erc721_holder) - unsupported = cached_contract(_state, unsupported_cls, unsupported) - - return erc721, account1, account2, erc721_holder, unsupported - - -@pytest.fixture -async def erc721_minted(contract_factory): - erc721, account, account2, erc721_holder, unsupported = contract_factory - # mint tokens to account - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *token] - ) - - return erc721, account, account2, erc721_holder, unsupported - - -class TestERC721EnumerableMintableBurnable(ERC721Base, OwnableBase): - # - # supportsInterface - # - - @pytest.mark.asyncio - async def test_supportsInterface(self, contract_factory): - erc721, *_ = contract_factory - - execution_info = await erc721.supportsInterface(ENUMERABLE_INTERFACE_ID).execute() - assert execution_info.result == (TRUE,) - - # - # totalSupply - # - - @pytest.mark.asyncio - async def test_totalSupply(self, erc721_minted): - erc721, *_ = erc721_minted - - execution_info = await erc721.totalSupply().execute() - assert execution_info.result == (TOTAL_TOKENS,) - - - # - # tokenOfOwnerByIndex - # - - - @pytest.mark.asyncio - async def test_tokenOfOwnerByIndex(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # check index - for i in range(0, len(TOKENS)): - execution_info = await erc721.tokenOfOwnerByIndex( - account.contract_address, to_uint(i)).execute() - assert execution_info.result == (TOKENS[i],) - - - @pytest.mark.asyncio - async def test_tokenOfOwnerByIndex_greater_than_supply(self, erc721_minted): - erc721, account, *_ = erc721_minted - - tokens_plus_one = add_uint(TOTAL_TOKENS, to_uint(1)) - - await assert_revert( - erc721.tokenOfOwnerByIndex( - account.contract_address, tokens_plus_one).execute(), - reverted_with="ERC721Enumerable: owner index out of bounds" - ) - - - @pytest.mark.asyncio - async def test_tokenOfOwnerByIndex_owner_with_no_tokens(self, erc721_minted): - erc721, *_ = erc721_minted - - await assert_revert( - erc721.tokenOfOwnerByIndex(RECIPIENT, to_uint(1)).execute(), - reverted_with="ERC721Enumerable: owner index out of bounds" - ) - - - @pytest.mark.asyncio - async def test_tokenOfOwnerByIndex_transfer_all_tokens(self, erc721_minted): - erc721, account, other, *_ = erc721_minted - - # transfer all tokens - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'transferFrom', [ - account.contract_address, - other.contract_address, - *token - ] - ) - - execution_info = await erc721.balanceOf(other.contract_address).execute() - assert execution_info.result == (TOTAL_TOKENS,) - - for i in range(0, len(TOKENS)): - execution_info = await erc721.tokenOfOwnerByIndex(other.contract_address, to_uint(i)).execute() - assert execution_info.result == (TOKENS[i],) - - execution_info = await erc721.balanceOf(account.contract_address).execute() - assert execution_info.result == (to_uint(0),) - - # check that queries to old owner's token ownership reverts since index is less - # than the target's balance - await assert_revert(erc721.tokenOfOwnerByIndex( - account.contract_address, to_uint(0)).execute(), - reverted_with="ERC721Enumerable: owner index out of bounds" - ) - - - @pytest.mark.asyncio - async def test_tokenOfOwnerByIndex_safe_transfer_all_tokens(self, erc721_minted): - erc721, account, other, *_ = erc721_minted - - # safe transfer all tokens - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'safeTransferFrom', [ - account.contract_address, - other.contract_address, - *token, - len(DATA), - *DATA - ] - ) - - execution_info = await erc721.balanceOf(other.contract_address).execute() - assert execution_info.result == (TOTAL_TOKENS,) - - for i in range(0, len(TOKENS)): - execution_info = await erc721.tokenOfOwnerByIndex(other.contract_address, to_uint(i)).execute() - assert execution_info.result == (TOKENS[i],) - - execution_info = await erc721.balanceOf(account.contract_address).execute() - assert execution_info.result == (to_uint(0),) - - # check that queries to old owner's token ownership reverts since index is less - # than the target's balance - await assert_revert(erc721.tokenOfOwnerByIndex( - account.contract_address, to_uint(0)).execute(), - reverted_with="ERC721Enumerable: owner index out of bounds" - ) - - - # - # tokenByIndex - # - - - @pytest.mark.asyncio - async def test_tokenByIndex(self, erc721_minted): - erc721, *_ = erc721_minted - - for i in range(0, len(TOKENS)): - execution_info = await erc721.tokenByIndex(to_uint(i)).execute() - assert execution_info.result == (TOKENS[i],) - - - @pytest.mark.asyncio - async def test_tokenByIndex_greater_than_supply(self, erc721_minted): - erc721, *_ = erc721_minted - - await assert_revert( - erc721.tokenByIndex(to_uint(5)).execute(), - reverted_with="ERC721Enumerable: global index out of bounds" - ) - - - @pytest.mark.asyncio - async def test_tokenByIndex_burn_last_token(self, erc721_minted): - erc721, account, *_ = erc721_minted - - tokens_minus_one = sub_uint(TOTAL_TOKENS, to_uint(1)) - - # burn last token - await signer.send_transaction( - account, erc721.contract_address, 'burn', [ - *TOKENS[4]] - ) - - execution_info = await erc721.totalSupply().execute() - assert execution_info.result == (tokens_minus_one,) - - for i in range(0, 4): - execution_info = await erc721.tokenByIndex(to_uint(i)).execute() - assert execution_info.result == (TOKENS[i],) - - await assert_revert( - erc721.tokenByIndex(tokens_minus_one).execute(), - reverted_with="ERC721Enumerable: global index out of bounds" - ) - - - @pytest.mark.asyncio - async def test_tokenByIndex_burn_first_token(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # burn first token - await signer.send_transaction( - account, erc721.contract_address, 'burn', [ - *TOKENS[0]] - ) - - # TOKEN[0] should be burnt and TOKEN[4] should be swapped - # to TOKEN[0]'s index - new_token_order = [TOKENS[4], TOKENS[1], TOKENS[2], TOKENS[3]] - for i in range(0, 3): - execution_info = await erc721.tokenByIndex(to_uint(i)).execute() - assert execution_info.result == (new_token_order[i],) - - - @pytest.mark.asyncio - async def test_tokenByIndex_burn_and_mint(self, erc721_minted): - erc721, account, *_ = erc721_minted - - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'burn', [ - *token] - ) - - execution_info = await erc721.totalSupply().execute() - assert execution_info.result == (to_uint(0),) - - await assert_revert( - erc721.tokenByIndex(to_uint(0)).execute(), - reverted_with="ERC721Enumerable: global index out of bounds" - ) - - # mint new tokens - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *token] - ) - - for i in range(0, len(TOKENS)): - execution_info = await erc721.tokenByIndex(to_uint(i)).execute() - assert execution_info.result == (TOKENS[i],) - - # - # mint - # - - @pytest.mark.asyncio - async def test_mint_emits_event(self, contract_factory): - erc721, account, _, _, _ = contract_factory - - # mint token to account - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *TOKEN] - ) - - assert_event_emitted( - tx_exec_info, - from_address=erc721.contract_address, - name='Transfer', - data=[ - ZERO_ADDRESS, - account.contract_address, - *TOKEN - ] - ) - - - @pytest.mark.asyncio - async def test_mint(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # checks balance - execution_info = await erc721.balanceOf(account.contract_address).execute() - assert execution_info.result == (to_uint(5),) - - # checks that account owns correct tokens - for token in TOKENS: - execution_info = await erc721.ownerOf(token).execute() - assert execution_info.result == (account.contract_address,) - - - @pytest.mark.asyncio - async def test_mint_duplicate_token_id(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # minting duplicate token_id should fail - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, - *TOKEN - ]), - reverted_with="ERC721: token already minted" - ) - - - @pytest.mark.asyncio - async def test_mint_to_zero_address(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # minting to zero address should fail - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'mint', [ - ZERO_ADDRESS, - *NONEXISTENT_TOKEN - ]), - reverted_with="ERC721: balance query for the zero address" - ) - - - @pytest.mark.asyncio - async def test_mint_approve_should_be_zero_address(self, erc721_minted): - erc721, *_ = erc721_minted - - # approved address should be zero for newly minted tokens - for token in TOKENS: - execution_info = await erc721.getApproved(token).execute() - assert execution_info.result == (0,) - - - @pytest.mark.asyncio - async def test_mint_by_not_owner(self, contract_factory): - erc721, _, not_owner, _, _ = contract_factory - - # minting from not_owner should fail - await assert_revert(signer.send_transaction( - not_owner, erc721.contract_address, 'mint', [ - not_owner.contract_address, - *TOKENS[0] - ]), - reverted_with="Ownable: caller is not the owner" - ) - - - # - # burn - # - - - @pytest.mark.asyncio - async def test_burn(self, erc721_minted): - erc721, account, *_ = erc721_minted - - execution_info = await erc721.balanceOf(account.contract_address).execute() - previous_balance = execution_info.result.balance - - # burn token - await signer.send_transaction( - account, erc721.contract_address, 'burn', [*TOKEN] - ) - - # account balance should subtract one - execution_info = await erc721.balanceOf(account.contract_address).execute() - assert execution_info.result.balance == sub_uint( - previous_balance, to_uint(1) - ) - - # approve should be cleared to zero, therefore, - # 'getApproved()' call should fail - await assert_revert( - erc721.getApproved(TOKEN).execute(), - reverted_with="ERC721: approved query for nonexistent token" - ) - - # 'token_to_burn' owner should be zero; therefore, - # 'ownerOf()' call should fail - await assert_revert( - erc721.ownerOf(TOKEN).execute(), - reverted_with="ERC721: owner query for nonexistent token" - ) - - - @pytest.mark.asyncio - async def test_burn_emits_event(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # mint token to account - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'burn', [ - *TOKEN - ] - ) - - # events - assert_events_emitted( - tx_exec_info, - [ - [0, erc721.contract_address, 'Approval', [ - account.contract_address, ZERO_ADDRESS, *TOKEN]], - [1, erc721.contract_address, 'Transfer', [ - account.contract_address, ZERO_ADDRESS, *TOKEN]] - ] - ) - - - @pytest.mark.asyncio - async def test_burn_nonexistent_token(self, erc721_minted): - erc721, account, *_ = erc721_minted - - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'burn', [ - *NONEXISTENT_TOKEN - ]), - reverted_with="ERC721: owner query for nonexistent token" - ) - - - @pytest.mark.asyncio - async def test_burn_unowned_token(self, erc721_minted): - erc721, account, other, *_ = erc721_minted - - # other should not be able to burn account's token - await assert_revert( - signer.send_transaction( - other, erc721.contract_address, 'burn', [*TOKEN] - ), - reverted_with="ERC721: caller is not the token owner" - ) - - # account can burn their own token - await signer.send_transaction( - account, erc721.contract_address, 'burn', [*TOKEN] - ) - - - @pytest.mark.asyncio - async def test_burn_from_zero_address(self, erc721_minted): - erc721, *_ = erc721_minted - - await assert_revert( - erc721.burn(TOKEN).execute(), - reverted_with="ERC721: caller is not the token owner" - ) diff --git a/tests/token/erc721/test_ERC721MintableBurnable.py b/tests/token/erc721/test_ERC721MintableBurnable.py deleted file mode 100644 index d14251be4..000000000 --- a/tests/token/erc721/test_ERC721MintableBurnable.py +++ /dev/null @@ -1,279 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import ZERO_ADDRESS, assert_revert, to_uint, sub_uint -from utils import ( - get_contract_class, cached_contract, assert_event_emitted, - assert_events_emitted, State, Account -) -from ERC721BaseSuite import ( - ERC721Base, NAME, SYMBOL, NONEXISTENT_TOKEN, TOKENS, TOKEN -) -from access.OwnableBaseSuite import OwnableBase - - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc721_cls = get_contract_class('ERC721MintableBurnable') - erc721_holder_cls = get_contract_class('ERC721Holder') - unsupported_cls = get_contract_class('Initializable') - - return account_cls, erc721_cls, erc721_holder_cls, unsupported_cls - - -@pytest.fixture(scope='module') -async def erc721_init(contract_classes): - _, erc721_cls, erc721_holder_cls, unsupported_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc721 = await starknet.deploy( - contract_class=erc721_cls, - constructor_calldata=[ - NAME, # name - SYMBOL, # symbol - account1.contract_address # owner - ] - ) - erc721_holder = await starknet.deploy( - contract_class=erc721_holder_cls, - constructor_calldata=[] - ) - unsupported = await starknet.deploy( - contract_class=unsupported_cls, - constructor_calldata=[] - ) - return ( - starknet.state, - account1, - account2, - erc721, - erc721_holder, - unsupported - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc721_init): - account_cls, erc721_cls, erc721_holder_cls, unsupported_cls = contract_classes - state, account1, account2, erc721, erc721_holder, unsupported = erc721_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc721 = cached_contract(_state, erc721_cls, erc721) - erc721_holder = cached_contract(_state, erc721_holder_cls, erc721_holder) - unsupported = cached_contract(_state, unsupported_cls, unsupported) - - return erc721, account1, account2, erc721_holder, unsupported - - -# Note that depending on what's being tested, test cases alternate between -# accepting `erc721_minted` and `contract_factory` fixtures -@pytest.fixture -async def erc721_minted(contract_factory): - erc721, account, account2, erc721_holder, unsupported = contract_factory - # mint tokens to account - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *token] - ) - - return erc721, account, account2, erc721_holder, unsupported - - -class TestERC721MintableBurnable(ERC721Base, OwnableBase): - # - # mint - # - - @pytest.mark.asyncio - async def test_mint_emits_event(self, contract_factory): - erc721, account, _, _, _ = contract_factory - - # mint token to account - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *TOKEN] - ) - - assert_event_emitted( - tx_exec_info, - from_address=erc721.contract_address, - name='Transfer', - data=[ - ZERO_ADDRESS, - account.contract_address, - *TOKEN - ] - ) - - - @pytest.mark.asyncio - async def test_mint(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # checks balance - execution_info = await erc721.balanceOf(account.contract_address).execute() - assert execution_info.result == (to_uint(2),) - - # checks that account owns correct tokens - for token in TOKENS: - execution_info = await erc721.ownerOf(token).execute() - assert execution_info.result == (account.contract_address,) - - - @pytest.mark.asyncio - async def test_mint_duplicate_token_id(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # minting duplicate token_id should fail - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, - *TOKEN - ]), - reverted_with="ERC721: token already minted" - ) - - - @pytest.mark.asyncio - async def test_mint_to_zero_address(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # minting to zero address should fail - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'mint', [ - ZERO_ADDRESS, - *NONEXISTENT_TOKEN - ]), - reverted_with="ERC721: cannot mint to the zero address" - ) - - - @pytest.mark.asyncio - async def test_mint_approve_should_be_zero_address(self, erc721_minted): - erc721, *_ = erc721_minted - - # approved address should be zero for newly minted tokens - for token in TOKENS: - execution_info = await erc721.getApproved(token).execute() - assert execution_info.result == (0,) - - - @pytest.mark.asyncio - async def test_mint_by_not_owner(self, contract_factory): - erc721, _, not_owner, _, _ = contract_factory - - # minting from not_owner should fail - await assert_revert(signer.send_transaction( - not_owner, erc721.contract_address, 'mint', [ - not_owner.contract_address, - *TOKENS[0] - ]), - reverted_with="Ownable: caller is not the owner" - ) - - - # - # burn - # - - - @pytest.mark.asyncio - async def test_burn(self, erc721_minted): - erc721, account, *_ = erc721_minted - - execution_info = await erc721.balanceOf(account.contract_address).execute() - previous_balance = execution_info.result.balance - - # burn token - await signer.send_transaction( - account, erc721.contract_address, 'burn', [*TOKEN] - ) - - # account balance should subtract one - execution_info = await erc721.balanceOf(account.contract_address).execute() - assert execution_info.result.balance == sub_uint( - previous_balance, to_uint(1) - ) - - # approve should be cleared to zero, therefore, - # 'getApproved()' call should fail - await assert_revert( - erc721.getApproved(TOKEN).execute(), - reverted_with="ERC721: approved query for nonexistent token" - ) - - # 'token_to_burn' owner should be zero; therefore, - # 'ownerOf()' call should fail - await assert_revert( - erc721.ownerOf(TOKEN).execute(), - reverted_with="ERC721: owner query for nonexistent token" - ) - - - @pytest.mark.asyncio - async def test_burn_emits_event(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # mint token to account - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'burn', [ - *TOKEN - ] - ) - - # events - assert_events_emitted( - tx_exec_info, - [ - [0, erc721.contract_address, 'Approval', [ - account.contract_address, ZERO_ADDRESS, *TOKEN]], - [1, erc721.contract_address, 'Transfer', [ - account.contract_address, ZERO_ADDRESS, *TOKEN]] - ] - ) - - - @pytest.mark.asyncio - async def test_burn_nonexistent_token(self, erc721_minted): - erc721, account, *_ = erc721_minted - - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'burn', [ - *NONEXISTENT_TOKEN - ]), - reverted_with="ERC721: owner query for nonexistent token" - ) - - - @pytest.mark.asyncio - async def test_burn_unowned_token(self, erc721_minted): - erc721, account, other, *_ = erc721_minted - - # other should not be able to burn account's token - await assert_revert( - signer.send_transaction( - other, erc721.contract_address, 'burn', [*TOKEN] - ), - reverted_with="ERC721: caller is not the token owner" - ) - - # account can burn their own token - await signer.send_transaction( - account, erc721.contract_address, 'burn', [*TOKEN] - ) - - - @pytest.mark.asyncio - async def test_burn_from_zero_address(self, erc721_minted): - erc721, *_ = erc721_minted - - await assert_revert( - erc721.burn(TOKEN).execute(), - reverted_with="ERC721: caller is not the token owner" - ) diff --git a/tests/token/erc721/test_ERC721MintablePausable.py b/tests/token/erc721/test_ERC721MintablePausable.py deleted file mode 100644 index 74f06cca8..000000000 --- a/tests/token/erc721/test_ERC721MintablePausable.py +++ /dev/null @@ -1,314 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import TRUE, FALSE, ZERO_ADDRESS, assert_revert, to_uint -from utils import ( - get_contract_class, cached_contract, assert_event_emitted, State, Account -) -from ERC721BaseSuite import ( - ERC721Base, NAME, SYMBOL, TOKENS, TOKEN, NONEXISTENT_TOKEN, DATA -) -from access.OwnableBaseSuite import OwnableBase - - -signer = MockSigner(123456789987654321) - -# testing vars -TOKEN_TO_MINT = to_uint(33) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc721_cls = get_contract_class('ERC721MintablePausable') - erc721_holder_cls = get_contract_class('ERC721Holder') - unsupported_cls = get_contract_class('Initializable') - - return account_cls, erc721_cls, erc721_holder_cls, unsupported_cls - - -@pytest.fixture(scope='module') -async def erc721_init(contract_classes): - _, erc721_cls, erc721_holder_cls, unsupported_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc721 = await starknet.deploy( - contract_class=erc721_cls, - constructor_calldata=[ - NAME, # name - SYMBOL, # ticker - account1.contract_address # owner - ] - ) - erc721_holder = await starknet.deploy( - contract_class=erc721_holder_cls, - constructor_calldata=[] - ) - unsupported = await starknet.deploy( - contract_class=unsupported_cls, - constructor_calldata=[] - ) - return ( - starknet.state, - account1, - account2, - erc721, - erc721_holder, - unsupported, - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc721_init): - account_cls, erc721_cls, erc721_holder_cls, unsupported_cls = contract_classes - state, account1, account2, erc721, erc721_holder, unsupported = erc721_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc721 = cached_contract(_state, erc721_cls, erc721) - erc721_holder = cached_contract(_state, erc721_holder_cls, erc721_holder) - unsupported = cached_contract(_state, unsupported_cls, unsupported) - - return erc721, account1, account2, erc721_holder, unsupported - - -@pytest.fixture -async def erc721_minted(contract_factory): - erc721, account, account2, erc721_holder, unsupported = contract_factory - # mint tokens to account - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *token] - ) - - return erc721, account, account2, erc721_holder, unsupported - - -class TestERC721MintablePausable(ERC721Base, OwnableBase): - # - # mint - # - - @pytest.mark.asyncio - async def test_mint_emits_event(self, contract_factory): - erc721, account, _, _, _ = contract_factory - - # mint token to account - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *TOKEN] - ) - - assert_event_emitted( - tx_exec_info, - from_address=erc721.contract_address, - name='Transfer', - data=[ - ZERO_ADDRESS, - account.contract_address, - *TOKEN - ] - ) - - - @pytest.mark.asyncio - async def test_mint(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # checks balance - execution_info = await erc721.balanceOf(account.contract_address).execute() - assert execution_info.result == (to_uint(2),) - - # checks that account owns correct tokens - for token in TOKENS: - execution_info = await erc721.ownerOf(token).execute() - assert execution_info.result == (account.contract_address,) - - - @pytest.mark.asyncio - async def test_mint_duplicate_token_id(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # minting duplicate token_id should fail - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, - *TOKEN - ]), - reverted_with="ERC721: token already minted" - ) - - - @pytest.mark.asyncio - async def test_mint_to_zero_address(self, erc721_minted): - erc721, account, *_ = erc721_minted - - # minting to zero address should fail - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'mint', [ - ZERO_ADDRESS, - *NONEXISTENT_TOKEN - ]), - reverted_with="ERC721: cannot mint to the zero address" - ) - - - @pytest.mark.asyncio - async def test_mint_approve_should_be_zero_address(self, erc721_minted): - erc721, *_ = erc721_minted - - # approved address should be zero for newly minted tokens - for token in TOKENS: - execution_info = await erc721.getApproved(token).execute() - assert execution_info.result == (0,) - - - @pytest.mark.asyncio - async def test_mint_by_not_owner(self, contract_factory): - erc721, _, not_owner, _, _ = contract_factory - - # minting from not_owner should fail - await assert_revert(signer.send_transaction( - not_owner, erc721.contract_address, 'mint', [ - not_owner.contract_address, - *TOKENS[0] - ]), - reverted_with="Ownable: caller is not the owner" - ) - - # - # pause - # - - @pytest.mark.asyncio - async def test_pause(self, erc721_minted): - erc721, owner, other, erc721_holder, _ = erc721_minted - - # pause - await signer.send_transaction(owner, erc721.contract_address, 'pause', []) - - execution_info = await erc721.paused().execute() - assert execution_info.result.paused == TRUE - - await assert_revert(signer.send_transaction( - owner, erc721.contract_address, 'approve', [ - other.contract_address, - *TOKENS[0] - ]), - reverted_with="Pausable: paused" - ) - - await assert_revert(signer.send_transaction( - owner, erc721.contract_address, 'setApprovalForAll', [ - other.contract_address, - TRUE - ]), - reverted_with="Pausable: paused" - ) - - await assert_revert(signer.send_transaction( - owner, erc721.contract_address, 'transferFrom', [ - owner.contract_address, - other.contract_address, - *TOKENS[0] - ]), - reverted_with="Pausable: paused" - ) - - await assert_revert(signer.send_transaction( - owner, erc721.contract_address, 'safeTransferFrom', [ - owner.contract_address, - erc721_holder.contract_address, - *TOKENS[1], - len(DATA), - *DATA - ]), - reverted_with="Pausable: paused" - ) - - await assert_revert(signer.send_transaction( - owner, erc721.contract_address, 'mint', [ - other.contract_address, - *TOKEN_TO_MINT - ]), - reverted_with="Pausable: paused" - ) - - - @pytest.mark.asyncio - async def test_unpause(self, erc721_minted): - erc721, owner, other, erc721_holder, _ = erc721_minted - - # pause - await signer.send_transaction(owner, erc721.contract_address, 'pause', []) - - # unpause - await signer.send_transaction(owner, erc721.contract_address, 'unpause', []) - - execution_info = await erc721.paused().execute() - assert execution_info.result.paused == FALSE - - await signer.send_transaction( - owner, erc721.contract_address, 'approve', [ - other.contract_address, - *TOKENS[0] - ] - ) - - await signer.send_transaction( - owner, erc721.contract_address, 'setApprovalForAll', [ - other.contract_address, - TRUE - ] - ) - - await signer.send_transaction( - owner, erc721.contract_address, 'transferFrom', [ - owner.contract_address, - other.contract_address, - *TOKENS[0] - ] - ) - - await signer.send_transaction( - other, erc721.contract_address, 'safeTransferFrom', [ - owner.contract_address, - erc721_holder.contract_address, - *TOKENS[1], - len(DATA), - *DATA - ] - ) - - await signer.send_transaction( - owner, erc721.contract_address, 'mint', [ - other.contract_address, - *TOKEN_TO_MINT - ] - ) - - - @pytest.mark.asyncio - async def test_only_owner(self, erc721_minted): - erc721, owner, other, *_ = erc721_minted - - # not-owner pause should revert - await assert_revert( - signer.send_transaction( - other, erc721.contract_address, 'pause', []), - reverted_with="Ownable: caller is not the owner" - ) - - # owner pause - await signer.send_transaction(owner, erc721.contract_address, 'pause', []) - - # not-owner unpause should revert - await assert_revert( - signer.send_transaction( - other, erc721.contract_address, 'unpause', []), - reverted_with="Ownable: caller is not the owner" - ) - - # owner unpause - await signer.send_transaction(owner, erc721.contract_address, 'unpause', []) diff --git a/tests/token/erc721/test_ERC721SafeMintableMock.py b/tests/token/erc721/test_ERC721SafeMintableMock.py deleted file mode 100644 index 6b9881d1b..000000000 --- a/tests/token/erc721/test_ERC721SafeMintableMock.py +++ /dev/null @@ -1,231 +0,0 @@ -import pytest -from signers import MockSigner -from nile.utils import ( - ZERO_ADDRESS, INVALID_UINT256, assert_revert, to_uint -) -from utils import ( - get_contract_class, cached_contract, assert_event_emitted, State, Account -) -from ERC721BaseSuite import ERC721Base, NAME, SYMBOL, DATA, TOKEN, TOKENS -from access.OwnableBaseSuite import OwnableBase - - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - erc721_cls = get_contract_class('ERC721SafeMintableMock') - erc721_holder_cls = get_contract_class('ERC721Holder') - unsupported_cls = get_contract_class('Initializable') - - return account_cls, erc721_cls, erc721_holder_cls, unsupported_cls - - -@pytest.fixture(scope='module') -async def erc721_init(contract_classes): - account_cls, erc721_cls, erc721_holder_cls, unsupported_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - erc721 = await starknet.deploy( - contract_class=erc721_cls, - constructor_calldata=[ - NAME, # name - SYMBOL, # ticker - account1.contract_address # owner - ] - ) - erc721_holder = await starknet.deploy( - contract_class=erc721_holder_cls, - constructor_calldata=[] - ) - unsupported = await starknet.deploy( - contract_class=unsupported_cls, - constructor_calldata=[] - ) - return ( - starknet.state, - account1, - account2, - erc721, - erc721_holder, - unsupported - ) - - -@pytest.fixture -def contract_factory(contract_classes, erc721_init): - account_cls, erc721_cls, erc721_holder_cls, unsupported_cls = contract_classes - state, account1, account2, erc721, erc721_holder, unsupported = erc721_init - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - erc721 = cached_contract(_state, erc721_cls, erc721) - erc721_holder = cached_contract(_state, erc721_holder_cls, erc721_holder) - unsupported = cached_contract(_state, unsupported_cls, unsupported) - - return erc721, account1, account2, erc721_holder, unsupported - - -@pytest.fixture -async def erc721_minted(contract_factory): - erc721, account, account2, erc721_holder, unsupported = contract_factory - # mint tokens to account - for token in TOKENS: - await signer.send_transaction( - account, erc721.contract_address, 'mint', [ - account.contract_address, *token] - ) - - return erc721, account, account2, erc721_holder, unsupported - - -class TestERC721SafeMintableMock(ERC721Base, OwnableBase): - # - # safeMint - # - - @pytest.mark.asyncio - async def test_safeMint_to_erc721_supported_contract(self, contract_factory): - erc721, account, _, erc721_holder, _ = contract_factory - - await signer.send_transaction( - account, erc721.contract_address, 'safeMint', [ - erc721_holder.contract_address, - *TOKEN, - len(DATA), - *DATA - ] - ) - - # check balance - execution_info = await erc721.balanceOf(erc721_holder.contract_address).call() - assert execution_info.result == (to_uint(1),) - - # check owner - execution_info = await erc721.ownerOf(TOKEN).call() - assert execution_info.result == (erc721_holder.contract_address,) - - - @pytest.mark.asyncio - async def test_safeMint_emits_event(self, contract_factory): - erc721, account, _, erc721_holder, _ = contract_factory - - tx_exec_info = await signer.send_transaction( - account, erc721.contract_address, 'safeMint', [ - erc721_holder.contract_address, - *TOKEN, - len(DATA), - *DATA - ] - ) - - assert_event_emitted( - tx_exec_info, - from_address=erc721.contract_address, - name='Transfer', - data=[ - ZERO_ADDRESS, - erc721_holder.contract_address, - *TOKEN - ] - ) - - - @pytest.mark.asyncio - async def test_safeMint_to_account(self, contract_factory): - erc721, account, recipient, _, _ = contract_factory - - await signer.send_transaction( - account, erc721.contract_address, 'safeMint', [ - recipient.contract_address, - *TOKEN, - len(DATA), - *DATA - ] - ) - - # check balance - execution_info = await erc721.balanceOf(recipient.contract_address).call() - assert execution_info.result == (to_uint(1),) - - # check owner - execution_info = await erc721.ownerOf(TOKEN).call() - assert execution_info.result == (recipient.contract_address,) - - - @pytest.mark.asyncio - async def test_safeMint_to_zero_address(self, contract_factory): - erc721, account, _, _, _ = contract_factory - - # to zero address should be rejected - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'safeMint', [ - ZERO_ADDRESS, - *TOKEN, - len(DATA), - *DATA - ]), - reverted_with="ERC721: cannot mint to the zero address" - ) - - - @pytest.mark.asyncio - async def test_safeMint_from_zero_address(self, contract_factory): - erc721, _, _, erc721_holder, _ = contract_factory - - # Caller address is `0` when not using an account contract - await assert_revert( - erc721.safeMint( - erc721_holder.contract_address, - TOKEN, - DATA - ).execute(), - reverted_with="Ownable: caller is the zero address" - ) - - - @pytest.mark.asyncio - async def test_safeMint_from_not_owner(self, contract_factory): - erc721, _, other, erc721_holder, _ = contract_factory - - await assert_revert(signer.send_transaction( - other, erc721.contract_address, 'safeMint', [ - erc721_holder.contract_address, - *TOKEN, - len(DATA), - *DATA - ]), - reverted_with="Ownable: caller is not the owner" - ) - - - @pytest.mark.asyncio - async def test_safeMint_to_unsupported_contract(self, contract_factory): - erc721, account, _, _, unsupported = contract_factory - - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'safeMint', [ - unsupported.contract_address, - *TOKEN, - len(DATA), - *DATA - ]) - ) - - - @pytest.mark.asyncio - async def test_safeMint_invalid_uint256(self, contract_factory): - erc721, account, recipient, _, _ = contract_factory - - await assert_revert(signer.send_transaction( - account, erc721.contract_address, 'safeMint', [ - recipient.contract_address, - *INVALID_UINT256, - len(DATA), - *DATA - ]), - reverted_with="ERC721: token_id is not a valid Uint256" - ) diff --git a/tests/upgrades/test_Proxy.py b/tests/upgrades/test_Proxy.py deleted file mode 100644 index 911bd818b..000000000 --- a/tests/upgrades/test_Proxy.py +++ /dev/null @@ -1,167 +0,0 @@ -import pytest -from starkware.starknet.public.abi import get_selector_from_name -from signers import MockSigner -from nile.utils import ( - assert_revert, assert_revert_entry_point -) -from utils import ( - get_contract_class, - cached_contract, - assert_event_emitted, - State, - Account -) - -# random value -VALUE = 123 - -signer = MockSigner(123456789987654321) - -class TestProxy: - @pytest.fixture(scope='module') - def contract_classes(self): - account_cls = Account.get_class - implementation_cls = get_contract_class('ProxiableImplementation') - proxy_cls = get_contract_class('Proxy') - - return account_cls, implementation_cls, proxy_cls - - - @pytest.fixture(scope='module') - async def proxy_init(self, contract_classes): - account_cls, implementation_cls, proxy_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - implementation_decl = await starknet.declare( - contract_class=implementation_cls - ) - selector = get_selector_from_name('initializer') - params = [ - account1.contract_address # admin account - ] - proxy = await starknet.deploy( - contract_class=proxy_cls, - constructor_calldata=[ - implementation_decl.class_hash, - selector, - len(params), - *params - ] - ) - return ( - starknet.state, - account1, - account2, - proxy - ) - - - @pytest.fixture - def proxy_factory(self, contract_classes, proxy_init): - account_cls, _, proxy_cls = contract_classes - state, account1, account2, proxy = proxy_init - _state = state.copy() - admin = cached_contract(_state, account_cls, account1) - other = cached_contract(_state, account_cls, account2) - proxy = cached_contract(_state, proxy_cls, proxy) - - return admin, other, proxy - - - # - # initializer - # - - @pytest.mark.asyncio - async def test_initializer(self, proxy_factory): - admin, _, proxy = proxy_factory - - # check admin is set - execution_info = await signer.send_transaction( - admin, proxy.contract_address, 'getAdmin', [] - ) - assert execution_info.call_info.retdata[1] == admin.contract_address - - - @pytest.mark.asyncio - async def test_initializer_after_initialized(self, proxy_factory): - admin, _, proxy = proxy_factory - - await assert_revert(signer.send_transaction( - admin, proxy.contract_address, 'initializer', [admin.contract_address]), - reverted_with="Proxy: contract already initialized" - ) - - # - # set_admin - # - - @pytest.mark.asyncio - async def test_set_admin(self, proxy_factory): - admin, _, proxy = proxy_factory - - # set admin - tx_exec_info = await signer.send_transaction( - admin, proxy.contract_address, 'setAdmin', [VALUE] - ) - - # check event - assert_event_emitted( - tx_exec_info, - from_address=proxy.contract_address, - name='AdminChanged', - data=[ - admin.contract_address, # old admin - VALUE # new admin - ] - ) - - # check new admin - execution_info = await signer.send_transaction( - admin, proxy.contract_address, 'getAdmin', [] - ) - assert execution_info.call_info.retdata[1] == VALUE - - - @pytest.mark.asyncio - async def test_set_admin_from_unauthorized(self, proxy_factory): - _, non_admin, proxy = proxy_factory - - # set admin - await assert_revert(signer.send_transaction( - non_admin, proxy.contract_address, 'setAdmin', [VALUE]), - reverted_with="Proxy: caller is not admin" - ) - - # - # fallback function - # - - @pytest.mark.asyncio - async def test_default_fallback(self, proxy_factory): - admin, _, proxy = proxy_factory - - # set value through proxy - await signer.send_transaction( - admin, proxy.contract_address, 'setValue', [VALUE] - ) - - # get value through proxy - execution_info = await signer.send_transaction( - admin, proxy.contract_address, 'getValue', [] - ) - assert execution_info.call_info.retdata[1] == VALUE - - - @pytest.mark.asyncio - async def test_fallback_when_selector_does_not_exist(self, proxy_factory): - admin, _, proxy = proxy_factory - - # should fail with entry point error - await assert_revert_entry_point( - signer.send_transaction( - admin, proxy.contract_address, 'invalid_selector', [] - ), - invalid_selector='invalid_selector' - ) diff --git a/tests/upgrades/test_upgrades.py b/tests/upgrades/test_upgrades.py deleted file mode 100644 index 75e9c7b20..000000000 --- a/tests/upgrades/test_upgrades.py +++ /dev/null @@ -1,368 +0,0 @@ -import pytest -from signers import MockSigner -from starkware.starknet.public.abi import get_selector_from_name -from nile.utils import assert_revert, assert_revert_entry_point, FALSE, TRUE -from utils import ( - State, - Account, - assert_event_emitted, - get_contract_class, - cached_contract, -) - - -# random value -VALUE_1 = 123 -VALUE_2 = 987 - -signer = MockSigner(123456789987654321) - - -class TestUpgrades: - @pytest.fixture(scope='module') - def contract_classes(self): - account_cls = Account.get_class - v1_cls = get_contract_class('UpgradesMockV1') - v2_cls = get_contract_class('UpgradesMockV2') - proxy_cls = get_contract_class('Proxy') - - return account_cls, v1_cls, v2_cls, proxy_cls - - - @pytest.fixture(scope='module') - async def implementations_declare(self, contract_classes): - _, v1_cls, v2_cls, proxy_cls = contract_classes - starknet = await State.init() - account1 = await Account.deploy(signer.public_key) - account2 = await Account.deploy(signer.public_key) - - v1_decl = await starknet.declare( - contract_class=v1_cls, - ) - v2_decl = await starknet.declare( - contract_class=v2_cls, - ) - - return ( - starknet, - account1, - account2, - v1_decl, - v2_decl, - proxy_cls - ) - - - @pytest.fixture(scope='module') - async def proxy_deploy(self, implementations_declare): - starknet, _, _, v1_decl, _, proxy_cls = implementations_declare - - # with selector set to 0, internal initialization call must be ignored - proxy = await starknet.deploy( - contract_class=proxy_cls, - constructor_calldata=[ - v1_decl.class_hash, - 0, - 0, - *[] - ] - ) - return proxy - - - @pytest.fixture(scope='module') - async def proxy_init(self, implementations_declare): - starknet, account1, account2, v1_decl, v2_decl, proxy_cls = implementations_declare - - selector = get_selector_from_name('initializer') - params = [ - account1.contract_address # admin account - ] - proxy = await starknet.deploy( - contract_class=proxy_cls, - constructor_calldata=[ - v1_decl.class_hash, - selector, - len(params), - *params - ] - ) - return ( - starknet.state, - account1, - account2, - v1_decl, - v2_decl, - proxy - ) - - - @pytest.fixture - def proxy_factory(self, contract_classes, proxy_init, proxy_deploy): - account_cls, _, _, proxy_cls = contract_classes - state, account1, account2, v1_decl, v2_decl, proxy = proxy_init - non_initialized_proxy = proxy_deploy - - _state = state.copy() - account1 = cached_contract(_state, account_cls, account1) - account2 = cached_contract(_state, account_cls, account2) - proxy = cached_contract(_state, proxy_cls, proxy) - - return account1, account2, proxy, non_initialized_proxy, v1_decl, v2_decl - - - @pytest.fixture - async def after_upgrade(self, proxy_factory): - admin, other, proxy, _, v1_decl, v2_decl = proxy_factory - - # set value, and upgrade to v2 - await signer.send_transactions( - admin, - [ - (proxy.contract_address, 'setValue1', [VALUE_1]), - (proxy.contract_address, 'upgrade', [v2_decl.class_hash]) - ] - ) - - return admin, other, proxy, v1_decl, v2_decl - - - @pytest.mark.asyncio - async def test_deployment_without_initialization(self, proxy_factory): - admin, _, _, proxy, *_ = proxy_factory - - # assert not initialized yet - execution_info = await signer.send_transaction( - admin, proxy.contract_address, 'initialized', [] - ) - assert execution_info.call_info.retdata[1] == FALSE - - # initialize - await signer.send_transaction( - admin, proxy.contract_address, 'initializer', [admin.contract_address], - ) - - # assert initialized - execution_info = await signer.send_transaction( - admin, proxy.contract_address, 'initialized', [] - ) - assert execution_info.call_info.retdata[1] == TRUE - - - @pytest.mark.asyncio - async def test_initializer_already_initialized(self, proxy_factory): - admin, _, proxy, *_ = proxy_factory - - await assert_revert( - signer.send_transaction( - admin, proxy.contract_address, 'initializer', [ - admin.contract_address - ] - ), - reverted_with='Proxy: contract already initialized' - ) - - - @pytest.mark.asyncio - async def test_upgrade(self, proxy_factory): - admin, _, proxy, _, _, v2_decl = proxy_factory - - # set value - await signer.send_transactions( - admin, - [ - (proxy.contract_address, 'setValue1', [VALUE_1]), - ] - ) - - # check value - execution_info = await signer.send_transaction( - admin, proxy.contract_address, 'getValue1', [] - ) - assert execution_info.call_info.retdata[1] == VALUE_1 - - # upgrade - await signer.send_transaction( - admin, proxy.contract_address, 'upgrade', [ - v2_decl.class_hash - ] - ) - - # check value - execution_info = await signer.send_transaction( - admin, proxy.contract_address, 'getValue1', [] - ) - assert execution_info.call_info.retdata[1] == VALUE_1 - - - @pytest.mark.asyncio - async def test_upgrade_event(self, proxy_factory): - admin, _, proxy, _, _, v2_decl = proxy_factory - - # upgrade - tx_exec_info = await signer.send_transaction( - admin, proxy.contract_address, 'upgrade', [ - v2_decl.class_hash - ] - ) - - # check event - assert_event_emitted( - tx_exec_info, - from_address=proxy.contract_address, - name='Upgraded', - data=[ - v2_decl.class_hash # new class hash - ] - ) - - - @pytest.mark.asyncio - async def test_upgrade_from_non_admin(self, proxy_factory): - _, non_admin, proxy, _, _, v2_decl = proxy_factory - - # upgrade should revert - await assert_revert( - signer.send_transaction( - non_admin, proxy.contract_address, 'upgrade', [ - v2_decl.class_hash - ] - ), - reverted_with="Proxy: caller is not admin" - ) - - - @pytest.mark.asyncio - async def test_set_implementation_as_zero(self, proxy_factory): - admin, _, proxy, *_ = proxy_factory - - # upgrade should revert - await assert_revert( - signer.send_transaction( - admin, proxy.contract_address, 'upgrade', [0] - ), - reverted_with="Proxy: implementation hash cannot be zero" - ) - - @pytest.mark.asyncio - async def test_implementation_v2(self, after_upgrade): - admin, _, proxy, _, v2_decl = after_upgrade - - execution_info = await signer.send_transactions( - admin, - [ - (proxy.contract_address, 'getImplementationHash', []), - (proxy.contract_address, 'getAdmin', []), - (proxy.contract_address, 'getValue1', []) - ] - ) - - expected = [ - 3, # number of return values - v2_decl.class_hash, # getImplementationHash - admin.contract_address, # getAdmin - VALUE_1 # getValue1 - ] - - assert execution_info.call_info.retdata == expected - - # - # v2 functions - # - - @pytest.mark.asyncio - async def test_set_admin(self, after_upgrade): - admin, new_admin, proxy, *_ = after_upgrade - - # change admin - await signer.send_transaction( - admin, proxy.contract_address, 'setAdmin', [ - new_admin.contract_address - ] - ) - - # check admin - execution_info = await signer.send_transaction( - admin, proxy.contract_address, 'getAdmin', [] - ) - assert execution_info.call_info.retdata[1] == new_admin.contract_address - - - @pytest.mark.asyncio - async def test_set_admin_from_non_admin(self, after_upgrade): - _, non_admin, proxy, *_ = after_upgrade - - # should revert - await assert_revert(signer.send_transaction( - non_admin, proxy.contract_address, 'setAdmin', [non_admin.contract_address]), - reverted_with="Proxy: caller is not admin" - ) - - - @pytest.mark.asyncio - async def test_v2_functions_pre_and_post_upgrade(self, proxy_factory): - admin, new_admin, proxy, _, _, v2_decl = proxy_factory - - # check getValue2 doesn't exist - await assert_revert_entry_point( - signer.send_transaction( - admin, proxy.contract_address, 'getValue2', [] - ), - invalid_selector='getValue2' - ) - - # check setValue2 doesn't exist in v1 - await assert_revert_entry_point( - signer.send_transaction( - admin, proxy.contract_address, 'setValue2', [VALUE_2] - ), - invalid_selector='setValue2' - ) - - # check getAdmin doesn't exist in v1 - await assert_revert_entry_point( - signer.send_transaction( - admin, proxy.contract_address, 'getAdmin', [] - ), - invalid_selector='getAdmin' - ) - - # check setAdmin doesn't exist in v1 - await assert_revert_entry_point( - signer.send_transaction( - admin, proxy.contract_address, 'setAdmin', [new_admin.contract_address] - ), - invalid_selector='setAdmin' - ) - - # upgrade - await signer.send_transaction( - admin, proxy.contract_address, 'upgrade', [ - v2_decl.class_hash - ] - ) - - # set value 2 and admin - await signer.send_transactions( - admin, - [ - (proxy.contract_address, 'setValue2', [VALUE_2]), - (proxy.contract_address, 'setAdmin', [new_admin.contract_address]) - ] - ) - - # check value 2 and admin - execution_info = await signer.send_transactions( - admin, - [ - (proxy.contract_address, 'getValue2', []), - (proxy.contract_address, 'getAdmin', []) - ] - ) - - expected = [ - 2, # number of return values - VALUE_2, # getValue2 - new_admin.contract_address # getAdmin - ] - assert execution_info.call_info.retdata == expected diff --git a/tests/utils.py b/tests/utils.py deleted file mode 100644 index e2da740d6..000000000 --- a/tests/utils.py +++ /dev/null @@ -1,154 +0,0 @@ -"""Utilities for testing Cairo contracts.""" - -import os -from pathlib import Path -from starkware.crypto.signature.fast_pedersen_hash import pedersen_hash -from starkware.starknet.core.os.class_hash import compute_class_hash -from starkware.starknet.public.abi import get_selector_from_name -from starkware.starknet.business_logic.execution.objects import OrderedEvent -from starkware.starknet.compiler.compile import compile_starknet_files -from starkware.starknet.testing.starknet import StarknetContract -from starkware.starknet.testing.starknet import Starknet - - - -MAX_UINT256 = (2**128 - 1, 2**128 - 1) -INVALID_UINT256 = (MAX_UINT256[0] + 1, MAX_UINT256[1]) -ZERO_ADDRESS = 0 -TRUE = 1 -FALSE = 0 -IACCOUNT_ID = 0xa66bd575 - -_root = Path(__file__).parent.parent - - -def get_cairo_path(): - CAIRO_PATH = os.getenv('CAIRO_PATH') - cairo_path = [] - - if CAIRO_PATH is not None: - cairo_path = [p for p in CAIRO_PATH.split(":")] - - return cairo_path - -def contract_path(name): - if name.startswith("tests/"): - return str(_root / name) - else: - return str(_root / "src" / name) - - -def assert_event_emitted(tx_exec_info, from_address, name, data, order=0): - """Assert one single event is fired with correct data.""" - assert_events_emitted(tx_exec_info, [(order, from_address, name, data)]) - - -def assert_events_emitted(tx_exec_info, events): - """Assert events are fired with correct data.""" - for event in events: - order, from_address, name, data = event - event_obj = OrderedEvent( - order=order, - keys=[get_selector_from_name(name)], - data=data, - ) - - base = tx_exec_info.call_info.internal_calls[0] - if event_obj in base.events and from_address == base.contract_address: - return - - try: - base2 = base.internal_calls[0] - if event_obj in base2.events and from_address == base2.contract_address: - return - except IndexError: - pass - - raise BaseException("Event not fired or not fired correctly") - - -def _get_path_from_name(name): - """Return the contract path by contract name.""" - dirs = ["src", "tests/mocks"] - for dir in dirs: - for (dirpath, _, filenames) in os.walk(dir): - for file in filenames: - if file == f"{name}.cairo": - return os.path.join(dirpath, file) - - raise FileNotFoundError(f"Cannot find '{name}'.") - - -def get_contract_class(contract, is_path=False): - """Return the contract class from the contract name or path""" - if is_path: - path = contract_path(contract) - else: - path = _get_path_from_name(contract) - - contract_class = compile_starknet_files( - files=[path], - debug_info=True, - cairo_path=get_cairo_path() - ) - return contract_class - - -def get_class_hash(contract_name, is_path=False): - """Return the class_hash for a given contract.""" - contract_class = get_contract_class(contract_name, is_path) - return compute_class_hash(contract_class=contract_class, hash_func=pedersen_hash) - - -def cached_contract(state, _class, deployed): - """Return the cached contract""" - contract = StarknetContract( - state=state, - abi=_class.abi, - contract_address=deployed.contract_address, - deploy_call_info=deployed.deploy_call_info - ) - return contract - - -class State: - """ - Utility helper for Account class to initialize and return StarkNet state. - - Example - --------- - Initalize StarkNet state - - >>> starknet = await State.init() - - """ - async def init(): - global starknet - starknet = await Starknet.empty() - return starknet - - -class Account: - """ - Utility for deploying Account contract. - - Parameters - ---------- - - public_key : int - - Examples - ---------- - - >>> starknet = await State.init() - >>> account = await Account.deploy(public_key) - - """ - get_class = get_contract_class("Account") - - async def deploy(public_key): - account = await starknet.deploy( - contract_class=Account.get_class, - constructor_calldata=[public_key] - ) - return account diff --git a/tests/utils/test_UniversalDeployer.py b/tests/utils/test_UniversalDeployer.py deleted file mode 100644 index 3fbfef2d9..000000000 --- a/tests/utils/test_UniversalDeployer.py +++ /dev/null @@ -1,102 +0,0 @@ -import pytest -from starkware.starknet.core.os.contract_address.contract_address import calculate_contract_address_from_hash -from starkware.crypto.signature.fast_pedersen_hash import pedersen_hash -from starkware.starknet.core.os.class_hash import compute_class_hash - -from signers import MockSigner -from utils import ( - State, - Account, - get_contract_class, - assert_event_emitted, - cached_contract, - IACCOUNT_ID, - FALSE, - TRUE, -) - -signer = MockSigner(123456789987654321) - - -@pytest.fixture(scope='module') -def contract_classes(): - account_cls = Account.get_class - deployer_cls = get_contract_class('UniversalDeployer') - - return account_cls, deployer_cls - - -@pytest.fixture(scope='module') -async def deployer_init(contract_classes): - _, deployer_cls = contract_classes - starknet = await State.init() - account = await Account.deploy(signer.public_key) - deployer = await starknet.deploy(contract_class=deployer_cls) - return ( - starknet.state, - account, - deployer - ) - - -@pytest.fixture -def deployer_factory(contract_classes, deployer_init): - account_cls, deployer_cls = contract_classes - state, account, deployer = deployer_init - _state = state.copy() - _account = cached_contract(_state, account_cls, account) - deployer = cached_contract(_state, deployer_cls, deployer) - - return _account, deployer - - -@pytest.mark.asyncio -@pytest.mark.parametrize('unique', [TRUE, FALSE]) -async def test_deployment(deployer_factory, unique): - account, deployer = deployer_factory - salt = 1234567875432 # random value - calldata = [signer.public_key] - class_hash = compute_class_hash( - contract_class=Account.get_class, hash_func=pedersen_hash) - - # deploy contract - params = [class_hash, salt, unique, len(calldata), *calldata] - deploy_exec_info = await signer.send_transaction(account, deployer.contract_address, 'deployContract', params) - deployed_address = deploy_exec_info.call_info.retdata[1] - - # check address - if unique: - actual_salt = pedersen_hash(account.contract_address, salt) - deployer_address = deployer.contract_address - else: - actual_salt = salt - deployer_address = 0 - - expected_address = calculate_contract_address_from_hash( - salt=actual_salt, - class_hash=class_hash, - constructor_calldata=calldata, - deployer_address=deployer_address - ) - - assert deployed_address == expected_address - - # check deployment - tx_exec_info = await signer.send_transaction(account, deployed_address, 'supportsInterface', [IACCOUNT_ID]) - is_account = tx_exec_info.call_info.retdata[1] - assert is_account == TRUE - - assert_event_emitted( - deploy_exec_info, - from_address=deployer.contract_address, - name='ContractDeployed', - data=[ - deployed_address, # contractAddress - account.contract_address, # deployer - unique, # unique - class_hash, # classHash - len(calldata), # calldata_len - *calldata, # calldata - salt, # salt - ] - ) diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 053a3e028..000000000 --- a/tox.ini +++ /dev/null @@ -1,63 +0,0 @@ -[tox] -minversion = 3.15 -envlist = default -isolated_build = True - -[pytest] -filterwarnings = - ignore::DeprecationWarning -addopts= -n auto -asyncio_mode = auto -markers = - only: marks a subset of tests to run (development purpose) - -[testenv] -description = Invoke pytest to run automated tests -setenv = - TOXINIDIR = {toxinidir} -passenv = - HOME - PYTHONPATH -deps = - cairo-lang==0.10.1 - cairo-nile==0.11.0 - pytest-xdist - # See https://github.com/starkware-libs/cairo-lang/issues/52 - marshmallow-dataclass==8.5.3 -extras = - testing -commands = - nile compile --directory src/ - pytest {posargs} - -[testenv:coverage] -description = Invoke nile-coverage to generate coverage report -skip_install = True -setenv = - {[testenv]setenv} - CAIRO_PATH = src -deps = - {[testenv]deps} - nile-coverage==0.2.4 -commands = - nile compile --directory src/ - nile coverage -c src {posargs} - -[testenv:build] -description = Build the package in isolation according to PEP517, see https://github.com/pypa/build -skip_install = True -changedir = {toxinidir} -deps = - build[virtualenv] - twine -commands = - python -m build . -o dist - python -m twine check --strict dist/* - -[testenv:lint] -description = Lint Markdown documents following the rules set forth here: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md -changedir = {toxinidir} -allowlist_externals = - npx -commands = - npx markdownlint-cli README.md CONTRIBUTING.md docs -i docs/node_modules From bce2506ae8f70ef810d8d299f58c665f4ec6d208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Tue, 7 Mar 2023 20:55:49 -0300 Subject: [PATCH 030/124] re-structure project --- .../account_mock.cairo => account.cairo} | 15 +++---- src/openzeppelin/account/cairo_project.toml | 2 - src/openzeppelin/account/lib.cairo | 6 --- .../account/tests/test_account.cairo | 43 ------------------- src/openzeppelin/cairo_project.toml | 2 + src/openzeppelin/introspection.cairo | 1 + .../tests/erc165mock.cairo => erc165.cairo} | 20 ++++++--- .../introspection/erc165/cairo_project.toml | 2 - .../introspection/erc165/lib.cairo | 6 --- .../introspection/erc165/tests.cairo | 2 - src/openzeppelin/lib.cairo | 3 ++ src/openzeppelin/{account => }/tests.cairo | 2 +- src/openzeppelin/tests/test_account.cairo | 18 ++++++++ .../erc165 => }/tests/test_erc165.cairo | 19 ++++---- 14 files changed, 54 insertions(+), 87 deletions(-) rename src/openzeppelin/{account/tests/account_mock.cairo => account.cairo} (78%) delete mode 100644 src/openzeppelin/account/cairo_project.toml delete mode 100644 src/openzeppelin/account/lib.cairo delete mode 100644 src/openzeppelin/account/tests/test_account.cairo create mode 100644 src/openzeppelin/cairo_project.toml create mode 100644 src/openzeppelin/introspection.cairo rename src/openzeppelin/introspection/{erc165/tests/erc165mock.cairo => erc165.cairo} (60%) delete mode 100644 src/openzeppelin/introspection/erc165/cairo_project.toml delete mode 100644 src/openzeppelin/introspection/erc165/lib.cairo delete mode 100644 src/openzeppelin/introspection/erc165/tests.cairo create mode 100644 src/openzeppelin/lib.cairo rename src/openzeppelin/{account => }/tests.cairo (50%) create mode 100644 src/openzeppelin/tests/test_account.cairo rename src/openzeppelin/{introspection/erc165 => }/tests/test_erc165.cairo (53%) diff --git a/src/openzeppelin/account/tests/account_mock.cairo b/src/openzeppelin/account.cairo similarity index 78% rename from src/openzeppelin/account/tests/account_mock.cairo rename to src/openzeppelin/account.cairo index cee549e12..e41be2080 100644 --- a/src/openzeppelin/account/tests/account_mock.cairo +++ b/src/openzeppelin/account.cairo @@ -1,6 +1,9 @@ +const ACCOUNT_ID: felt = 0x4; + #[account_contract] mod Account { - use erc165::ERC165Library; + use openzeppelin::account::ACCOUNT_ID; + use openzeppelin::introspection::erc165::ERC165Contract; use starknet::get_caller_address; use starknet::get_contract_address; @@ -10,6 +13,7 @@ mod Account { #[constructor] fn constructor(_public_key: felt) { + ERC165Contract::register_interface(ACCOUNT_ID); public_key::write(_public_key); } @@ -41,14 +45,9 @@ mod Account { assert(1 == 2, 'Account: unauthorized.'); } - // ERC165Library + // ERC165Contract #[view] fn supports_interface(interface_id: felt) -> bool { - ERC165Library::supports_interface(interface_id) - } - - #[external] - fn register_interface(interface_id: felt) { - ERC165Library::register_interface(interface_id); + ERC165Contract::supports_interface(interface_id) } } diff --git a/src/openzeppelin/account/cairo_project.toml b/src/openzeppelin/account/cairo_project.toml deleted file mode 100644 index 9a0b3f035..000000000 --- a/src/openzeppelin/account/cairo_project.toml +++ /dev/null @@ -1,2 +0,0 @@ -[crate_roots] -account = "." diff --git a/src/openzeppelin/account/lib.cairo b/src/openzeppelin/account/lib.cairo deleted file mode 100644 index f6bc9aeb8..000000000 --- a/src/openzeppelin/account/lib.cairo +++ /dev/null @@ -1,6 +0,0 @@ -mod tests; - -trait IAccount { - // fn supports_interface(interface_id: felt) -> bool; - // fn register_interface(interface_id: felt); -} diff --git a/src/openzeppelin/account/tests/test_account.cairo b/src/openzeppelin/account/tests/test_account.cairo deleted file mode 100644 index 21ca324d5..000000000 --- a/src/openzeppelin/account/tests/test_account.cairo +++ /dev/null @@ -1,43 +0,0 @@ -use erc165::tests::erc165mock::ERC165Mock; - -const ERC165_ID: felt = 0x01ffc9a7; -const INVALID_ID: felt = 0xffffffff; -const OTHER_ID: felt = 0x12345678; - - -#[test] -#[available_gas(2000000)] -fn test_default_behavior() { - let supports_default_interface: bool = ERC165Mock::supports_interface(ERC165_ID); - assert(supports_default_interface, 'Should support base interface'); -} - -#[test] -#[available_gas(2000000)] -fn test_not_registered_interface() { - let supports_unregistered_interface: bool = ERC165Mock::supports_interface(OTHER_ID); - assert(! supports_unregistered_interface, 'Should not support unregistered'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_supports_invalid_interface() { - let supports_invalid_interface: bool = ERC165Mock::supports_interface(INVALID_ID); - assert(! supports_invalid_interface, 'Should not support invalid id'); -} - -#[test] -#[available_gas(2000000)] -fn test_register_interface() { - ERC165Mock::register_interface(OTHER_ID); - let supports_new_interface: bool = ERC165Mock::supports_interface(OTHER_ID); - assert(supports_new_interface, 'Should support new interface'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_register_invalid_interface() { - ERC165Mock::register_interface(INVALID_ID); -} diff --git a/src/openzeppelin/cairo_project.toml b/src/openzeppelin/cairo_project.toml new file mode 100644 index 000000000..badca57cd --- /dev/null +++ b/src/openzeppelin/cairo_project.toml @@ -0,0 +1,2 @@ +[crate_roots] +openzeppelin = "." diff --git a/src/openzeppelin/introspection.cairo b/src/openzeppelin/introspection.cairo new file mode 100644 index 000000000..4391460f4 --- /dev/null +++ b/src/openzeppelin/introspection.cairo @@ -0,0 +1 @@ +mod erc165; diff --git a/src/openzeppelin/introspection/erc165/tests/erc165mock.cairo b/src/openzeppelin/introspection/erc165.cairo similarity index 60% rename from src/openzeppelin/introspection/erc165/tests/erc165mock.cairo rename to src/openzeppelin/introspection/erc165.cairo index 0526945e7..533593512 100644 --- a/src/openzeppelin/introspection/erc165/tests/erc165mock.cairo +++ b/src/openzeppelin/introspection/erc165.cairo @@ -1,23 +1,29 @@ +const IERC165_ID: felt = 0x01ffc9a7; +const INVALID_ID: felt = 0xffffffff; + +trait IERC165 { + fn supports_interface(interface_id: felt) -> bool; + fn register_interface(interface_id: felt); +} + #[contract] -mod ERC165Mock { - use erc165::IERC165; - const IERC165_ID: felt = 0x01ffc9a7; - const INVALID_ID: felt = 0xffffffff; +mod ERC165Contract { + use openzeppelin::introspection::erc165; struct Storage { supported_interfaces: LegacyMap::, } - impl ERC165 of IERC165 { + impl ERC165 of erc165::IERC165 { fn supports_interface(interface_id: felt) -> bool { - if interface_id == IERC165_ID { + if interface_id == erc165::IERC165_ID { return true; } supported_interfaces::read(interface_id) } fn register_interface(interface_id: felt) { - assert(interface_id != INVALID_ID, 'Invalid id'); + assert(interface_id != erc165::INVALID_ID, 'Invalid id'); supported_interfaces::write(interface_id, true); } } diff --git a/src/openzeppelin/introspection/erc165/cairo_project.toml b/src/openzeppelin/introspection/erc165/cairo_project.toml deleted file mode 100644 index ba52962d0..000000000 --- a/src/openzeppelin/introspection/erc165/cairo_project.toml +++ /dev/null @@ -1,2 +0,0 @@ -[crate_roots] -erc165 = "." diff --git a/src/openzeppelin/introspection/erc165/lib.cairo b/src/openzeppelin/introspection/erc165/lib.cairo deleted file mode 100644 index 32e5e1525..000000000 --- a/src/openzeppelin/introspection/erc165/lib.cairo +++ /dev/null @@ -1,6 +0,0 @@ -mod tests; - -trait IERC165 { - fn supports_interface(interface_id: felt) -> bool; - fn register_interface(interface_id: felt); -} diff --git a/src/openzeppelin/introspection/erc165/tests.cairo b/src/openzeppelin/introspection/erc165/tests.cairo deleted file mode 100644 index 517c54280..000000000 --- a/src/openzeppelin/introspection/erc165/tests.cairo +++ /dev/null @@ -1,2 +0,0 @@ -mod test_erc165; -mod erc165mock; diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo new file mode 100644 index 000000000..9c80c87ab --- /dev/null +++ b/src/openzeppelin/lib.cairo @@ -0,0 +1,3 @@ +mod introspection; +mod account; +mod tests; diff --git a/src/openzeppelin/account/tests.cairo b/src/openzeppelin/tests.cairo similarity index 50% rename from src/openzeppelin/account/tests.cairo rename to src/openzeppelin/tests.cairo index b837159e4..4bc4f188e 100644 --- a/src/openzeppelin/account/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,2 +1,2 @@ +mod test_erc165; mod test_account; -mod account_mock; diff --git a/src/openzeppelin/tests/test_account.cairo b/src/openzeppelin/tests/test_account.cairo new file mode 100644 index 000000000..7308ec172 --- /dev/null +++ b/src/openzeppelin/tests/test_account.cairo @@ -0,0 +1,18 @@ +use openzeppelin::account::Account; +use openzeppelin::account::ACCOUNT_ID; +use openzeppelin::introspection::erc165::IERC165_ID; + +const PUB_KEY: felt = 0x123; + + +#[test] +#[available_gas(2000000)] +fn test_erc165() { + Account::constructor(PUB_KEY); + + let supports_default_interface: bool = Account::supports_interface(IERC165_ID); + assert(supports_default_interface, 'Should support base interface'); + + let supports_account_interface: bool = Account::supports_interface(ACCOUNT_ID); + assert(supports_account_interface, 'Should support account id'); +} diff --git a/src/openzeppelin/introspection/erc165/tests/test_erc165.cairo b/src/openzeppelin/tests/test_erc165.cairo similarity index 53% rename from src/openzeppelin/introspection/erc165/tests/test_erc165.cairo rename to src/openzeppelin/tests/test_erc165.cairo index 21ca324d5..a387dbfc3 100644 --- a/src/openzeppelin/introspection/erc165/tests/test_erc165.cairo +++ b/src/openzeppelin/tests/test_erc165.cairo @@ -1,37 +1,36 @@ -use erc165::tests::erc165mock::ERC165Mock; +use openzeppelin::introspection::erc165::ERC165Contract; +use openzeppelin::introspection::erc165::IERC165_ID; +use openzeppelin::introspection::erc165::INVALID_ID; -const ERC165_ID: felt = 0x01ffc9a7; -const INVALID_ID: felt = 0xffffffff; const OTHER_ID: felt = 0x12345678; #[test] #[available_gas(2000000)] fn test_default_behavior() { - let supports_default_interface: bool = ERC165Mock::supports_interface(ERC165_ID); + let supports_default_interface: bool = ERC165Contract::supports_interface(IERC165_ID); assert(supports_default_interface, 'Should support base interface'); } #[test] #[available_gas(2000000)] fn test_not_registered_interface() { - let supports_unregistered_interface: bool = ERC165Mock::supports_interface(OTHER_ID); + let supports_unregistered_interface: bool = ERC165Contract::supports_interface(OTHER_ID); assert(! supports_unregistered_interface, 'Should not support unregistered'); } #[test] #[available_gas(2000000)] -#[should_panic] fn test_supports_invalid_interface() { - let supports_invalid_interface: bool = ERC165Mock::supports_interface(INVALID_ID); + let supports_invalid_interface: bool = ERC165Contract::supports_interface(INVALID_ID); assert(! supports_invalid_interface, 'Should not support invalid id'); } #[test] #[available_gas(2000000)] fn test_register_interface() { - ERC165Mock::register_interface(OTHER_ID); - let supports_new_interface: bool = ERC165Mock::supports_interface(OTHER_ID); + ERC165Contract::register_interface(OTHER_ID); + let supports_new_interface: bool = ERC165Contract::supports_interface(OTHER_ID); assert(supports_new_interface, 'Should support new interface'); } @@ -39,5 +38,5 @@ fn test_register_interface() { #[available_gas(2000000)] #[should_panic] fn test_register_invalid_interface() { - ERC165Mock::register_interface(INVALID_ID); + ERC165Contract::register_interface(INVALID_ID); } From 35ede09ccefc64d982cda71bce7f3db46da1e418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Tue, 7 Mar 2023 21:00:17 -0300 Subject: [PATCH 031/124] re-structure project --- src/openzeppelin/account.cairo | 53 ---- src/openzeppelin/account/old/Account.cairo | 147 ---------- .../account/old/AddressRegistry.cairo | 27 -- src/openzeppelin/account/old/EthAccount.cairo | 146 ---------- src/openzeppelin/account/old/IAccount.cairo | 45 --- src/openzeppelin/account/old/library.cairo | 260 ------------------ src/openzeppelin/lib.cairo | 1 - src/openzeppelin/tests.cairo | 1 - src/openzeppelin/tests/test_account.cairo | 18 -- 9 files changed, 698 deletions(-) delete mode 100644 src/openzeppelin/account.cairo delete mode 100644 src/openzeppelin/account/old/Account.cairo delete mode 100644 src/openzeppelin/account/old/AddressRegistry.cairo delete mode 100644 src/openzeppelin/account/old/EthAccount.cairo delete mode 100644 src/openzeppelin/account/old/IAccount.cairo delete mode 100644 src/openzeppelin/account/old/library.cairo delete mode 100644 src/openzeppelin/tests/test_account.cairo diff --git a/src/openzeppelin/account.cairo b/src/openzeppelin/account.cairo deleted file mode 100644 index e41be2080..000000000 --- a/src/openzeppelin/account.cairo +++ /dev/null @@ -1,53 +0,0 @@ -const ACCOUNT_ID: felt = 0x4; - -#[account_contract] -mod Account { - use openzeppelin::account::ACCOUNT_ID; - use openzeppelin::introspection::erc165::ERC165Contract; - use starknet::get_caller_address; - use starknet::get_contract_address; - - struct Storage { - public_key: felt, - } - - #[constructor] - fn constructor(_public_key: felt) { - ERC165Contract::register_interface(ACCOUNT_ID); - public_key::write(_public_key); - } - - #[external] - fn __execute__(amount: felt) { - let is_valid = is_valid_signature(); - assert(is_valid == true, 'Invalid signature.'); - } - - #[external] - fn set_public_key(new_public_key: felt) { - only_self(); - public_key::write(new_public_key); - } - - #[view] - fn get_public_key() -> felt { - public_key::read() - } - - #[view] - fn is_valid_signature() -> bool { - true - } - - fn only_self() { - let caller = starknet::get_caller_address(); - let self = starknet::get_contract_address(); - assert(1 == 2, 'Account: unauthorized.'); - } - - // ERC165Contract - #[view] - fn supports_interface(interface_id: felt) -> bool { - ERC165Contract::supports_interface(interface_id) - } -} diff --git a/src/openzeppelin/account/old/Account.cairo b/src/openzeppelin/account/old/Account.cairo deleted file mode 100644 index 23c10199b..000000000 --- a/src/openzeppelin/account/old/Account.cairo +++ /dev/null @@ -1,147 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/presets/Account.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin -from starkware.starknet.common.syscalls import get_tx_info - -from openzeppelin.account.library import Account, AccountCallArray - - -// -// Constructor -// - -@constructor -func constructor{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -}(publicKey: felt) { - Account.initializer(publicKey); - return (); -} - -// -// Getters -// - -@view -func getPublicKey{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} () -> (publicKey: felt) { - let (publicKey: felt) = Account.get_public_key(); - return (publicKey=publicKey); -} - -@view -func supportsInterface{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} (interfaceId: felt) -> (success: felt) { - return Account.supports_interface(interfaceId); -} - -// -// Setters -// - -@external -func setPublicKey{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} (newPublicKey: felt) { - Account.set_public_key(newPublicKey); - return (); -} - -// -// Business logic -// - -@view -func isValidSignature{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr -}( - hash: felt, - signature_len: felt, - signature: felt* -) -> (isValid: felt) { - let (isValid: felt) = Account.is_valid_signature(hash, signature_len, signature); - return (isValid=isValid); -} - -@external -func __validate__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr -}( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* -) { - let (tx_info) = get_tx_info(); - Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __validate_declare__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr -} (class_hash: felt) { - let (tx_info) = get_tx_info(); - Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __validate_deploy__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr -} ( - class_hash: felt, - salt: felt, - publicKey: felt -) { - let (tx_info) = get_tx_info(); - Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __execute__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -}( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* -) -> ( - response_len: felt, - response: felt* -) { - let (response_len, response) = Account.execute( - call_array_len, call_array, calldata_len, calldata - ); - return (response_len, response); -} diff --git a/src/openzeppelin/account/old/AddressRegistry.cairo b/src/openzeppelin/account/old/AddressRegistry.cairo deleted file mode 100644 index 7076bd25a..000000000 --- a/src/openzeppelin/account/old/AddressRegistry.cairo +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/presets/AddressRegistry.cairo) - -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.starknet.common.syscalls import get_caller_address - -@storage_var -func L1_address(L2_address: felt) -> (address: felt) { -} - -@external -func get_L1_address{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - L2_address: felt -) -> (address: felt) { - return L1_address.read(L2_address); -} - -@external -func set_L1_address{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_L1_address: felt -) { - let (caller) = get_caller_address(); - L1_address.write(caller, new_L1_address); - return (); -} diff --git a/src/openzeppelin/account/old/EthAccount.cairo b/src/openzeppelin/account/old/EthAccount.cairo deleted file mode 100644 index 50277380d..000000000 --- a/src/openzeppelin/account/old/EthAccount.cairo +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/presets/EthAccount.cairo) - -%lang starknet -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin -from starkware.starknet.common.syscalls import get_tx_info - -from openzeppelin.account.library import Account, AccountCallArray - -// -// Constructor -// - -@constructor -func constructor{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -}(ethAddress: felt) { - Account.initializer(ethAddress); - return (); -} - -// -// Getters -// - -@view -func getEthAddress{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} () -> (ethAddress: felt) { - let (ethAddress: felt) = Account.get_public_key(); - return (ethAddress=ethAddress); -} - -@view -func supportsInterface{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} (interfaceId: felt) -> (success: felt) { - return Account.supports_interface(interfaceId); -} - -// -// Setters -// - -@external -func setEthAddress{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr -} (newEthAddress: felt) { - Account.set_public_key(newEthAddress); - return (); -} - -// -// Business logic -// - -@view -func isValidSignature{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -}( - hash: felt, - signature_len: felt, - signature: felt* -) -> (isValid: felt) { - let (isValid) = Account.is_valid_eth_signature(hash, signature_len, signature); - return (isValid=isValid); -} - -@external -func __validate__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -}( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* -) { - let (tx_info) = get_tx_info(); - Account.is_valid_eth_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __validate_declare__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -} (class_hash: felt) { - let (tx_info) = get_tx_info(); - Account.is_valid_eth_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - - -@external -func __validate_deploy__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr -} ( - class_hash: felt, - salt: felt, - ethAddress: felt -) { - let (tx_info) = get_tx_info(); - Account.is_valid_eth_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); - return (); -} - -@external -func __execute__{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, -}( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* -) -> ( - response_len: felt, - response: felt* -) { - let (response_len, response) = Account.execute( - call_array_len, call_array, calldata_len, calldata - ); - return (response_len, response); -} diff --git a/src/openzeppelin/account/old/IAccount.cairo b/src/openzeppelin/account/old/IAccount.cairo deleted file mode 100644 index 8a22d38c1..000000000 --- a/src/openzeppelin/account/old/IAccount.cairo +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/IAccount.cairo) - -%lang starknet - -from openzeppelin.account.library import AccountCallArray - -@contract_interface -namespace IAccount { - func isValidSignature( - hash: felt, - signature_len: felt, - signature: felt* - ) -> (isValid: felt) { - } - - func __validate__( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* - ) { - } - - // Parameter temporarily named `cls_hash` instead of `class_hash` (expected). - // See https://github.com/starkware-libs/cairo-lang/issues/100 for details. - func __validate_declare__(cls_hash: felt) { - } - - func __execute__( - call_array_len: felt, - call_array: AccountCallArray*, - calldata_len: felt, - calldata: felt* - ) -> ( - response_len: felt, - response: felt* - ) { - } - - // ERC165 - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } -} diff --git a/src/openzeppelin/account/old/library.cairo b/src/openzeppelin/account/old/library.cairo deleted file mode 100644 index 6723032eb..000000000 --- a/src/openzeppelin/account/old/library.cairo +++ /dev/null @@ -1,260 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.6.1 (account/library.cairo) - -%lang starknet - -from starkware.cairo.common.registers import get_fp_and_pc -from starkware.cairo.common.signature import verify_ecdsa_signature -from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin -from starkware.cairo.common.alloc import alloc -from starkware.cairo.common.uint256 import Uint256 -from starkware.cairo.common.memcpy import memcpy -from starkware.cairo.common.math import split_felt -from starkware.cairo.common.math_cmp import is_le_felt -from starkware.cairo.common.bool import TRUE, FALSE -from starkware.starknet.common.syscalls import ( - call_contract, - get_caller_address, - get_contract_address, - get_tx_info -) -from starkware.cairo.common.cairo_secp.signature import ( - finalize_keccak, - verify_eth_signature_uint256 -) -from openzeppelin.utils.constants.library import ( - IACCOUNT_ID, - IERC165_ID, - TRANSACTION_VERSION -) - -// -// Storage -// - -@storage_var -func Account_public_key() -> (public_key: felt) { -} - -// -// Structs -// - -struct Call { - to: felt, - selector: felt, - calldata_len: felt, - calldata: felt*, -} - -// Tmp struct introduced while we wait for Cairo -// to support passing `[AccountCall]` to __execute__ -struct AccountCallArray { - to: felt, - selector: felt, - data_offset: felt, - data_len: felt, -} - -namespace Account { - // - // Initializer - // - - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - _public_key: felt - ) { - Account_public_key.write(_public_key); - return (); - } - - // - // Guards - // - - func assert_only_self{syscall_ptr: felt*}() { - let (self) = get_contract_address(); - let (caller) = get_caller_address(); - with_attr error_message("Account: caller is not this account") { - assert self = caller; - } - return (); - } - - // - // Getters - // - - func get_public_key{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( - public_key: felt - ) { - return Account_public_key.read(); - } - - func supports_interface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(interface_id: felt) -> ( - success: felt - ) { - if (interface_id == IERC165_ID) { - return (success=TRUE); - } - if (interface_id == IACCOUNT_ID) { - return (success=TRUE); - } - return (success=FALSE); - } - - // - // Setters - // - - func set_public_key{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - new_public_key: felt - ) { - assert_only_self(); - Account_public_key.write(new_public_key); - return (); - } - - // - // Business logic - // - - func is_valid_signature{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - range_check_ptr, - }(hash: felt, signature_len: felt, signature: felt*) -> (is_valid: felt) { - let (_public_key) = Account_public_key.read(); - - // This interface expects a signature pointer and length to make - // no assumption about signature validation schemes. - // But this implementation does, and it expects a (sig_r, sig_s) pair. - let sig_r = signature[0]; - let sig_s = signature[1]; - - verify_ecdsa_signature( - message=hash, public_key=_public_key, signature_r=sig_r, signature_s=sig_s - ); - - return (is_valid=TRUE); - } - - func is_valid_eth_signature{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, - }(hash: felt, signature_len: felt, signature: felt*) -> (is_valid: felt) { - alloc_locals; - let (_public_key) = get_public_key(); - let (__fp__, _) = get_fp_and_pc(); - - // This interface expects a signature pointer and length to make - // no assumption about signature validation schemes. - // But this implementation does, and it expects a the sig_v, sig_r, - // sig_s, and hash elements. - let sig_v: felt = signature[0]; - let sig_r: Uint256 = Uint256(low=signature[1], high=signature[2]); - let sig_s: Uint256 = Uint256(low=signature[3], high=signature[4]); - let (high, low) = split_felt(hash); - let msg_hash: Uint256 = Uint256(low=low, high=high); - - let (keccak_ptr: felt*) = alloc(); - local keccak_ptr_start: felt* = keccak_ptr; - - with keccak_ptr { - verify_eth_signature_uint256( - msg_hash=msg_hash, r=sig_r, s=sig_s, v=sig_v, eth_address=_public_key - ); - } - // Required to ensure sequencers cannot spoof validation check. - finalize_keccak(keccak_ptr_start=keccak_ptr_start, keccak_ptr_end=keccak_ptr); - - return (is_valid=TRUE); - } - - func execute{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - ecdsa_ptr: SignatureBuiltin*, - bitwise_ptr: BitwiseBuiltin*, - range_check_ptr, - }(call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt*) -> ( - response_len: felt, response: felt* - ) { - alloc_locals; - - let (tx_info) = get_tx_info(); - // Disallow deprecated tx versions - with_attr error_message("Account: deprecated tx version") { - assert is_le_felt(TRANSACTION_VERSION, tx_info.version) = TRUE; - } - - // Assert not a reentrant call - let (caller) = get_caller_address(); - with_attr error_message("Account: reentrant call") { - assert caller = 0; - } - - // TMP: Convert `AccountCallArray` to 'Call'. - let (calls: Call*) = alloc(); - _from_call_array_to_call(call_array_len, call_array, calldata, calls); - let calls_len = call_array_len; - - // Execute call - let (response: felt*) = alloc(); - let (response_len) = _execute_list(calls_len, calls, response); - - return (response_len=response_len, response=response); - } - - func _execute_list{syscall_ptr: felt*}(calls_len: felt, calls: Call*, response: felt*) -> ( - response_len: felt - ) { - alloc_locals; - - // if no more calls - if (calls_len == 0) { - return (response_len=0); - } - - // do the current call - let this_call: Call = [calls]; - let res = call_contract( - contract_address=this_call.to, - function_selector=this_call.selector, - calldata_size=this_call.calldata_len, - calldata=this_call.calldata, - ); - // copy the result in response - memcpy(response, res.retdata, res.retdata_size); - // do the next calls recursively - let (response_len) = _execute_list( - calls_len - 1, calls + Call.SIZE, response + res.retdata_size - ); - return (response_len=response_len + res.retdata_size); - } - - func _from_call_array_to_call{syscall_ptr: felt*}( - call_array_len: felt, call_array: AccountCallArray*, calldata: felt*, calls: Call* - ) { - // if no more calls - if (call_array_len == 0) { - return (); - } - - // parse the current call - assert [calls] = Call( - to=[call_array].to, - selector=[call_array].selector, - calldata_len=[call_array].data_len, - calldata=calldata + [call_array].data_offset - ); - // parse the remaining calls recursively - _from_call_array_to_call( - call_array_len - 1, call_array + AccountCallArray.SIZE, calldata, calls + Call.SIZE - ); - return (); - } -} diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 9c80c87ab..ad13b042b 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,3 +1,2 @@ mod introspection; -mod account; mod tests; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 4bc4f188e..4f213d1c3 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,2 +1 @@ mod test_erc165; -mod test_account; diff --git a/src/openzeppelin/tests/test_account.cairo b/src/openzeppelin/tests/test_account.cairo deleted file mode 100644 index 7308ec172..000000000 --- a/src/openzeppelin/tests/test_account.cairo +++ /dev/null @@ -1,18 +0,0 @@ -use openzeppelin::account::Account; -use openzeppelin::account::ACCOUNT_ID; -use openzeppelin::introspection::erc165::IERC165_ID; - -const PUB_KEY: felt = 0x123; - - -#[test] -#[available_gas(2000000)] -fn test_erc165() { - Account::constructor(PUB_KEY); - - let supports_default_interface: bool = Account::supports_interface(IERC165_ID); - assert(supports_default_interface, 'Should support base interface'); - - let supports_account_interface: bool = Account::supports_interface(ACCOUNT_ID); - assert(supports_account_interface, 'Should support account id'); -} From e55889a2e5add0ba3731b96a9cab7fde2ba24426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Tue, 7 Mar 2023 21:02:53 -0300 Subject: [PATCH 032/124] re-structure project --- src/openzeppelin/introspection.cairo | 1 - src/openzeppelin/introspection/erc165.cairo | 40 -------------------- src/openzeppelin/lib.cairo | 1 - src/openzeppelin/tests.cairo | 2 +- src/openzeppelin/tests/test_erc165.cairo | 42 --------------------- src/openzeppelin/tests/test_mytest.cairo | 5 +++ 6 files changed, 6 insertions(+), 85 deletions(-) delete mode 100644 src/openzeppelin/introspection.cairo delete mode 100644 src/openzeppelin/introspection/erc165.cairo delete mode 100644 src/openzeppelin/tests/test_erc165.cairo create mode 100644 src/openzeppelin/tests/test_mytest.cairo diff --git a/src/openzeppelin/introspection.cairo b/src/openzeppelin/introspection.cairo deleted file mode 100644 index 4391460f4..000000000 --- a/src/openzeppelin/introspection.cairo +++ /dev/null @@ -1 +0,0 @@ -mod erc165; diff --git a/src/openzeppelin/introspection/erc165.cairo b/src/openzeppelin/introspection/erc165.cairo deleted file mode 100644 index 533593512..000000000 --- a/src/openzeppelin/introspection/erc165.cairo +++ /dev/null @@ -1,40 +0,0 @@ -const IERC165_ID: felt = 0x01ffc9a7; -const INVALID_ID: felt = 0xffffffff; - -trait IERC165 { - fn supports_interface(interface_id: felt) -> bool; - fn register_interface(interface_id: felt); -} - -#[contract] -mod ERC165Contract { - use openzeppelin::introspection::erc165; - - struct Storage { - supported_interfaces: LegacyMap::, - } - - impl ERC165 of erc165::IERC165 { - fn supports_interface(interface_id: felt) -> bool { - if interface_id == erc165::IERC165_ID { - return true; - } - supported_interfaces::read(interface_id) - } - - fn register_interface(interface_id: felt) { - assert(interface_id != erc165::INVALID_ID, 'Invalid id'); - supported_interfaces::write(interface_id, true); - } - } - - #[view] - fn supports_interface(interface_id: felt) -> bool { - ERC165::supports_interface(interface_id) - } - - #[external] - fn register_interface(interface_id: felt) { - ERC165::register_interface(interface_id) - } -} diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index ad13b042b..14f00389d 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,2 +1 @@ -mod introspection; mod tests; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 4f213d1c3..ba51ab5d3 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1 +1 @@ -mod test_erc165; +mod test_mytest; diff --git a/src/openzeppelin/tests/test_erc165.cairo b/src/openzeppelin/tests/test_erc165.cairo deleted file mode 100644 index a387dbfc3..000000000 --- a/src/openzeppelin/tests/test_erc165.cairo +++ /dev/null @@ -1,42 +0,0 @@ -use openzeppelin::introspection::erc165::ERC165Contract; -use openzeppelin::introspection::erc165::IERC165_ID; -use openzeppelin::introspection::erc165::INVALID_ID; - -const OTHER_ID: felt = 0x12345678; - - -#[test] -#[available_gas(2000000)] -fn test_default_behavior() { - let supports_default_interface: bool = ERC165Contract::supports_interface(IERC165_ID); - assert(supports_default_interface, 'Should support base interface'); -} - -#[test] -#[available_gas(2000000)] -fn test_not_registered_interface() { - let supports_unregistered_interface: bool = ERC165Contract::supports_interface(OTHER_ID); - assert(! supports_unregistered_interface, 'Should not support unregistered'); -} - -#[test] -#[available_gas(2000000)] -fn test_supports_invalid_interface() { - let supports_invalid_interface: bool = ERC165Contract::supports_interface(INVALID_ID); - assert(! supports_invalid_interface, 'Should not support invalid id'); -} - -#[test] -#[available_gas(2000000)] -fn test_register_interface() { - ERC165Contract::register_interface(OTHER_ID); - let supports_new_interface: bool = ERC165Contract::supports_interface(OTHER_ID); - assert(supports_new_interface, 'Should support new interface'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic] -fn test_register_invalid_interface() { - ERC165Contract::register_interface(INVALID_ID); -} diff --git a/src/openzeppelin/tests/test_mytest.cairo b/src/openzeppelin/tests/test_mytest.cairo new file mode 100644 index 000000000..1f5f2ca0e --- /dev/null +++ b/src/openzeppelin/tests/test_mytest.cairo @@ -0,0 +1,5 @@ +#[test] +#[available_gas(2000000)] +fn test_pass() { + assert(true, 'Should pass'); +} From 9d5079c68a91e009d51bf6d2e3920dc6d5b5f89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Tue, 7 Mar 2023 21:09:29 -0300 Subject: [PATCH 033/124] update makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 020e49482..9ed2f2af3 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ build: cargo build test: - cargo run --bin cairo-test -- --starknet --path $(dir) + cargo run --bin cairo-test -- --starknet --path src/openzeppelin format: cargo run --bin cairo-format -- --recursive $(SOURCE_FOLDER) --print-parsing-errors From ae89fa538fa58ef4959bda03e24d9c91548d730f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Wed, 8 Mar 2023 13:18:38 -0300 Subject: [PATCH 034/124] bump submodule --- cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo b/cairo index 176712e8e..903337885 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 176712e8e54404a79f42bd90251571a5d90d7250 +Subproject commit 903337885fa19e28f59988a4952d670f72b44b34 From a54e98ca74e0d2c127680f3a3ca23d4643eb0ddf Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 28 Mar 2023 08:57:20 -0400 Subject: [PATCH 035/124] Update erc20 migration branch (#586) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change the spelling of "StarkNet" to "Starknet" (#557) * fix: link (#545) * change StarkNet to Starknet --------- Co-authored-by: Eric Nordelo * add Cargo and Makefile * add deps in cairo_project, create lib * add presets * add base lib * add tests * remove old cairo lib and interface * remove unused import * fix vars * change external funcs to snake case * remove unused import * add tests for externals * add bool assertions * remove preset mods * add IERC20 trait * clean up test * remove assertion * simplify max_u256 * clarify error msg * clean up python project. ready for rust/cairo1 * add erc165 + tests * kickstart account module * re-structure project * re-structure project * re-structure project * update makefile * re-structure project * update to felt252, add use ContractAddress * formatting * remove colons from storage, remove _mint from initializer * add constructor test * add comments * fix format * check error msg in tests * set max_u256 as func * update cairo * update cargo * revert doc commit * remove __init__ * refix link --------- Co-authored-by: kongtaoxing <69096526+kongtaoxing@users.noreply.github.com> Co-authored-by: Eric Nordelo Co-authored-by: Martín Triay --- Cargo.lock | 327 ++++++++++++---- Cargo.toml | 6 +- cairo | 2 +- src/openzeppelin/lib.cairo | 1 + src/openzeppelin/tests.cairo | 2 +- src/openzeppelin/tests/test_erc20.cairo | 455 +++++++++++++++++++++++ src/openzeppelin/tests/test_mytest.cairo | 5 - src/openzeppelin/token.cairo | 1 + src/openzeppelin/token/erc20.cairo | 207 +++++++++++ 9 files changed, 918 insertions(+), 88 deletions(-) create mode 100644 src/openzeppelin/tests/test_erc20.cairo delete mode 100644 src/openzeppelin/tests/test_mytest.cairo create mode 100644 src/openzeppelin/token.cairo create mode 100644 src/openzeppelin/token/erc20.cairo diff --git a/Cargo.lock b/Cargo.lock index e6cd6443e..2094098a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" dependencies = [ "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -81,7 +81,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3ba0a3cf584a8ede533a1749b86040e9018cf752265fc39a71c69fe1fafaba5" dependencies = [ "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -93,7 +93,7 @@ dependencies = [ "num-bigint", "num-traits 0.2.15", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -106,7 +106,7 @@ dependencies = [ "num-traits 0.2.15", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -173,7 +173,7 @@ checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -196,7 +196,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -307,7 +307,7 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-utils", "env_logger", @@ -316,6 +316,7 @@ dependencies = [ "num-bigint", "num-traits 0.2.15", "pretty_assertions", + "serde", "test-case", "test-log", "thiserror", @@ -323,7 +324,7 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "anyhow", "cairo-lang-defs", @@ -347,7 +348,7 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-proc-macros", "cairo-lang-utils", @@ -358,7 +359,7 @@ dependencies = [ [[package]] name = "cairo-lang-defs" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -379,7 +380,7 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-filesystem", "cairo-lang-proc-macros", @@ -394,7 +395,7 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-utils", "env_logger", @@ -408,7 +409,7 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -421,7 +422,7 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -444,8 +445,9 @@ dependencies = [ [[package]] name = "cairo-lang-language-server" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ + "anyhow", "cairo-lang-compiler", "cairo-lang-debug", "cairo-lang-defs", @@ -460,10 +462,14 @@ dependencies = [ "cairo-lang-starknet", "cairo-lang-syntax", "cairo-lang-utils", + "indoc", + "log", "lsp-types", "salsa", + "scarb-metadata", "serde", "serde_json", + "smol_str", "test-log", "tokio", "tower-lsp", @@ -471,7 +477,7 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -486,6 +492,7 @@ dependencies = [ "cairo-lang-utils", "env_logger", "id-arena", + "indexmap", "indoc", "itertools", "log", @@ -499,7 +506,7 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -520,7 +527,7 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -543,16 +550,16 @@ dependencies = [ [[package]] name = "cairo-lang-proc-macros" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-debug", "quote", - "syn", + "syn 1.0.103", ] [[package]] name = "cairo-lang-project" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-filesystem", "indoc", @@ -565,7 +572,7 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "anyhow", "ark-ff 0.4.0-alpha.7", @@ -593,7 +600,7 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "assert_matches", "cairo-lang-debug", @@ -623,7 +630,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "assert_matches", "bimap", @@ -651,7 +658,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -666,7 +673,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -683,7 +690,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -714,8 +721,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ + "anyhow", "assert_matches", "cairo-felt", "cairo-lang-casm", @@ -738,9 +746,10 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "anyhow", + "cairo-lang-casm", "cairo-lang-compiler", "cairo-lang-defs", "cairo-lang-diagnostics", @@ -780,7 +789,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -794,7 +803,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-utils", "env_logger", @@ -806,7 +815,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-runner" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "anyhow", "cairo-felt", @@ -839,7 +848,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-utils" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "cairo-lang-utils", "env_logger", @@ -850,13 +859,18 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "chrono", "env_logger", "indexmap", "itertools", "log", + "num-bigint", + "num-integer", + "num-traits 0.2.15", + "serde", + "serde_json", "test-case", "test-log", ] @@ -890,6 +904,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "camino" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +dependencies = [ + "serde", +] + [[package]] name = "cc" version = "1.0.77" @@ -959,7 +982,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -972,7 +995,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -1132,7 +1155,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -1159,7 +1182,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 1.0.103", ] [[package]] @@ -1176,7 +1199,42 @@ checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.103", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.103", ] [[package]] @@ -1200,7 +1258,38 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.103", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.103", ] [[package]] @@ -1315,6 +1404,7 @@ checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1337,6 +1427,17 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.25" @@ -1351,7 +1452,7 @@ checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -1366,6 +1467,12 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + [[package]] name = "futures-util" version = "0.3.25" @@ -1403,7 +1510,7 @@ checksum = "40803f2757f84c877f088e62420931f6e05a72514f1f03630384aa30b91d667b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -1549,6 +1656,12 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.3.0" @@ -2058,7 +2171,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2106,7 +2219,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.103", "version_check", ] @@ -2123,18 +2236,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -2176,9 +2289,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "0.9.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -2186,9 +2299,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -2250,6 +2363,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rstest" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07f2d176c472198ec1e6551dc7da28f1c089652f66a7b722676c2238ebc0edf" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version 0.4.0", +] + +[[package]] +name = "rstest_macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.103", + "unicode-ident", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2271,7 +2410,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.16", + "semver 1.0.17", ] [[package]] @@ -2312,7 +2451,7 @@ dependencies = [ "heck 0.3.3", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2324,6 +2463,20 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scarb-metadata" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2480a9a896395a1414feebcfe8550b35f4dce0e6a437eeaa0c3d79ec938ddf42" +dependencies = [ + "camino", + "derive_builder", + "semver 1.0.17", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -2347,9 +2500,12 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] [[package]] name = "semver-parser" @@ -2362,9 +2518,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" dependencies = [ "serde_derive", ] @@ -2380,20 +2536,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.3", ] [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" dependencies = [ "itoa", "ryu", @@ -2408,7 +2564,7 @@ checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2534,7 +2690,7 @@ checksum = "6569d70430f0f6edc41f6820d00acf63356e6308046ca01e57eeac22ad258c47" dependencies = [ "starknet-curve", "starknet-ff", - "syn", + "syn 1.0.103", ] [[package]] @@ -2598,6 +2754,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -2606,7 +2773,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "unicode-xid", ] @@ -2649,7 +2816,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2660,12 +2827,12 @@ checksum = "38f0c854faeb68a048f0f2dc410c5ddae3bf83854ef0e4977d58306a5edef50e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] name = "tests" -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" dependencies = [ "assert_matches", "cairo-felt", @@ -2674,6 +2841,7 @@ dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", "cairo-lang-filesystem", + "cairo-lang-lowering", "cairo-lang-parser", "cairo-lang-plugins", "cairo-lang-runner", @@ -2690,6 +2858,7 @@ dependencies = [ "log", "num-bigint", "pretty_assertions", + "rstest", "salsa", "test-case", "test-log", @@ -2703,22 +2872,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.3", ] [[package]] @@ -2793,7 +2962,7 @@ checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2870,7 +3039,7 @@ checksum = "7ebd99eec668d0a450c177acbc4d05e0d0d13b1f8d3db13cd706c52cbec4ac04" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -3027,7 +3196,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.103", "wasm-bindgen-shared", ] @@ -3049,7 +3218,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3186,6 +3355,6 @@ checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index 4294fd6aa..107fb5d91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ members = [ ] [workspace.package] -version = "1.0.0-alpha.3" +version = "1.0.0-alpha.6" edition = "2021" repository = "https://github.com/starkware-libs/cairo/" license = "Apache-2.0" @@ -71,8 +71,10 @@ path-clean = "0.1.0" pretty_assertions = "1.2.1" proc-macro2 = "1.0" quote = "1.0.21" -rayon = "0.9.0" +rayon = "1.7.0" +rstest = "0.16.0" salsa = "0.16.1" +scarb-metadata = "1.0.1" serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0" sha3 = "0.10.6" diff --git a/cairo b/cairo index 903337885..9c190561c 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 903337885fa19e28f59988a4952d670f72b44b34 +Subproject commit 9c190561ce1e8323665857f1a77082925c817b4c diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 14f00389d..daffe3c5e 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1 +1,2 @@ +mod token; mod tests; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index ba51ab5d3..0117a1281 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1 +1 @@ -mod test_mytest; +mod test_erc20; diff --git a/src/openzeppelin/tests/test_erc20.cairo b/src/openzeppelin/tests/test_erc20.cairo new file mode 100644 index 000000000..0b4f7f230 --- /dev/null +++ b/src/openzeppelin/tests/test_erc20.cairo @@ -0,0 +1,455 @@ +use openzeppelin::token::erc20::ERC20; +use starknet::contract_address_const; +use starknet::ContractAddress; +use starknet::testing::set_caller_address; +use integer::u256; +use integer::u256_from_felt252; + +// +// Constants +// + +const NAME: felt252 = 111; +const SYMBOL: felt252 = 222; + +fn MAX_U256() -> u256 { + u256 { + low: 0xffffffffffffffffffffffffffffffff_u128, high: 0xffffffffffffffffffffffffffffffff_u128 + } +} + +// +// Helper functions +// + +fn setup() -> (ContractAddress, u256) { + let initial_supply: u256 = u256_from_felt252(2000); + let account: ContractAddress = contract_address_const::<1>(); + // Set account as default caller + set_caller_address(account); + + ERC20::constructor(NAME, SYMBOL, initial_supply, account); + (account, initial_supply) +} + +fn set_caller_as_zero() { + set_caller_address(contract_address_const::<0>()); +} + +// +// Tests +// + +#[test] +#[available_gas(2000000)] +fn test_initializer() { + ERC20::initializer(NAME, SYMBOL); + + assert(ERC20::name() == NAME, 'Name should be NAME'); + assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20::decimals() == 18_u8, 'Decimals should be 18'); + assert(ERC20::total_supply() == u256_from_felt252(0), 'Supply should eq 0'); +} + + +#[test] +#[available_gas(2000000)] +fn test_constructor() { + let initial_supply: u256 = u256_from_felt252(2000); + let account: ContractAddress = contract_address_const::<1>(); + let decimals: u8 = 18_u8; + + ERC20::constructor(NAME, SYMBOL, initial_supply, account); + + let owner_balance: u256 = ERC20::balance_of(account); + assert(owner_balance == initial_supply, 'Should eq inital_supply'); + + assert(ERC20::total_supply() == initial_supply, 'Should eq inital_supply'); + assert(ERC20::name() == NAME, 'Name should be NAME'); + assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20::decimals() == decimals, 'Decimals should be 18'); +} + +#[test] +#[available_gas(2000000)] +fn test_approve() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + let success: bool = ERC20::approve(spender, amount); + assert(success, 'Should return true'); + assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: approve from 0', ))] +fn test_approve_from_zero() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + set_caller_as_zero(); + + ERC20::approve(spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: approve to 0', ))] +fn test_approve_to_zero() { + let (owner, supply) = setup(); + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::approve(spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__approve() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::_approve(owner, spender, amount); + assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: approve from 0', ))] +fn test__approve_from_zero() { + let owner: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<1>(); + let amount: u256 = u256_from_felt252(100); + ERC20::_approve(owner, spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: approve to 0', ))] +fn test__approve_to_zero() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt252(100); + ERC20::_approve(owner, spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + let success: bool = ERC20::transfer(recipient, amount); + + assert(success, 'Should return true'); + assert(ERC20::balance_of(recipient) == amount, 'Balance should eq amount'); + assert(ERC20::balance_of(sender) == supply - amount, 'Should eq supply - amount'); + assert(ERC20::total_supply() == supply, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test__transfer() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + ERC20::_transfer(sender, recipient, amount); + + assert(ERC20::balance_of(recipient) == amount, 'Balance should eq amount'); + assert(ERC20::balance_of(sender) == supply - amount, 'Should eq supply - amount'); + assert(ERC20::total_supply() == supply, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('u256_sub Overflow', ))] +fn test__transfer_not_enough_balance() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let amount: u256 = supply + u256_from_felt252(1); + ERC20::_transfer(sender, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: transfer from 0', ))] +fn test__transfer_from_zero() { + let sender: ContractAddress = contract_address_const::<0>(); + let recipient: ContractAddress = contract_address_const::<1>(); + let amount: u256 = u256_from_felt252(100); + ERC20::_transfer(sender, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: transfer to 0', ))] +fn test__transfer_to_zero() { + let (sender, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt252(100); + ERC20::_transfer(sender, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::approve(spender, amount); + + set_caller_address(spender); + + let success: bool = ERC20::transfer_from(owner, recipient, amount); + assert(success, 'Should return true'); + + // Will dangle without setting as a var + let spender_allowance: u256 = ERC20::allowance(owner, spender); + + assert(ERC20::balance_of(recipient) == amount, 'Should eq amount'); + assert(ERC20::balance_of(owner) == supply - amount, 'Should eq suppy - amount'); + assert(spender_allowance == u256_from_felt252(0), 'Should eq 0'); + assert(ERC20::total_supply() == supply, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from_doesnt_consume_infinite_allowance() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::approve(spender, MAX_U256()); + + set_caller_address(spender); + ERC20::transfer_from(owner, recipient, amount); + + let spender_allowance: u256 = ERC20::allowance(owner, spender); + assert(spender_allowance == MAX_U256(), 'Allowance should not change'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('u256_sub Overflow', ))] +fn test_transfer_from_greater_than_allowance() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt252(100); + let amount_plus_one: u256 = amount + u256_from_felt252(1); + + ERC20::approve(spender, amount); + + set_caller_address(spender); + + ERC20::transfer_from(owner, recipient, amount_plus_one); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: transfer to 0', ))] +fn test_transfer_from_to_zero_address() { + let (owner, supply) = setup(); + + let recipient: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::approve(spender, amount); + + set_caller_address(spender); + + ERC20::transfer_from(owner, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('u256_sub Overflow', ))] +fn test_transfer_from_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let recipient: ContractAddress = contract_address_const::<2>(); + let spender: ContractAddress = contract_address_const::<3>(); + let amount: u256 = u256_from_felt252(100); + + set_caller_address(zero_address); + + ERC20::transfer_from(owner, recipient, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_increase_allowance() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::approve(spender, amount); + let success: bool = ERC20::increase_allowance(spender, amount); + assert(success, 'Should return true'); + + let spender_allowance: u256 = ERC20::allowance(owner, spender); + assert(spender_allowance == amount + amount, 'Should be amount * 2'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: approve to 0', ))] +fn test_increase_allowance_to_zero_address() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::increase_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: approve from 0', ))] +fn test_increase_allowance_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + set_caller_address(zero_address); + + ERC20::increase_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test_decrease_allowance() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::approve(spender, amount); + let success: bool = ERC20::decrease_allowance(spender, amount); + assert(success, 'Should return true'); + + let spender_allowance: u256 = ERC20::allowance(owner, spender); + assert(spender_allowance == amount - amount, 'Should be 0'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('u256_sub Overflow', ))] +fn test_decrease_allowance_to_zero_address() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::decrease_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('u256_sub Overflow', ))] +fn test_decrease_allowance_from_zero_address() { + let (owner, supply) = setup(); + + let zero_address: ContractAddress = contract_address_const::<0>(); + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + set_caller_address(zero_address); + + ERC20::decrease_allowance(spender, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__spend_allowance_not_unlimited() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::_approve(owner, spender, supply); + ERC20::_spend_allowance(owner, spender, amount); + assert(ERC20::allowance(owner, spender) == supply - amount, 'Should eq supply - amount'); +} + +#[test] +#[available_gas(2000000)] +fn test__spend_allowance_unlimited() { + let (owner, supply) = setup(); + + let spender: ContractAddress = contract_address_const::<2>(); + let max_minus_one: u256 = MAX_U256() - u256_from_felt252(1); + + ERC20::_approve(owner, spender, MAX_U256()); + ERC20::_spend_allowance(owner, spender, max_minus_one); + + assert(ERC20::allowance(owner, spender) == MAX_U256(), 'Allowance should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test__mint() { + let minter: ContractAddress = contract_address_const::<2>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::_mint(minter, amount); + + let minter_balance: u256 = ERC20::balance_of(minter); + assert(minter_balance == amount, 'Should eq amount'); + + assert(ERC20::total_supply() == amount, 'Should eq total supply'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: mint to 0', ))] +fn test__mint_to_zero() { + let minter: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::_mint(minter, amount); +} + +#[test] +#[available_gas(2000000)] +fn test__burn() { + let (owner, supply) = setup(); + + let amount: u256 = u256_from_felt252(100); + ERC20::_burn(owner, amount); + + assert(ERC20::total_supply() == supply - amount, 'Should eq supply - amount'); + assert(ERC20::balance_of(owner) == supply - amount, 'Should eq supply - amount'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('ERC20: burn from 0', ))] +fn test__burn_from_zero() { + setup(); + let zero_address: ContractAddress = contract_address_const::<0>(); + let amount: u256 = u256_from_felt252(100); + + ERC20::_burn(zero_address, amount); +} diff --git a/src/openzeppelin/tests/test_mytest.cairo b/src/openzeppelin/tests/test_mytest.cairo deleted file mode 100644 index 1f5f2ca0e..000000000 --- a/src/openzeppelin/tests/test_mytest.cairo +++ /dev/null @@ -1,5 +0,0 @@ -#[test] -#[available_gas(2000000)] -fn test_pass() { - assert(true, 'Should pass'); -} diff --git a/src/openzeppelin/token.cairo b/src/openzeppelin/token.cairo new file mode 100644 index 000000000..bfe4665e0 --- /dev/null +++ b/src/openzeppelin/token.cairo @@ -0,0 +1 @@ +mod erc20; diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo new file mode 100644 index 000000000..ad231f2d2 --- /dev/null +++ b/src/openzeppelin/token/erc20.cairo @@ -0,0 +1,207 @@ +use starknet::ContractAddress; + +trait IERC20 { + fn name() -> felt252; + fn symbol() -> felt252; + fn decimals() -> u8; + fn total_supply() -> u256; + fn balance_of(account: ContractAddress) -> u256; + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; + fn approve(spender: ContractAddress, amount: u256) -> bool; +} + +#[contract] +mod ERC20 { + use openzeppelin::token::erc20::IERC20; + use starknet::get_caller_address; + use starknet::ContractAddress; + use starknet::contract_address_const; + use starknet::ContractAddressZeroable; + use zeroable::Zeroable; + + struct Storage { + _name: felt252, + _symbol: felt252, + _total_supply: u256, + _balances: LegacyMap, + _allowances: LegacyMap<(ContractAddress, ContractAddress), u256>, + } + + #[event] + fn Transfer(from: ContractAddress, to: ContractAddress, value: u256) {} + + #[event] + fn Approval(owner: ContractAddress, spender: ContractAddress, value: u256) {} + + impl ERC20 of IERC20 { + fn name() -> felt252 { + _name::read() + } + + fn symbol() -> felt252 { + _symbol::read() + } + + fn decimals() -> u8 { + 18_u8 + } + + fn total_supply() -> u256 { + _total_supply::read() + } + + fn balance_of(account: ContractAddress) -> u256 { + _balances::read(account) + } + + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + _allowances::read((owner, spender)) + } + + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + let sender = get_caller_address(); + _transfer(sender, recipient, amount); + true + } + + fn transfer_from( + sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool { + let caller = get_caller_address(); + _spend_allowance(sender, caller, amount); + _transfer(sender, recipient, amount); + true + } + + fn approve(spender: ContractAddress, amount: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, amount); + true + } + } + + #[constructor] + fn constructor( + name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress + ) { + initializer(name, symbol); + _mint(recipient, initial_supply); + } + + #[view] + fn name() -> felt252 { + ERC20::name() + } + + #[view] + fn symbol() -> felt252 { + ERC20::symbol() + } + + #[view] + fn decimals() -> u8 { + ERC20::decimals() + } + + #[view] + fn total_supply() -> u256 { + ERC20::total_supply() + } + + #[view] + fn balance_of(account: ContractAddress) -> u256 { + ERC20::balance_of(account) + } + + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + ERC20::allowance(owner, spender) + } + + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + ERC20::transfer(recipient, amount) + } + + #[external] + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20::transfer_from(sender, recipient, amount) + } + + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool { + ERC20::approve(spender, amount) + } + + #[external] + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { + _increase_allowance(spender, added_value) + } + + #[external] + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { + _decrease_allowance(spender, subtracted_value) + } + + /// + /// Internals + /// + + fn initializer(name_: felt252, symbol_: felt252) { + _name::write(name_); + _symbol::write(symbol_); + } + + fn _increase_allowance(spender: ContractAddress, added_value: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, _allowances::read((caller, spender)) + added_value); + true + } + + fn _decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, _allowances::read((caller, spender)) - subtracted_value); + true + } + + fn _mint(recipient: ContractAddress, amount: u256) { + assert(!recipient.is_zero(), 'ERC20: mint to 0'); + _total_supply::write(_total_supply::read() + amount); + _balances::write(recipient, _balances::read(recipient) + amount); + Transfer(contract_address_const::<0>(), recipient, amount); + } + + fn _burn(account: ContractAddress, amount: u256) { + assert(!account.is_zero(), 'ERC20: burn from 0'); + _total_supply::write(_total_supply::read() - amount); + _balances::write(account, _balances::read(account) - amount); + Transfer(account, contract_address_const::<0>(), amount); + } + + fn _approve(owner: ContractAddress, spender: ContractAddress, amount: u256) { + assert(!owner.is_zero(), 'ERC20: approve from 0'); + assert(!spender.is_zero(), 'ERC20: approve to 0'); + _allowances::write((owner, spender), amount); + Approval(owner, spender, amount); + } + + fn _transfer(sender: ContractAddress, recipient: ContractAddress, amount: u256) { + assert(!sender.is_zero(), 'ERC20: transfer from 0'); + assert(!recipient.is_zero(), 'ERC20: transfer to 0'); + _balances::write(sender, _balances::read(sender) - amount); + _balances::write(recipient, _balances::read(recipient) + amount); + Transfer(sender, recipient, amount); + } + + fn _spend_allowance(owner: ContractAddress, spender: ContractAddress, amount: u256) { + let current_allowance = _allowances::read((owner, spender)); + let ONES_MASK = 0xffffffffffffffffffffffffffffffff_u128; + let is_unlimited_allowance = + current_allowance.low == ONES_MASK & current_allowance.high == ONES_MASK; + if !is_unlimited_allowance { + _approve(owner, spender, current_allowance - amount); + } + } +} From 91dcad3010fd82961347b881f09662f769e70dbe Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 31 Mar 2023 14:24:56 -0400 Subject: [PATCH 036/124] Migrate security/initializable (#592) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update cairo * fix path * add security mod * add initializable * add tests * Update src/openzeppelin/security/initializable.cairo Co-authored-by: Martín Triay * remove underscore * add internal macros --------- Co-authored-by: Martín Triay --- Makefile | 2 +- src/openzeppelin/lib.cairo | 1 + src/openzeppelin/security.cairo | 1 + src/openzeppelin/security/initializable.cairo | 17 +++++++++++++++++ src/openzeppelin/tests.cairo | 1 + src/openzeppelin/tests/test_initializable.cairo | 17 +++++++++++++++++ 6 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/openzeppelin/security.cairo create mode 100644 src/openzeppelin/security/initializable.cairo create mode 100644 src/openzeppelin/tests/test_initializable.cairo diff --git a/Makefile b/Makefile index 9ed2f2af3..7969ea043 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ build: cargo build test: - cargo run --bin cairo-test -- --starknet --path src/openzeppelin + cargo run --bin cairo-test -- --starknet --path $(SOURCE_FOLDER) format: cargo run --bin cairo-format -- --recursive $(SOURCE_FOLDER) --print-parsing-errors diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index daffe3c5e..74152ca25 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,2 +1,3 @@ +mod security; mod token; mod tests; diff --git a/src/openzeppelin/security.cairo b/src/openzeppelin/security.cairo new file mode 100644 index 000000000..c3e918b1e --- /dev/null +++ b/src/openzeppelin/security.cairo @@ -0,0 +1 @@ +mod initializable; diff --git a/src/openzeppelin/security/initializable.cairo b/src/openzeppelin/security/initializable.cairo new file mode 100644 index 000000000..80df38da6 --- /dev/null +++ b/src/openzeppelin/security/initializable.cairo @@ -0,0 +1,17 @@ +#[contract] +mod Initializable { + struct Storage { + initialized: bool, + } + + #[internal] + fn is_initialized() -> bool { + initialized::read() + } + + #[internal] + fn initialize() { + assert(!is_initialized(), 'Contract already initialized'); + initialized::write(true); + } +} diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 0117a1281..4ef4b5247 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1 +1,2 @@ mod test_erc20; +mod test_initializable; diff --git a/src/openzeppelin/tests/test_initializable.cairo b/src/openzeppelin/tests/test_initializable.cairo new file mode 100644 index 000000000..bcbb7c503 --- /dev/null +++ b/src/openzeppelin/tests/test_initializable.cairo @@ -0,0 +1,17 @@ +use openzeppelin::security::initializable::Initializable; + +#[test] +#[available_gas(2000000)] +fn test_initialize() { + assert(!Initializable::is_initialized(),'Should not be initialized'); + Initializable::initialize(); + assert(Initializable::is_initialized(),'Should be initialized'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('Contract already initialized', ))] +fn test_initialize_when_initialized() { + Initializable::initialize(); + Initializable::initialize(); +} From f48da2c00d4252204a53a5b496b445f2b87a1856 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 31 Mar 2023 20:31:00 +0200 Subject: [PATCH 037/124] Use zeroable::zero() instead of contract_address_const::<0>() (#598) * use zeroable for address * cleanup import --- src/openzeppelin/token/erc20.cairo | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo index ad231f2d2..8b84c1a1f 100644 --- a/src/openzeppelin/token/erc20.cairo +++ b/src/openzeppelin/token/erc20.cairo @@ -17,7 +17,6 @@ mod ERC20 { use openzeppelin::token::erc20::IERC20; use starknet::get_caller_address; use starknet::ContractAddress; - use starknet::contract_address_const; use starknet::ContractAddressZeroable; use zeroable::Zeroable; @@ -170,14 +169,14 @@ mod ERC20 { assert(!recipient.is_zero(), 'ERC20: mint to 0'); _total_supply::write(_total_supply::read() + amount); _balances::write(recipient, _balances::read(recipient) + amount); - Transfer(contract_address_const::<0>(), recipient, amount); + Transfer(Zeroable::zero(), recipient, amount); } fn _burn(account: ContractAddress, amount: u256) { assert(!account.is_zero(), 'ERC20: burn from 0'); _total_supply::write(_total_supply::read() - amount); _balances::write(account, _balances::read(account) - amount); - Transfer(account, contract_address_const::<0>(), amount); + Transfer(account, Zeroable::zero(), amount); } fn _approve(owner: ContractAddress, spender: ContractAddress, amount: u256) { From d671d4c849a90b9f005fef76287413d84fbf64e2 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 31 Mar 2023 14:46:10 -0400 Subject: [PATCH 038/124] Migrate security/pausable (#593) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix path * add security mod * add pausable * add mock * add tests * add security mod * update cargo * update cairo * Apply suggestions from code review Co-authored-by: Martín Triay * remove underscore from _paused * remove unused imports * add test assertion for is_paused * move mocks inside tests crate * remove underscore * add blank line --------- Co-authored-by: Martín Triay --- src/openzeppelin/security.cairo | 1 + src/openzeppelin/security/pausable.cairo | 39 +++++++++++++++ src/openzeppelin/tests.cairo | 2 + src/openzeppelin/tests/mocks.cairo | 1 + .../tests/mocks/mock_pausable.cairo | 34 ++++++++++++++ src/openzeppelin/tests/test_pausable.cairo | 47 +++++++++++++++++++ 6 files changed, 124 insertions(+) create mode 100644 src/openzeppelin/security/pausable.cairo create mode 100644 src/openzeppelin/tests/mocks.cairo create mode 100644 src/openzeppelin/tests/mocks/mock_pausable.cairo create mode 100644 src/openzeppelin/tests/test_pausable.cairo diff --git a/src/openzeppelin/security.cairo b/src/openzeppelin/security.cairo index c3e918b1e..871349507 100644 --- a/src/openzeppelin/security.cairo +++ b/src/openzeppelin/security.cairo @@ -1 +1,2 @@ +mod pausable; mod initializable; diff --git a/src/openzeppelin/security/pausable.cairo b/src/openzeppelin/security/pausable.cairo new file mode 100644 index 000000000..4fcd68384 --- /dev/null +++ b/src/openzeppelin/security/pausable.cairo @@ -0,0 +1,39 @@ +#[contract] +mod Pausable { + use starknet::ContractAddress; + use starknet::get_caller_address; + + struct Storage { + paused: bool, + } + + #[event] + fn Paused(account: ContractAddress) {} + + #[event] + fn Unpaused(account: ContractAddress) {} + + fn is_paused() -> bool { + paused::read() + } + + fn assert_not_paused() { + assert(!is_paused(), 'Pausable: paused'); + } + + fn assert_paused() { + assert(is_paused(), 'Pausable: not paused'); + } + + fn pause() { + assert_not_paused(); + paused::write(true); + Paused(get_caller_address()); + } + + fn unpause() { + assert_paused(); + paused::write(false); + Unpaused(get_caller_address()); + } +} diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 4ef4b5247..dee2e7cfa 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,2 +1,4 @@ mod test_erc20; +mod test_pausable; mod test_initializable; +mod mocks; diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo new file mode 100644 index 000000000..60df001ef --- /dev/null +++ b/src/openzeppelin/tests/mocks.cairo @@ -0,0 +1 @@ +mod mock_pausable; diff --git a/src/openzeppelin/tests/mocks/mock_pausable.cairo b/src/openzeppelin/tests/mocks/mock_pausable.cairo new file mode 100644 index 000000000..799449b4a --- /dev/null +++ b/src/openzeppelin/tests/mocks/mock_pausable.cairo @@ -0,0 +1,34 @@ +#[contract] +mod MockPausable { + use openzeppelin::security::pausable::Pausable; + + struct Storage { + counter: felt252 + } + + #[view] + fn is_paused() -> bool { + Pausable::is_paused() + } + + #[view] + fn get_count() -> felt252 { + counter::read() + } + + #[external] + fn assert_unpaused_and_increment() { + Pausable::assert_not_paused(); + counter::write(counter::read() + 1); + } + + #[external] + fn pause() { + Pausable::pause(); + } + + #[external] + fn unpause() { + Pausable::unpause(); + } +} diff --git a/src/openzeppelin/tests/test_pausable.cairo b/src/openzeppelin/tests/test_pausable.cairo new file mode 100644 index 000000000..6fe484505 --- /dev/null +++ b/src/openzeppelin/tests/test_pausable.cairo @@ -0,0 +1,47 @@ +use openzeppelin::tests::mocks::mock_pausable::MockPausable; + +#[test] +#[available_gas(2000000)] +fn test_pause_when_unpaused() { + assert(! MockPausable::is_paused(), 'Should not be paused'); + assert(MockPausable::get_count() == 0, 'Should be 0'); + MockPausable::assert_unpaused_and_increment(); + assert(MockPausable::get_count() == 1, 'Should increment'); + MockPausable::pause(); + assert(MockPausable::is_paused(), 'Should be paused'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('Pausable: paused', ))] +fn test_pause_when_paused() { + MockPausable::pause(); + MockPausable::pause(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('Pausable: paused', ))] +fn test_pause_increment() { + MockPausable::pause(); + MockPausable::assert_unpaused_and_increment(); +} + +#[test] +#[available_gas(2000000)] +fn test_unpause_when_paused() { + MockPausable::pause(); + assert(MockPausable::is_paused(), 'Should be paused'); + MockPausable::unpause(); + assert(! MockPausable::is_paused(), 'Should not be paused'); + MockPausable::assert_unpaused_and_increment(); + assert(MockPausable::get_count() == 1, 'Should increment'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('Pausable: not paused', ))] +fn test_unpause_when_unpaused() { + assert(! MockPausable::is_paused(), 'Should be unpaused'); + MockPausable::unpause(); +} From e86bcd2107b052e13c58a9af7907e1f82e427a60 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 18 Apr 2023 11:58:18 -0400 Subject: [PATCH 039/124] add utils and constants --- src/openzeppelin/lib.cairo | 1 + src/openzeppelin/utils.cairo | 1 + src/openzeppelin/utils/constants.cairo | 32 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/openzeppelin/utils.cairo create mode 100644 src/openzeppelin/utils/constants.cairo diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 74152ca25..c0f1f3ad0 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,3 +1,4 @@ mod security; mod token; mod tests; +mod utils; diff --git a/src/openzeppelin/utils.cairo b/src/openzeppelin/utils.cairo new file mode 100644 index 000000000..3709db21f --- /dev/null +++ b/src/openzeppelin/utils.cairo @@ -0,0 +1 @@ +mod constants; diff --git a/src/openzeppelin/utils/constants.cairo b/src/openzeppelin/utils/constants.cairo new file mode 100644 index 000000000..84fbe24b9 --- /dev/null +++ b/src/openzeppelin/utils/constants.cairo @@ -0,0 +1,32 @@ +// +// Interface ids +// + +// ERC165 +const IERC165_ID: u32 = 0x01ffc9a7_u32; +const INVALID_ID: u32 = 0xffffffff_u32; + +// Account +const IACCOUNT_ID: u32 = 0xa66bd575_u32; + +// ERC721 +const IERC721_ID: u32 = 0x80ac58cd_u32; +const IERC721_RECEIVER_ID: u32 = 0x150b7a02_u32; +const IERC721_METADATA_ID: u32 = 0x5b5e139f_u32; +const IERC721_ENUMERABLE_ID: u32 = 0x780e9d63_u32; + +// ERC1155 +const IERC1155_ID: u32 = 0xd9b67a26_u32; +const IERC1155_METADATA_ID: u32 = 0x0e89341c_u32; +const IERC1155_RECEIVER_ID: u32 = 0x4e2312e0_u32; +const ON_ERC1155_RECEIVED_SELECTOR: u32 = 0xf23a6e61_u32; +const ON_ERC1155_BATCH_RECEIVED_SELECTOR: u32 = 0xbc197c81_u32; + +// AccessControl +const IACCESSCONTROL_ID: u32 = 0x7965db0b_u32; + +// +// Roles +// + +const DEFAULT_ADMIN_ROLE: felt252 = 0x00; From 42a160f1f011414e5044b5174e56dcaa73876aae Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 18 Apr 2023 12:02:28 -0400 Subject: [PATCH 040/124] Revert "add utils and constants" This reverts commit e86bcd2107b052e13c58a9af7907e1f82e427a60. --- src/openzeppelin/lib.cairo | 1 - src/openzeppelin/utils.cairo | 1 - src/openzeppelin/utils/constants.cairo | 32 -------------------------- 3 files changed, 34 deletions(-) delete mode 100644 src/openzeppelin/utils.cairo delete mode 100644 src/openzeppelin/utils/constants.cairo diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index c0f1f3ad0..74152ca25 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,4 +1,3 @@ mod security; mod token; mod tests; -mod utils; diff --git a/src/openzeppelin/utils.cairo b/src/openzeppelin/utils.cairo deleted file mode 100644 index 3709db21f..000000000 --- a/src/openzeppelin/utils.cairo +++ /dev/null @@ -1 +0,0 @@ -mod constants; diff --git a/src/openzeppelin/utils/constants.cairo b/src/openzeppelin/utils/constants.cairo deleted file mode 100644 index 84fbe24b9..000000000 --- a/src/openzeppelin/utils/constants.cairo +++ /dev/null @@ -1,32 +0,0 @@ -// -// Interface ids -// - -// ERC165 -const IERC165_ID: u32 = 0x01ffc9a7_u32; -const INVALID_ID: u32 = 0xffffffff_u32; - -// Account -const IACCOUNT_ID: u32 = 0xa66bd575_u32; - -// ERC721 -const IERC721_ID: u32 = 0x80ac58cd_u32; -const IERC721_RECEIVER_ID: u32 = 0x150b7a02_u32; -const IERC721_METADATA_ID: u32 = 0x5b5e139f_u32; -const IERC721_ENUMERABLE_ID: u32 = 0x780e9d63_u32; - -// ERC1155 -const IERC1155_ID: u32 = 0xd9b67a26_u32; -const IERC1155_METADATA_ID: u32 = 0x0e89341c_u32; -const IERC1155_RECEIVER_ID: u32 = 0x4e2312e0_u32; -const ON_ERC1155_RECEIVED_SELECTOR: u32 = 0xf23a6e61_u32; -const ON_ERC1155_BATCH_RECEIVED_SELECTOR: u32 = 0xbc197c81_u32; - -// AccessControl -const IACCESSCONTROL_ID: u32 = 0x7965db0b_u32; - -// -// Roles -// - -const DEFAULT_ADMIN_ROLE: felt252 = 0x00; From 598c2324f2ff2c558f477abbec6fdb5faa43ee8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Wed, 26 Apr 2023 08:58:20 -0300 Subject: [PATCH 041/124] Migrate ERC165 (#582) * Apply suggestions from code review Co-authored-by: Andrew Fleming Co-authored-by: Hadrien Croubois * apply review suggestions * remove unused import * add internal macro * add deregister --------- Co-authored-by: Andrew Fleming Co-authored-by: Hadrien Croubois --- Cargo.lock | 12 ++--- src/openzeppelin/introspection.cairo | 1 + src/openzeppelin/introspection/erc165.cairo | 41 +++++++++++++++ src/openzeppelin/lib.cairo | 1 + src/openzeppelin/tests.cairo | 1 + src/openzeppelin/tests/test_erc165.cairo | 57 +++++++++++++++++++++ 6 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 src/openzeppelin/introspection.cairo create mode 100644 src/openzeppelin/introspection/erc165.cairo create mode 100644 src/openzeppelin/tests/test_erc165.cairo diff --git a/Cargo.lock b/Cargo.lock index 2094098a2..02e70d1c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2236,9 +2236,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" dependencies = [ "unicode-ident", ] @@ -2542,7 +2542,7 @@ checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.3", + "syn 2.0.9", ] [[package]] @@ -2756,9 +2756,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.3" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60" +checksum = "0da4a3c17e109f700685ec577c0f85efd9b19bcf15c913985f14dc1ac01775aa" dependencies = [ "proc-macro2", "quote", @@ -2887,7 +2887,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.3", + "syn 2.0.9", ] [[package]] diff --git a/src/openzeppelin/introspection.cairo b/src/openzeppelin/introspection.cairo new file mode 100644 index 000000000..4391460f4 --- /dev/null +++ b/src/openzeppelin/introspection.cairo @@ -0,0 +1 @@ +mod erc165; diff --git a/src/openzeppelin/introspection/erc165.cairo b/src/openzeppelin/introspection/erc165.cairo new file mode 100644 index 000000000..10eb980a9 --- /dev/null +++ b/src/openzeppelin/introspection/erc165.cairo @@ -0,0 +1,41 @@ +const IERC165_ID: u32 = 0x01ffc9a7_u32; +const INVALID_ID: u32 = 0xffffffff_u32; + +trait IERC165 { + fn supports_interface(interface_id: u32) -> bool; +} + +#[contract] +mod ERC165 { + use openzeppelin::introspection::erc165; + + struct Storage { + supported_interfaces: LegacyMap, + } + + impl ERC165 of erc165::IERC165 { + fn supports_interface(interface_id: u32) -> bool { + if interface_id == erc165::IERC165_ID { + return true; + } + supported_interfaces::read(interface_id) + } + } + + #[view] + fn supports_interface(interface_id: u32) -> bool { + ERC165::supports_interface(interface_id) + } + + #[internal] + fn register_interface(interface_id: u32) { + assert(interface_id != erc165::INVALID_ID, 'Invalid id'); + supported_interfaces::write(interface_id, true); + } + + #[internal] + fn deregister_interface(interface_id: u32) { + assert(interface_id != erc165::IERC165_ID, 'Invalid id'); + supported_interfaces::write(interface_id, false); + } +} diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 74152ca25..97e2a1021 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,3 +1,4 @@ +mod introspection; mod security; mod token; mod tests; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index dee2e7cfa..ac9e6b924 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,3 +1,4 @@ +mod test_erc165; mod test_erc20; mod test_pausable; mod test_initializable; diff --git a/src/openzeppelin/tests/test_erc165.cairo b/src/openzeppelin/tests/test_erc165.cairo new file mode 100644 index 000000000..79b1c40cd --- /dev/null +++ b/src/openzeppelin/tests/test_erc165.cairo @@ -0,0 +1,57 @@ +use openzeppelin::introspection::erc165::ERC165; +use openzeppelin::introspection::erc165::IERC165_ID; +use openzeppelin::introspection::erc165::INVALID_ID; + +const OTHER_ID: u32 = 0x12345678_u32; + +#[test] +#[available_gas(2000000)] +fn test_default_behavior() { + let supports_default_interface: bool = ERC165::supports_interface(IERC165_ID); + assert(supports_default_interface, 'Should support base interface'); +} + +#[test] +#[available_gas(2000000)] +fn test_not_registered_interface() { + let supports_unregistered_interface: bool = ERC165::supports_interface(OTHER_ID); + assert(! supports_unregistered_interface, 'Should not support unregistered'); +} + +#[test] +#[available_gas(2000000)] +fn test_supports_invalid_interface() { + let supports_invalid_interface: bool = ERC165::supports_interface(INVALID_ID); + assert(! supports_invalid_interface, 'Should not support invalid id'); +} + +#[test] +#[available_gas(2000000)] +fn test_register_interface() { + ERC165::register_interface(OTHER_ID); + let supports_new_interface: bool = ERC165::supports_interface(OTHER_ID); + assert(supports_new_interface, 'Should support new interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('Invalid id', ))] +fn test_register_invalid_interface() { + ERC165::register_interface(INVALID_ID); +} + +#[test] +#[available_gas(2000000)] +fn test_deregister_interface() { + ERC165::register_interface(OTHER_ID); + ERC165::deregister_interface(OTHER_ID); + let supports_old_interface: bool = ERC165::supports_interface(OTHER_ID); + assert(! supports_old_interface, 'Should not support interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected = ('Invalid id', ))] +fn test_deregister_default_interface() { + ERC165::deregister_interface(IERC165_ID); +} From b2624eed4ff3261271b2621f0316320bad0746b5 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Wed, 26 Apr 2023 13:43:08 -0400 Subject: [PATCH 042/124] Migrate constants (#611) * add utils and constants * simplify role val * add context comments for interface ids --- src/openzeppelin/lib.cairo | 1 + src/openzeppelin/utils.cairo | 1 + src/openzeppelin/utils/constants.cairo | 38 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 src/openzeppelin/utils.cairo create mode 100644 src/openzeppelin/utils/constants.cairo diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 97e2a1021..14a9204a4 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -2,3 +2,4 @@ mod introspection; mod security; mod token; mod tests; +mod utils; diff --git a/src/openzeppelin/utils.cairo b/src/openzeppelin/utils.cairo new file mode 100644 index 000000000..3709db21f --- /dev/null +++ b/src/openzeppelin/utils.cairo @@ -0,0 +1 @@ +mod constants; diff --git a/src/openzeppelin/utils/constants.cairo b/src/openzeppelin/utils/constants.cairo new file mode 100644 index 000000000..d7346bf55 --- /dev/null +++ b/src/openzeppelin/utils/constants.cairo @@ -0,0 +1,38 @@ +// +// Interface ids +// + +// ERC165 +// See: https://eips.ethereum.org/EIPS/eip-165 +const IERC165_ID: u32 = 0x01ffc9a7_u32; +const INVALID_ID: u32 = 0xffffffff_u32; + +// Account +// See: https://github.com/OpenZeppelin/cairo-contracts/pull/449#discussion_r966242914 +const IACCOUNT_ID: u32 = 0xa66bd575_u32; + +// ERC721 +// See: https://eips.ethereum.org/EIPS/eip-721 +const IERC721_ID: u32 = 0x80ac58cd_u32; +const IERC721_RECEIVER_ID: u32 = 0x150b7a02_u32; +const IERC721_METADATA_ID: u32 = 0x5b5e139f_u32; +const IERC721_ENUMERABLE_ID: u32 = 0x780e9d63_u32; + +// ERC1155 +// See: https://eips.ethereum.org/EIPS/eip-1155 +const IERC1155_ID: u32 = 0xd9b67a26_u32; +const IERC1155_METADATA_ID: u32 = 0x0e89341c_u32; +const IERC1155_RECEIVER_ID: u32 = 0x4e2312e0_u32; +const ON_ERC1155_RECEIVED_SELECTOR: u32 = 0xf23a6e61_u32; +const ON_ERC1155_BATCH_RECEIVED_SELECTOR: u32 = 0xbc197c81_u32; + +// AccessControl +// Calculated from XOR of all function selectors in IAccessControl. +// See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/IAccessControl.sol +const IACCESSCONTROL_ID: u32 = 0x7965db0b_u32; + +// +// Roles +// + +const DEFAULT_ADMIN_ROLE: felt252 = 0; From 4a4bca98998f13e93b41c7dd69e0ad305c8e77b7 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 27 Apr 2023 16:52:45 -0400 Subject: [PATCH 043/124] Set up new CI (#599) * add lint and test * fix name * add md linter * add header * remove extra line * add blank line * remove env * change name * fix on condition * change name * fix formatting * remove trailing comma in storage --- .github/workflows/coverage.yml | 52 ------------------ .github/workflows/release.yml | 41 -------------- .github/workflows/test.yml | 54 +++++++------------ .markdownlint.jsonc | 5 ++ .markdownlintrc | 8 --- PULL_REQUEST_TEMPLATE.md | 1 - SECURITY.md | 4 +- src/openzeppelin/security/initializable.cairo | 2 +- src/openzeppelin/security/pausable.cairo | 2 +- .../tests/test_initializable.cairo | 4 +- src/openzeppelin/tests/test_pausable.cairo | 6 +-- 11 files changed, 34 insertions(+), 145 deletions(-) delete mode 100644 .github/workflows/coverage.yml delete mode 100644 .github/workflows/release.yml create mode 100644 .markdownlint.jsonc delete mode 100644 .markdownlintrc diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml deleted file mode 100644 index 4aee047f0..000000000 --- a/.github/workflows/coverage.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Coverage and linter - -on: - pull_request: - workflow_dispatch: - push: - branches: - - main - -jobs: - linter: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Markdown Linter - uses: docker://avtodev/markdown-lint:v1 - with: - args: README.md CONTRIBUTING.md docs - - name: Set up Python 3.8 - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install flake8 - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - coverage: - runs-on: ubuntu-latest - needs: [linter] - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.8 - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pytest tox - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Run tests and collect coverage - run: | - tox -e coverage -- --xml - - name: Upload coverage reports to Codecov with GitHub Action - uses: codecov/codecov-action@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 4474058a5..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Build and Release - -on: - workflow_run: - workflows: [Test] - types: - - completed - -jobs: - dist: - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} - name: Build package - steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v2 - with: - python-version: "3.8" - - run: python -m pip install -U setuptools - - run: python -m pip install -e .[testing] - - name: Build package - run: tox -e build - - uses: actions/upload-artifact@v2 - with: - name: dist - path: dist - - dist_upload: - runs-on: ubuntu-latest - needs: [dist] - name: Upload to PyPi - steps: - - uses: actions/download-artifact@v2 - with: - name: dist - path: dist - - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@master - with: - user: __token__ - password: ${{ secrets.pypi_token }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d199db298..fa705adfa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,44 +1,28 @@ -name: Test +name: Lint and test on: + pull_request: + branches: + - cairo-1 push: - tags: - - "v*" + branches: + - cairo-1 jobs: - validate: + lint_and_test: + name: Lint and test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: Get commits - id: commits - run: | - echo "MAIN=$(git show -s --format="%H" origin/main)" >> $GITHUB_OUTPUT - echo "TAG=$(git rev-list -n 1 ${GITHUB_REF#refs/*/})" >> $GITHUB_OUTPUT - - name: Print commits - run: | - echo "Main commit: ${{ steps.commits.outputs.MAIN }}" - echo "Tag commit: ${{ steps.commits.outputs.TAG }}" - - name: Compare commits - if: ${{ steps.commits.outputs.MAIN != steps.commits.outputs.TAG }} - uses: actions/github-script@d556feaca394842dc55e4734bf3bb9f685482fa0 # v6.3.3 + - uses: actions/checkout@v3 with: - script: | - core.setFailed('Tagged commit does not match main') - - test: - runs-on: ubuntu-latest - needs: [validate] - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.8 - uses: actions/setup-python@v2 + submodules: recursive + - name: Markdown lint + uses: DavidAnson/markdownlint-cli2-action@5b7c9f74fec47e6b15667b2cc23c63dff11e449e # v9 with: - python-version: 3.8 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pytest tox - - name: Run tests - run: | - tox + globs: | + *.md + !PULL_REQUEST_TEMPLATE.md + - name: Cairo lint + run: make check-format + - name: Cairo test + run: make test diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc new file mode 100644 index 000000000..97c4068dc --- /dev/null +++ b/.markdownlint.jsonc @@ -0,0 +1,5 @@ +{ + // Disable line length check to enable paragraphs without internal line breaks. + // See https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md013---line-length + "MD013": false +} diff --git a/.markdownlintrc b/.markdownlintrc deleted file mode 100644 index a90ec93ab..000000000 --- a/.markdownlintrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - // Disable line length check to enable paragraphs without internal line breaks. - // See https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md013---line-length - "MD013": false, - // Disable inline HTML check to enable duplicate headers with separate ids. - // See https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md033---inline-html - "MD033": false -} diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 5d0b808a3..f751872d8 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -8,7 +8,6 @@ Fixes #??? - #### PR Checklist diff --git a/SECURITY.md b/SECURITY.md index 7c633259e..8bd19014b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,4 +1,6 @@ +# Security + > ⚠️ Warning! ⚠️ > This project is still in a very early and experimental phase. It has never been audited nor thoroughly reviewed for security vulnerabilities. Do not use in production. -Please report any security issues you find to security@openzeppelin.com. \ No newline at end of file +Please report any security issues you find to security@openzeppelin.com. diff --git a/src/openzeppelin/security/initializable.cairo b/src/openzeppelin/security/initializable.cairo index 80df38da6..00079d280 100644 --- a/src/openzeppelin/security/initializable.cairo +++ b/src/openzeppelin/security/initializable.cairo @@ -1,7 +1,7 @@ #[contract] mod Initializable { struct Storage { - initialized: bool, + initialized: bool } #[internal] diff --git a/src/openzeppelin/security/pausable.cairo b/src/openzeppelin/security/pausable.cairo index 4fcd68384..0a9018f51 100644 --- a/src/openzeppelin/security/pausable.cairo +++ b/src/openzeppelin/security/pausable.cairo @@ -4,7 +4,7 @@ mod Pausable { use starknet::get_caller_address; struct Storage { - paused: bool, + paused: bool } #[event] diff --git a/src/openzeppelin/tests/test_initializable.cairo b/src/openzeppelin/tests/test_initializable.cairo index bcbb7c503..37e1b6b78 100644 --- a/src/openzeppelin/tests/test_initializable.cairo +++ b/src/openzeppelin/tests/test_initializable.cairo @@ -3,9 +3,9 @@ use openzeppelin::security::initializable::Initializable; #[test] #[available_gas(2000000)] fn test_initialize() { - assert(!Initializable::is_initialized(),'Should not be initialized'); + assert(!Initializable::is_initialized(), 'Should not be initialized'); Initializable::initialize(); - assert(Initializable::is_initialized(),'Should be initialized'); + assert(Initializable::is_initialized(), 'Should be initialized'); } #[test] diff --git a/src/openzeppelin/tests/test_pausable.cairo b/src/openzeppelin/tests/test_pausable.cairo index 6fe484505..598f98be9 100644 --- a/src/openzeppelin/tests/test_pausable.cairo +++ b/src/openzeppelin/tests/test_pausable.cairo @@ -3,7 +3,7 @@ use openzeppelin::tests::mocks::mock_pausable::MockPausable; #[test] #[available_gas(2000000)] fn test_pause_when_unpaused() { - assert(! MockPausable::is_paused(), 'Should not be paused'); + assert(!MockPausable::is_paused(), 'Should not be paused'); assert(MockPausable::get_count() == 0, 'Should be 0'); MockPausable::assert_unpaused_and_increment(); assert(MockPausable::get_count() == 1, 'Should increment'); @@ -33,7 +33,7 @@ fn test_unpause_when_paused() { MockPausable::pause(); assert(MockPausable::is_paused(), 'Should be paused'); MockPausable::unpause(); - assert(! MockPausable::is_paused(), 'Should not be paused'); + assert(!MockPausable::is_paused(), 'Should not be paused'); MockPausable::assert_unpaused_and_increment(); assert(MockPausable::get_count() == 1, 'Should increment'); } @@ -42,6 +42,6 @@ fn test_unpause_when_paused() { #[available_gas(2000000)] #[should_panic(expected = ('Pausable: not paused', ))] fn test_unpause_when_unpaused() { - assert(! MockPausable::is_paused(), 'Should be unpaused'); + assert(!MockPausable::is_paused(), 'Should be unpaused'); MockPausable::unpause(); } From 09620519f369306bd9afe7b9870506aa415b0530 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 27 Apr 2023 22:42:24 -0400 Subject: [PATCH 044/124] fix formatting (#613) --- src/openzeppelin/introspection/erc165.cairo | 6 +++--- src/openzeppelin/tests/test_erc165.cairo | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/openzeppelin/introspection/erc165.cairo b/src/openzeppelin/introspection/erc165.cairo index 10eb980a9..16f13205a 100644 --- a/src/openzeppelin/introspection/erc165.cairo +++ b/src/openzeppelin/introspection/erc165.cairo @@ -2,7 +2,7 @@ const IERC165_ID: u32 = 0x01ffc9a7_u32; const INVALID_ID: u32 = 0xffffffff_u32; trait IERC165 { - fn supports_interface(interface_id: u32) -> bool; + fn supports_interface(interface_id: u32) -> bool; } #[contract] @@ -10,7 +10,7 @@ mod ERC165 { use openzeppelin::introspection::erc165; struct Storage { - supported_interfaces: LegacyMap, + supported_interfaces: LegacyMap } impl ERC165 of erc165::IERC165 { @@ -26,7 +26,7 @@ mod ERC165 { fn supports_interface(interface_id: u32) -> bool { ERC165::supports_interface(interface_id) } - + #[internal] fn register_interface(interface_id: u32) { assert(interface_id != erc165::INVALID_ID, 'Invalid id'); diff --git a/src/openzeppelin/tests/test_erc165.cairo b/src/openzeppelin/tests/test_erc165.cairo index 79b1c40cd..7a4efeac8 100644 --- a/src/openzeppelin/tests/test_erc165.cairo +++ b/src/openzeppelin/tests/test_erc165.cairo @@ -15,14 +15,14 @@ fn test_default_behavior() { #[available_gas(2000000)] fn test_not_registered_interface() { let supports_unregistered_interface: bool = ERC165::supports_interface(OTHER_ID); - assert(! supports_unregistered_interface, 'Should not support unregistered'); + assert(!supports_unregistered_interface, 'Should not support unregistered'); } #[test] #[available_gas(2000000)] fn test_supports_invalid_interface() { let supports_invalid_interface: bool = ERC165::supports_interface(INVALID_ID); - assert(! supports_invalid_interface, 'Should not support invalid id'); + assert(!supports_invalid_interface, 'Should not support invalid id'); } #[test] @@ -46,7 +46,7 @@ fn test_deregister_interface() { ERC165::register_interface(OTHER_ID); ERC165::deregister_interface(OTHER_ID); let supports_old_interface: bool = ERC165::supports_interface(OTHER_ID); - assert(! supports_old_interface, 'Should not support interface'); + assert(!supports_old_interface, 'Should not support interface'); } #[test] From a1950eec131bc280877fa7a90c7ade291415a76c Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 28 Apr 2023 11:34:52 -0400 Subject: [PATCH 045/124] Normalize error message style (#606) * normalize error msg * update cairo * update Cargo * fix test command * update should_panic syntax * use super for interface import --- Cargo.lock | 522 ++++++++++-------- Cargo.toml | 16 +- Makefile | 2 +- cairo | 2 +- src/openzeppelin/security/initializable.cairo | 2 +- src/openzeppelin/tests/test_erc20.cairo | 32 +- .../tests/test_initializable.cairo | 2 +- src/openzeppelin/tests/test_pausable.cairo | 6 +- src/openzeppelin/token/erc20.cairo | 2 +- 9 files changed, 329 insertions(+), 257 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02e70d1c7..e4ddc69bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -22,9 +33,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] name = "ark-ff" @@ -182,7 +193,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -205,17 +216,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "bigdecimal" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits 0.2.15", -] - [[package]] name = "bimap" version = "0.6.2" @@ -224,9 +224,9 @@ checksum = "bc0455254eb5c6964c4545d8bac815e1a1be4f3afe0ae695ea539c12d728d44b" [[package]] name = "bincode" -version = "1.3.3" +version = "2.0.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "7bb50c5a2ef4b9b1e7ae73e3a73b52ea24b20312d629f9c4df28260b7ad2c3c4" dependencies = [ "serde", ] @@ -253,12 +253,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "block-buffer" -version = "0.9.0" +name = "bitvec" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "generic-array", + "funty", + "radium", + "tap", + "wyz", ] [[package]] @@ -294,9 +297,9 @@ checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "cairo-felt" -version = "0.1.1" +version = "0.3.0-rc1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a792f409586c42c2d62cff582989e573d45b0855be95e022421d25f608364cc1" +checksum = "a93dedd19b8edf685798f1f12e4e0ac21ac196ea5262c300783f69f3fa0cb28b" dependencies = [ "lazy_static", "num-bigint", @@ -307,7 +310,7 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-utils", "env_logger", @@ -324,7 +327,7 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "anyhow", "cairo-lang-defs", @@ -339,7 +342,7 @@ dependencies = [ "cairo-lang-sierra-generator", "cairo-lang-syntax", "cairo-lang-utils", - "clap 4.0.26", + "clap", "log", "salsa", "test-log", @@ -348,7 +351,7 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-proc-macros", "cairo-lang-utils", @@ -359,7 +362,7 @@ dependencies = [ [[package]] name = "cairo-lang-defs" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -380,7 +383,7 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-filesystem", "cairo-lang-proc-macros", @@ -395,7 +398,7 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-utils", "env_logger", @@ -409,20 +412,22 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", "env_logger", "path-clean", "salsa", + "serde", + "serde_json", "smol_str", "test-log", ] [[package]] name = "cairo-lang-formatter" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -430,7 +435,7 @@ dependencies = [ "cairo-lang-parser", "cairo-lang-syntax", "cairo-lang-utils", - "clap 4.0.26", + "clap", "colored", "diffy", "ignore", @@ -445,7 +450,7 @@ dependencies = [ [[package]] name = "cairo-lang-language-server" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -477,7 +482,7 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -506,7 +511,7 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -527,7 +532,7 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -541,16 +546,17 @@ dependencies = [ "env_logger", "indoc", "itertools", - "pretty_assertions", "salsa", + "serde_json", "smol_str", "test-case", "test-log", + "unescaper", ] [[package]] name = "cairo-lang-proc-macros" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-debug", "quote", @@ -559,7 +565,7 @@ dependencies = [ [[package]] name = "cairo-lang-project" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-filesystem", "indoc", @@ -572,7 +578,7 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "anyhow", "ark-ff 0.4.0-alpha.7", @@ -588,9 +594,10 @@ dependencies = [ "cairo-lang-sierra-to-casm", "cairo-lang-utils", "cairo-vm", - "clap 4.0.26", + "clap", "itertools", "num-bigint", + "num-integer", "num-traits 0.2.15", "pretty_assertions", "salsa", @@ -600,7 +607,7 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "assert_matches", "cairo-lang-debug", @@ -630,7 +637,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "assert_matches", "bimap", @@ -658,7 +665,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -673,7 +680,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -690,7 +697,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -721,7 +728,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "anyhow", "assert_matches", @@ -731,7 +738,7 @@ dependencies = [ "cairo-lang-sierra-ap-change", "cairo-lang-sierra-gas", "cairo-lang-utils", - "clap 4.0.26", + "clap", "env_logger", "indoc", "itertools", @@ -746,7 +753,7 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "anyhow", "cairo-lang-casm", @@ -766,17 +773,17 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-test-utils", "cairo-lang-utils", - "clap 4.0.26", + "clap", "convert_case", "env_logger", "genco", "indoc", "itertools", - "lazy_static", "log", "num-bigint", "num-integer", "num-traits 0.2.15", + "once_cell", "pretty_assertions", "serde", "serde_json", @@ -789,7 +796,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -803,7 +810,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-utils", "env_logger", @@ -815,7 +822,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-runner" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "anyhow", "cairo-felt", @@ -825,6 +832,7 @@ dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", "cairo-lang-filesystem", + "cairo-lang-lowering", "cairo-lang-plugins", "cairo-lang-project", "cairo-lang-runner", @@ -836,7 +844,7 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-utils", "cairo-vm", - "clap 4.0.26", + "clap", "colored", "itertools", "num-bigint", @@ -848,7 +856,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-utils" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "cairo-lang-utils", "env_logger", @@ -859,7 +867,7 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "chrono", "env_logger", @@ -875,16 +883,28 @@ dependencies = [ "test-log", ] +[[package]] +name = "cairo-take_until_unbalanced" +version = "0.24.2-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e174056df7cfe9b579376f32de405722e1090c74deb2540bb0cd9e7931772d" +dependencies = [ + "nom", +] + [[package]] name = "cairo-vm" -version = "0.1.2" +version = "0.3.0-rc1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4fa1ade23dd2a6e671a923e748406c2c5f6c27fc186950ed04fae392b552a51" +checksum = "9f4af8c3e7be5ac46b7da4a3ab551ee4c8c8e2fdb501a4dda4dceef4c66dbcde" dependencies = [ + "anyhow", "bincode", + "bitvec", "cairo-felt", - "clap 3.2.23", + "cairo-take_until_unbalanced", "generic-array", + "hashbrown 0.13.2", "hex", "keccak", "lazy_static", @@ -893,15 +913,15 @@ dependencies = [ "num-bigint", "num-integer", "num-traits 0.2.15", - "parse-hyperlinks", "rand_core", "serde", "serde_bytes", "serde_json", - "sha2 0.10.6", + "sha2", "sha3", "starknet-crypto", "thiserror", + "thiserror-no-std", ] [[package]] @@ -940,23 +960,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "clap" -version = "3.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" -dependencies = [ - "atty", - "bitflags", - "clap_derive 3.2.18", - "clap_lex 0.2.4", - "indexmap", - "once_cell", - "strsim", - "termcolor", - "textwrap", -] - [[package]] name = "clap" version = "4.0.26" @@ -965,26 +968,13 @@ checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" dependencies = [ "atty", "bitflags", - "clap_derive 4.0.21", - "clap_lex 0.3.0", + "clap_derive", + "clap_lex", "once_cell", "strsim", "termcolor", ] -[[package]] -name = "clap_derive" -version = "3.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" -dependencies = [ - "heck 0.4.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.103", -] - [[package]] name = "clap_derive" version = "4.0.21" @@ -998,15 +988,6 @@ dependencies = [ "syn 1.0.103", ] -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - [[package]] name = "clap_lex" version = "0.3.0" @@ -1118,12 +1099,11 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.3.2" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", - "rand_core", "subtle", "zeroize", ] @@ -1138,16 +1118,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "ctor" version = "0.1.26" @@ -1244,7 +1214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.12.3", "lock_api", "once_cell", "parking_lot_core 0.9.4", @@ -1322,8 +1292,9 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.3", + "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -1375,6 +1346,27 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1396,6 +1388,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.25" @@ -1565,6 +1563,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", + "serde", +] + [[package]] name = "heck" version = "0.3.3" @@ -1589,6 +1597,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -1597,21 +1611,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - -[[package]] -name = "html-escape" -version = "0.2.13" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "utf8-width", + "digest 0.10.6", ] [[package]] @@ -1696,14 +1700,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", + "serde", ] [[package]] name = "indoc" -version = "1.0.7" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" +checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" [[package]] name = "instant" @@ -1714,6 +1719,29 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-lifetimes" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -1749,15 +1777,15 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.19.8" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" +checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87" dependencies = [ "ascii-canvas", - "atty", "bit-set", "diff", "ena", + "is-terminal", "itertools", "lalrpop-util", "petgraph", @@ -1772,9 +1800,9 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.19.8" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" +checksum = "e5c1f7869c94d214466c5fd432dfed12c379fd87786768d36455892d46b18edd" dependencies = [ "regex", ] @@ -1784,6 +1812,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1810,6 +1841,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" version = "0.4.9" @@ -1900,7 +1937,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1998,15 +2035,15 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", ] [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -2014,12 +2051,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - [[package]] name = "os_str_bytes" version = "6.4.1" @@ -2086,19 +2117,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", -] - -[[package]] -name = "parse-hyperlinks" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0181d37c4d5ae35cc8be7cf823c1a933005661da6a08bcb2855aa392c9a54b8e" -dependencies = [ - "html-escape", - "nom", - "percent-encoding", - "thiserror", + "windows-sys 0.42.0", ] [[package]] @@ -2252,6 +2271,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -2277,9 +2302,6 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] [[package]] name = "rawpointer" @@ -2354,9 +2376,9 @@ checksum = "0df32d82cedd1499386877b062ebe8721f806de80b08d183c70184ef17dd1d42" [[package]] name = "rfc6979" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ "crypto-bigint", "hmac", @@ -2413,6 +2435,20 @@ dependencies = [ "semver 1.0.17", ] +[[package]] +name = "rustix" +version = "0.36.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + [[package]] name = "rustversion" version = "1.0.9" @@ -2527,9 +2563,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" dependencies = [ "serde", ] @@ -2567,19 +2603,6 @@ dependencies = [ "syn 1.0.103", ] -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.6" @@ -2633,9 +2656,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smol_str" -version = "0.1.23" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" dependencies = [ "serde", ] @@ -2650,6 +2673,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "sprs" version = "0.7.1" @@ -2663,9 +2692,9 @@ dependencies = [ [[package]] name = "starknet-crypto" -version = "0.2.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be7d6b2c959fde2a10dbc31d54bdd0307eecb7ef6c05c23a0263e65b57b3e18a" +checksum = "d49eb65d58fa98a164ad2cd4d04775885386b83bdad6060f168a38ede77c9aed" dependencies = [ "crypto-bigint", "hex", @@ -2674,19 +2703,18 @@ dependencies = [ "num-integer", "num-traits 0.2.15", "rfc6979", - "sha2 0.9.9", + "sha2", "starknet-crypto-codegen", "starknet-curve", "starknet-ff", - "thiserror", "zeroize", ] [[package]] name = "starknet-crypto-codegen" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6569d70430f0f6edc41f6820d00acf63356e6308046ca01e57eeac22ad258c47" +checksum = "bff08f74f3ac785ac34ac05c68c5bd4df280107ab35df69dbcbde35183d89eba" dependencies = [ "starknet-curve", "starknet-ff", @@ -2695,27 +2723,23 @@ dependencies = [ [[package]] name = "starknet-curve" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84be6079d3060fdbd8b5335574fef3d3783fa2f7ee6474d08ae0c1e4b0a29ba4" +checksum = "fe0dbde7ef14d54c2117bc6d2efb68c2383005f1cd749b277c11df874d07b7af" dependencies = [ "starknet-ff", ] [[package]] name = "starknet-ff" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5874510620214ebeac50915b01d67437d8ca10a6682b1de85b93cd01157b58eb" +checksum = "78d484109da192f3a8cd58f674861c2d5e4b3e1765a466362c6f350ef213dfd1" dependencies = [ "ark-ff 0.3.0", - "bigdecimal", "crypto-bigint", "getrandom", "hex", - "num-bigint", - "serde", - "thiserror", ] [[package]] @@ -2777,6 +2801,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "term" version = "0.7.0" @@ -2832,7 +2862,7 @@ dependencies = [ [[package]] name = "tests" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" dependencies = [ "assert_matches", "cairo-felt", @@ -2857,6 +2887,7 @@ dependencies = [ "itertools", "log", "num-bigint", + "once_cell", "pretty_assertions", "rstest", "salsa", @@ -2864,12 +2895,6 @@ dependencies = [ "test-log", ] -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" version = "1.0.40" @@ -2890,6 +2915,26 @@ dependencies = [ "syn 2.0.9", ] +[[package]] +name = "thiserror-impl-no-std" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + +[[package]] +name = "thiserror-no-std" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" +dependencies = [ + "thiserror-impl-no-std", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -3140,12 +3185,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf8-width" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" - [[package]] name = "version_check" version = "0.9.4" @@ -3275,47 +3314,80 @@ dependencies = [ "windows_x86_64_msvc", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "wyz" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] [[package]] name = "xshell" diff --git a/Cargo.toml b/Cargo.toml index 107fb5d91..bb3d92a73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ members = [ ] [workspace.package] -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.7" edition = "2021" repository = "https://github.com/starkware-libs/cairo/" license = "Apache-2.0" @@ -43,8 +43,8 @@ ark-ff = "0.4.0-alpha.7" ark-std = "0.3.0" assert_matches = "1.5" bimap = "0.6.2" -cairo-felt = "0.1.1" -cairo-vm = "0.1.2" +cairo-felt = "0.3.0-rc1" +cairo-vm = "0.3.0-rc1" chrono = "0.4.23" clap = { version = "4.0", features = ["derive"] } colored = "2" @@ -57,16 +57,16 @@ genco = "0.17.0" good_lp = { version = "1.3.2", features = ["minilp"], default-features = false } id-arena = "2.2.1" ignore = "0.4.20" -indexmap = "1.9.1" -indoc = "1.0.7" +indexmap = { version = "1.9.1", features = ["serde"] } +indoc = "2.0.1" itertools = "0.10.3" -lalrpop-util = { version = "0.19.8", features = ["lexer"] } -lazy_static = "1.4.0" +lalrpop-util = { version = "0.19.9", features = ["lexer"] } log = "0.4" lsp = { version = "0.93", package = "lsp-types" } num-bigint = "0.4" num-integer = "0.1" num-traits = "0.2" +once_cell = "1.17.1" path-clean = "0.1.0" pretty_assertions = "1.2.1" proc-macro2 = "1.0" @@ -78,7 +78,7 @@ scarb-metadata = "1.0.1" serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0" sha3 = "0.10.6" -smol_str = "0.1.23" +smol_str = { version = "0.2.0", features = ["serde"] } syn = { version = "1.0.99", features = ["full", "extra-traits"] } test-case = "2.2.2" test-case-macros = "2.2.2" diff --git a/Makefile b/Makefile index 7969ea043..0ed75752e 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ build: cargo build test: - cargo run --bin cairo-test -- --starknet --path $(SOURCE_FOLDER) + cargo run --bin cairo-test -- --starknet $(SOURCE_FOLDER) format: cargo run --bin cairo-format -- --recursive $(SOURCE_FOLDER) --print-parsing-errors diff --git a/cairo b/cairo index 9c190561c..81c4eb942 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 9c190561ce1e8323665857f1a77082925c817b4c +Subproject commit 81c4eb942dace6849a8067dc43263da99579bef8 diff --git a/src/openzeppelin/security/initializable.cairo b/src/openzeppelin/security/initializable.cairo index 00079d280..8485238bb 100644 --- a/src/openzeppelin/security/initializable.cairo +++ b/src/openzeppelin/security/initializable.cairo @@ -11,7 +11,7 @@ mod Initializable { #[internal] fn initialize() { - assert(!is_initialized(), 'Contract already initialized'); + assert(!is_initialized(), 'Initializable: is initialized'); initialized::write(true); } } diff --git a/src/openzeppelin/tests/test_erc20.cairo b/src/openzeppelin/tests/test_erc20.cairo index 0b4f7f230..04fb5fcf1 100644 --- a/src/openzeppelin/tests/test_erc20.cairo +++ b/src/openzeppelin/tests/test_erc20.cairo @@ -84,7 +84,7 @@ fn test_approve() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: approve from 0', ))] +#[should_panic(expected: ('ERC20: approve from 0', ))] fn test_approve_from_zero() { let (owner, supply) = setup(); let spender: ContractAddress = contract_address_const::<2>(); @@ -97,7 +97,7 @@ fn test_approve_from_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: approve to 0', ))] +#[should_panic(expected: ('ERC20: approve to 0', ))] fn test_approve_to_zero() { let (owner, supply) = setup(); let spender: ContractAddress = contract_address_const::<0>(); @@ -120,7 +120,7 @@ fn test__approve() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: approve from 0', ))] +#[should_panic(expected: ('ERC20: approve from 0', ))] fn test__approve_from_zero() { let owner: ContractAddress = contract_address_const::<0>(); let spender: ContractAddress = contract_address_const::<1>(); @@ -130,7 +130,7 @@ fn test__approve_from_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: approve to 0', ))] +#[should_panic(expected: ('ERC20: approve to 0', ))] fn test__approve_to_zero() { let (owner, supply) = setup(); @@ -170,7 +170,7 @@ fn test__transfer() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow', ))] fn test__transfer_not_enough_balance() { let (sender, supply) = setup(); @@ -181,7 +181,7 @@ fn test__transfer_not_enough_balance() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: transfer from 0', ))] +#[should_panic(expected: ('ERC20: transfer from 0', ))] fn test__transfer_from_zero() { let sender: ContractAddress = contract_address_const::<0>(); let recipient: ContractAddress = contract_address_const::<1>(); @@ -191,7 +191,7 @@ fn test__transfer_from_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: transfer to 0', ))] +#[should_panic(expected: ('ERC20: transfer to 0', ))] fn test__transfer_to_zero() { let (sender, supply) = setup(); @@ -245,7 +245,7 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow', ))] fn test_transfer_from_greater_than_allowance() { let (owner, supply) = setup(); @@ -263,7 +263,7 @@ fn test_transfer_from_greater_than_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: transfer to 0', ))] +#[should_panic(expected: ('ERC20: transfer to 0', ))] fn test_transfer_from_to_zero_address() { let (owner, supply) = setup(); @@ -280,7 +280,7 @@ fn test_transfer_from_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow', ))] fn test_transfer_from_from_zero_address() { let (owner, supply) = setup(); @@ -312,7 +312,7 @@ fn test_increase_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: approve to 0', ))] +#[should_panic(expected: ('ERC20: approve to 0', ))] fn test_increase_allowance_to_zero_address() { let (owner, supply) = setup(); @@ -324,7 +324,7 @@ fn test_increase_allowance_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: approve from 0', ))] +#[should_panic(expected: ('ERC20: approve from 0', ))] fn test_increase_allowance_from_zero_address() { let (owner, supply) = setup(); @@ -355,7 +355,7 @@ fn test_decrease_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow', ))] fn test_decrease_allowance_to_zero_address() { let (owner, supply) = setup(); @@ -367,7 +367,7 @@ fn test_decrease_allowance_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow', ))] fn test_decrease_allowance_from_zero_address() { let (owner, supply) = setup(); @@ -423,7 +423,7 @@ fn test__mint() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: mint to 0', ))] +#[should_panic(expected: ('ERC20: mint to 0', ))] fn test__mint_to_zero() { let minter: ContractAddress = contract_address_const::<0>(); let amount: u256 = u256_from_felt252(100); @@ -445,7 +445,7 @@ fn test__burn() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('ERC20: burn from 0', ))] +#[should_panic(expected: ('ERC20: burn from 0', ))] fn test__burn_from_zero() { setup(); let zero_address: ContractAddress = contract_address_const::<0>(); diff --git a/src/openzeppelin/tests/test_initializable.cairo b/src/openzeppelin/tests/test_initializable.cairo index 37e1b6b78..cfd7ec003 100644 --- a/src/openzeppelin/tests/test_initializable.cairo +++ b/src/openzeppelin/tests/test_initializable.cairo @@ -10,7 +10,7 @@ fn test_initialize() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('Contract already initialized', ))] +#[should_panic(expected: ('Initializable: is initialized', ))] fn test_initialize_when_initialized() { Initializable::initialize(); Initializable::initialize(); diff --git a/src/openzeppelin/tests/test_pausable.cairo b/src/openzeppelin/tests/test_pausable.cairo index 598f98be9..6b76e9375 100644 --- a/src/openzeppelin/tests/test_pausable.cairo +++ b/src/openzeppelin/tests/test_pausable.cairo @@ -13,7 +13,7 @@ fn test_pause_when_unpaused() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('Pausable: paused', ))] +#[should_panic(expected: ('Pausable: paused', ))] fn test_pause_when_paused() { MockPausable::pause(); MockPausable::pause(); @@ -21,7 +21,7 @@ fn test_pause_when_paused() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('Pausable: paused', ))] +#[should_panic(expected: ('Pausable: paused', ))] fn test_pause_increment() { MockPausable::pause(); MockPausable::assert_unpaused_and_increment(); @@ -40,7 +40,7 @@ fn test_unpause_when_paused() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('Pausable: not paused', ))] +#[should_panic(expected: ('Pausable: not paused', ))] fn test_unpause_when_unpaused() { assert(!MockPausable::is_paused(), 'Should be unpaused'); MockPausable::unpause(); diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo index 8b84c1a1f..f0b63d59d 100644 --- a/src/openzeppelin/token/erc20.cairo +++ b/src/openzeppelin/token/erc20.cairo @@ -14,7 +14,7 @@ trait IERC20 { #[contract] mod ERC20 { - use openzeppelin::token::erc20::IERC20; + use super::IERC20; use starknet::get_caller_address; use starknet::ContractAddress; use starknet::ContractAddressZeroable; From c29b45cf69232c469ac2c90da572149f707a025f Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 28 Apr 2023 12:57:45 -0400 Subject: [PATCH 046/124] Add `BoundedInt` and internal macros, update cairo (#600) * update cairo * update Cargo * remove path flag * refactor _spend_allowance with BoundedInt * add BoundedInt for u256_max * add internal macros * update cairo * update cairo * update Cargo * remove import * update expected syntax * remove redundant maxu256 fn * update expected syntax * Update src/openzeppelin/tests/test_erc20.cairo Co-authored-by: Hadrien Croubois * use into trait * use address zeroable in mod * set cairo to alpha7 * update Cargo --------- Co-authored-by: Hadrien Croubois --- src/openzeppelin/tests/test_erc165.cairo | 4 ++-- src/openzeppelin/tests/test_erc20.cairo | 18 +++++++----------- src/openzeppelin/token/erc20.cairo | 14 ++++++++++---- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/openzeppelin/tests/test_erc165.cairo b/src/openzeppelin/tests/test_erc165.cairo index 7a4efeac8..c66c1b034 100644 --- a/src/openzeppelin/tests/test_erc165.cairo +++ b/src/openzeppelin/tests/test_erc165.cairo @@ -35,7 +35,7 @@ fn test_register_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('Invalid id', ))] +#[should_panic(expected: ('Invalid id', ))] fn test_register_invalid_interface() { ERC165::register_interface(INVALID_ID); } @@ -51,7 +51,7 @@ fn test_deregister_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected = ('Invalid id', ))] +#[should_panic(expected: ('Invalid id', ))] fn test_deregister_default_interface() { ERC165::deregister_interface(IERC165_ID); } diff --git a/src/openzeppelin/tests/test_erc20.cairo b/src/openzeppelin/tests/test_erc20.cairo index 04fb5fcf1..5c5615990 100644 --- a/src/openzeppelin/tests/test_erc20.cairo +++ b/src/openzeppelin/tests/test_erc20.cairo @@ -4,6 +4,8 @@ use starknet::ContractAddress; use starknet::testing::set_caller_address; use integer::u256; use integer::u256_from_felt252; +use integer::BoundedInt; +use traits::Into; // // Constants @@ -12,12 +14,6 @@ use integer::u256_from_felt252; const NAME: felt252 = 111; const SYMBOL: felt252 = 222; -fn MAX_U256() -> u256 { - u256 { - low: 0xffffffffffffffffffffffffffffffff_u128, high: 0xffffffffffffffffffffffffffffffff_u128 - } -} - // // Helper functions // @@ -234,13 +230,13 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { let spender: ContractAddress = contract_address_const::<3>(); let amount: u256 = u256_from_felt252(100); - ERC20::approve(spender, MAX_U256()); + ERC20::approve(spender, BoundedInt::max()); set_caller_address(spender); ERC20::transfer_from(owner, recipient, amount); let spender_allowance: u256 = ERC20::allowance(owner, spender); - assert(spender_allowance == MAX_U256(), 'Allowance should not change'); + assert(spender_allowance == BoundedInt::max(), 'Allowance should not change'); } #[test] @@ -399,12 +395,12 @@ fn test__spend_allowance_unlimited() { let (owner, supply) = setup(); let spender: ContractAddress = contract_address_const::<2>(); - let max_minus_one: u256 = MAX_U256() - u256_from_felt252(1); + let max_minus_one: u256 = BoundedInt::max() - 1.into(); - ERC20::_approve(owner, spender, MAX_U256()); + ERC20::_approve(owner, spender, BoundedInt::max()); ERC20::_spend_allowance(owner, spender, max_minus_one); - assert(ERC20::allowance(owner, spender) == MAX_U256(), 'Allowance should not change'); + assert(ERC20::allowance(owner, spender) == BoundedInt::max(), 'Allowance should not change'); } #[test] diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo index f0b63d59d..c53fdbbe4 100644 --- a/src/openzeppelin/token/erc20.cairo +++ b/src/openzeppelin/token/erc20.cairo @@ -19,6 +19,7 @@ mod ERC20 { use starknet::ContractAddress; use starknet::ContractAddressZeroable; use zeroable::Zeroable; + use integer::BoundedInt; struct Storage { _name: felt252, @@ -148,23 +149,27 @@ mod ERC20 { /// Internals /// + #[internal] fn initializer(name_: felt252, symbol_: felt252) { _name::write(name_); _symbol::write(symbol_); } + #[internal] fn _increase_allowance(spender: ContractAddress, added_value: u256) -> bool { let caller = get_caller_address(); _approve(caller, spender, _allowances::read((caller, spender)) + added_value); true } + #[internal] fn _decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { let caller = get_caller_address(); _approve(caller, spender, _allowances::read((caller, spender)) - subtracted_value); true } + #[internal] fn _mint(recipient: ContractAddress, amount: u256) { assert(!recipient.is_zero(), 'ERC20: mint to 0'); _total_supply::write(_total_supply::read() + amount); @@ -172,6 +177,7 @@ mod ERC20 { Transfer(Zeroable::zero(), recipient, amount); } + #[internal] fn _burn(account: ContractAddress, amount: u256) { assert(!account.is_zero(), 'ERC20: burn from 0'); _total_supply::write(_total_supply::read() - amount); @@ -179,6 +185,7 @@ mod ERC20 { Transfer(account, Zeroable::zero(), amount); } + #[internal] fn _approve(owner: ContractAddress, spender: ContractAddress, amount: u256) { assert(!owner.is_zero(), 'ERC20: approve from 0'); assert(!spender.is_zero(), 'ERC20: approve to 0'); @@ -186,6 +193,7 @@ mod ERC20 { Approval(owner, spender, amount); } + #[internal] fn _transfer(sender: ContractAddress, recipient: ContractAddress, amount: u256) { assert(!sender.is_zero(), 'ERC20: transfer from 0'); assert(!recipient.is_zero(), 'ERC20: transfer to 0'); @@ -194,12 +202,10 @@ mod ERC20 { Transfer(sender, recipient, amount); } + #[internal] fn _spend_allowance(owner: ContractAddress, spender: ContractAddress, amount: u256) { let current_allowance = _allowances::read((owner, spender)); - let ONES_MASK = 0xffffffffffffffffffffffffffffffff_u128; - let is_unlimited_allowance = - current_allowance.low == ONES_MASK & current_allowance.high == ONES_MASK; - if !is_unlimited_allowance { + if current_allowance != BoundedInt::max() { _approve(owner, spender, current_allowance - amount); } } From e48a68291d2b878ed683bcbb39cf7a3eb96c20ac Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 11 May 2023 18:12:21 -0400 Subject: [PATCH 047/124] Migrate ownable (#604) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add ownable * add ownable tests * simplify renounce * fix formatting * add internal macros * Apply suggestions from code review Co-authored-by: Martín Triay * add test_transfer_ownership_from_zero * update cairo to alpha7 * update Cargo * fix expected syntax * update cairo to rc0 * update Cargo * fix import * simplify imports * Apply suggestions from code review Co-authored-by: Eric Nordelo * Update src/openzeppelin/token/erc20.cairo Co-authored-by: Eric Nordelo * fix set_caller_address --------- Co-authored-by: Martín Triay Co-authored-by: Eric Nordelo --- Cargo.lock | 263 +++++++--------------- Cargo.toml | 13 +- cairo | 2 +- src/openzeppelin/access.cairo | 1 + src/openzeppelin/access/ownable.cairo | 52 +++++ src/openzeppelin/lib.cairo | 1 + src/openzeppelin/tests.cairo | 1 + src/openzeppelin/tests/test_ownable.cairo | 90 ++++++++ src/openzeppelin/token/erc20.cairo | 5 +- 9 files changed, 239 insertions(+), 189 deletions(-) create mode 100644 src/openzeppelin/access.cairo create mode 100644 src/openzeppelin/access/ownable.cairo create mode 100644 src/openzeppelin/tests/test_ownable.cairo diff --git a/Cargo.lock b/Cargo.lock index e4ddc69bf..85aa935ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,15 +22,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anyhow" version = "1.0.70" @@ -310,7 +301,7 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-utils", "env_logger", @@ -327,7 +318,7 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "anyhow", "cairo-lang-defs", @@ -345,13 +336,14 @@ dependencies = [ "clap", "log", "salsa", + "smol_str", "test-log", "thiserror", ] [[package]] name = "cairo-lang-debug" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-proc-macros", "cairo-lang-utils", @@ -362,7 +354,7 @@ dependencies = [ [[package]] name = "cairo-lang-defs" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -383,7 +375,7 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-filesystem", "cairo-lang-proc-macros", @@ -398,7 +390,7 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-utils", "env_logger", @@ -412,7 +404,7 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -427,7 +419,7 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -450,7 +442,7 @@ dependencies = [ [[package]] name = "cairo-lang-language-server" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -482,7 +474,7 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -511,7 +503,7 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -523,16 +515,19 @@ dependencies = [ "env_logger", "itertools", "log", + "num-bigint", + "num-traits 0.2.15", "pretty_assertions", "salsa", "smol_str", "test-case", "test-log", + "unescaper", ] [[package]] name = "cairo-lang-plugins" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -551,12 +546,11 @@ dependencies = [ "smol_str", "test-case", "test-log", - "unescaper", ] [[package]] name = "cairo-lang-proc-macros" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-debug", "quote", @@ -565,7 +559,7 @@ dependencies = [ [[package]] name = "cairo-lang-project" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-filesystem", "indoc", @@ -578,7 +572,7 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "anyhow", "ark-ff 0.4.0-alpha.7", @@ -586,16 +580,22 @@ dependencies = [ "cairo-felt", "cairo-lang-casm", "cairo-lang-compiler", + "cairo-lang-defs", "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-lowering", + "cairo-lang-semantic", "cairo-lang-sierra", "cairo-lang-sierra-ap-change", "cairo-lang-sierra-gas", "cairo-lang-sierra-generator", "cairo-lang-sierra-to-casm", + "cairo-lang-starknet", "cairo-lang-utils", "cairo-vm", "clap", "itertools", + "keccak", "num-bigint", "num-integer", "num-traits 0.2.15", @@ -607,7 +607,7 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "assert_matches", "cairo-lang-debug", @@ -632,12 +632,11 @@ dependencies = [ "smol_str", "test-case", "test-log", - "unescaper", ] [[package]] name = "cairo-lang-sierra" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "assert_matches", "bimap", @@ -665,7 +664,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -680,7 +679,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -697,7 +696,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -728,7 +727,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "anyhow", "assert_matches", @@ -753,9 +752,10 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "anyhow", + "cairo-felt", "cairo-lang-casm", "cairo-lang-compiler", "cairo-lang-defs", @@ -796,21 +796,25 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", "cairo-lang-utils", "env_logger", + "num-bigint", + "num-traits 0.2.15", "pretty_assertions", "salsa", "smol_str", "test-log", + "thiserror", + "unescaper", ] [[package]] name = "cairo-lang-syntax-codegen" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-utils", "env_logger", @@ -822,7 +826,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-runner" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "anyhow", "cairo-felt", @@ -848,15 +852,15 @@ dependencies = [ "colored", "itertools", "num-bigint", + "num-traits 0.2.15", "rayon", "salsa", "thiserror", - "unescaper", ] [[package]] name = "cairo-lang-test-utils" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "cairo-lang-utils", "env_logger", @@ -867,9 +871,8 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ - "chrono", "env_logger", "indexmap", "itertools", @@ -881,6 +884,7 @@ dependencies = [ "serde_json", "test-case", "test-log", + "time", ] [[package]] @@ -945,21 +949,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits 0.2.15", - "time", - "wasm-bindgen", - "winapi", -] - [[package]] name = "clap" version = "4.0.26" @@ -997,16 +986,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "colored" version = "2.0.0" @@ -1033,12 +1012,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - [[package]] name = "cpufeatures" version = "0.2.5" @@ -1128,50 +1101,6 @@ dependencies = [ "syn 1.0.103", ] -[[package]] -name = "cxx" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 1.0.103", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - [[package]] name = "darling" version = "0.14.4" @@ -1530,7 +1459,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1630,30 +1559,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "iana-time-zone" -version = "0.1.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - [[package]] name = "id-arena" version = "2.2.1" @@ -1832,15 +1737,6 @@ dependencies = [ "libc", ] -[[package]] -name = "link-cplusplus" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" -dependencies = [ - "cc", -] - [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -1936,7 +1832,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.42.0", ] @@ -2039,6 +1935,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -2255,9 +2160,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.53" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" dependencies = [ "unicode-ident", ] @@ -2519,12 +2424,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" - [[package]] name = "semver" version = "0.11.0" @@ -2578,7 +2477,7 @@ checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.3", ] [[package]] @@ -2780,9 +2679,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.9" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da4a3c17e109f700685ec577c0f85efd9b19bcf15c913985f14dc1ac01775aa" +checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60" dependencies = [ "proc-macro2", "quote", @@ -2862,7 +2761,7 @@ dependencies = [ [[package]] name = "tests" -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" dependencies = [ "assert_matches", "cairo-felt", @@ -2912,7 +2811,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.3", ] [[package]] @@ -2946,13 +2845,31 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ + "itoa", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +dependencies = [ + "time-core", ] [[package]] @@ -3161,12 +3078,6 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - [[package]] name = "unicode-xid" version = "0.2.4" @@ -3202,12 +3113,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index bb3d92a73..49e71907f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,10 +3,8 @@ members = [ "cairo/crates/cairo-lang-casm", "cairo/crates/cairo-lang-compiler", - "cairo/crates/cairo-lang-utils", "cairo/crates/cairo-lang-debug", "cairo/crates/cairo-lang-defs", - "cairo/crates/cairo-lang-proc-macros", "cairo/crates/cairo-lang-diagnostics", "cairo/crates/cairo-lang-eq-solver", "cairo/crates/cairo-lang-filesystem", @@ -15,23 +13,25 @@ members = [ "cairo/crates/cairo-lang-lowering", "cairo/crates/cairo-lang-parser", "cairo/crates/cairo-lang-plugins", + "cairo/crates/cairo-lang-proc-macros", "cairo/crates/cairo-lang-project", "cairo/crates/cairo-lang-runner", "cairo/crates/cairo-lang-semantic", + "cairo/crates/cairo-lang-sierra", "cairo/crates/cairo-lang-sierra-ap-change", "cairo/crates/cairo-lang-sierra-gas", "cairo/crates/cairo-lang-sierra-generator", "cairo/crates/cairo-lang-sierra-to-casm", - "cairo/crates/cairo-lang-sierra", "cairo/crates/cairo-lang-starknet", - "cairo/crates/cairo-lang-syntax-codegen", "cairo/crates/cairo-lang-syntax", + "cairo/crates/cairo-lang-syntax-codegen", "cairo/crates/cairo-lang-test-runner", + "cairo/crates/cairo-lang-utils", "cairo/tests", ] [workspace.package] -version = "1.0.0-alpha.7" +version = "1.0.0-rc0" edition = "2021" repository = "https://github.com/starkware-libs/cairo/" license = "Apache-2.0" @@ -45,7 +45,6 @@ assert_matches = "1.5" bimap = "0.6.2" cairo-felt = "0.3.0-rc1" cairo-vm = "0.3.0-rc1" -chrono = "0.4.23" clap = { version = "4.0", features = ["derive"] } colored = "2" const-fnv1a-hash = "1.1.0" @@ -60,6 +59,7 @@ ignore = "0.4.20" indexmap = { version = "1.9.1", features = ["serde"] } indoc = "2.0.1" itertools = "0.10.3" +keccak = "0.1.3" lalrpop-util = { version = "0.19.9", features = ["lexer"] } log = "0.4" lsp = { version = "0.93", package = "lsp-types" } @@ -84,6 +84,7 @@ test-case = "2.2.2" test-case-macros = "2.2.2" test-log = "0.2.11" thiserror = "1.0.32" +time = { version = "0.3.20", features = ["formatting", "macros", "local-offset"] } tokio = { version = "1.18.2", features = ["full", "sync"] } toml = "0.4.2" tower-lsp = "0.17.0" diff --git a/cairo b/cairo index 81c4eb942..05867c82d 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 81c4eb942dace6849a8067dc43263da99579bef8 +Subproject commit 05867c82de42d5ee5cfa953dcca1cb826402f74b diff --git a/src/openzeppelin/access.cairo b/src/openzeppelin/access.cairo new file mode 100644 index 000000000..cadc81b51 --- /dev/null +++ b/src/openzeppelin/access.cairo @@ -0,0 +1 @@ +mod ownable; diff --git a/src/openzeppelin/access/ownable.cairo b/src/openzeppelin/access/ownable.cairo new file mode 100644 index 000000000..69bf5b2b1 --- /dev/null +++ b/src/openzeppelin/access/ownable.cairo @@ -0,0 +1,52 @@ +#[contract] +mod Ownable { + use starknet::ContractAddress; + use starknet::get_caller_address; + use zeroable::Zeroable; + + struct Storage { + _owner: ContractAddress + } + + #[event] + fn OwnershipTransferred(previous_owner: ContractAddress, new_owner: ContractAddress) {} + + #[internal] + fn initializer() { + let caller: ContractAddress = get_caller_address(); + _transfer_ownership(caller); + } + + #[internal] + fn assert_only_owner() { + let owner: ContractAddress = _owner::read(); + let caller: ContractAddress = get_caller_address(); + assert(!caller.is_zero(), 'Caller is the zero address'); + assert(caller == owner, 'Caller is not the owner'); + } + + #[internal] + fn owner() -> ContractAddress { + _owner::read() + } + + #[internal] + fn transfer_ownership(new_owner: ContractAddress) { + assert(!new_owner.is_zero(), 'New owner is the zero address'); + assert_only_owner(); + _transfer_ownership(new_owner); + } + + #[internal] + fn renounce_ownership() { + assert_only_owner(); + _transfer_ownership(Zeroable::zero()); + } + + #[internal] + fn _transfer_ownership(new_owner: ContractAddress) { + let previous_owner: ContractAddress = _owner::read(); + _owner::write(new_owner); + OwnershipTransferred(previous_owner, new_owner); + } +} diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 14a9204a4..1f55a830f 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,3 +1,4 @@ +mod access; mod introspection; mod security; mod token; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index ac9e6b924..df1dcba06 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,3 +1,4 @@ +mod test_ownable; mod test_erc165; mod test_erc20; mod test_pausable; diff --git a/src/openzeppelin/tests/test_ownable.cairo b/src/openzeppelin/tests/test_ownable.cairo new file mode 100644 index 000000000..424cc0546 --- /dev/null +++ b/src/openzeppelin/tests/test_ownable.cairo @@ -0,0 +1,90 @@ +use openzeppelin::access::ownable::Ownable; + +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing; +use zeroable::Zeroable; + +fn ZERO() -> ContractAddress { + contract_address_const::<0>() +} + +fn OWNER() -> ContractAddress { + contract_address_const::<1>() +} + +fn OTHER() -> ContractAddress { + contract_address_const::<2>() +} + +fn setup() { + testing::set_caller_address(OWNER()); + Ownable::initializer(); +} + +#[test] +#[available_gas(2000000)] +fn test_initializer() { + assert(Ownable::owner().is_zero(), 'Should be zero'); + setup(); + assert(Ownable::owner() == OWNER(), 'Owner should be set'); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_ownership() { + setup(); + Ownable::transfer_ownership(OTHER()); + assert(Ownable::owner() == OTHER(), 'Should transfer ownership'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('New owner is the zero address', ))] +fn test_transfer_ownership_to_zero() { + setup(); + Ownable::transfer_ownership(ZERO()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is the zero address', ))] +fn test_transfer_ownership_from_zero() { + assert(Ownable::owner() == ZERO(), 'Should be zero with no owner'); + Ownable::transfer_ownership(OTHER()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is not the owner', ))] +fn test_transfer_ownership_from_nonowner() { + setup(); + testing::set_caller_address(OTHER()); + Ownable::transfer_ownership(OTHER()); +} + +#[test] +#[available_gas(2000000)] +fn test_renounce_ownership() { + setup(); + Ownable::renounce_ownership(); + assert(Ownable::owner() == ZERO(), 'Should renounce ownership'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is the zero address', ))] +fn test_renounce_ownership_from_zero_address() { + setup(); + testing::set_caller_address(ZERO()); + Ownable::renounce_ownership(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is not the owner', ))] +fn test_renounce_ownership_from_nonowner() { + setup(); + testing::set_caller_address(OTHER()); + Ownable::renounce_ownership(); +} diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo index c53fdbbe4..f2350bebc 100644 --- a/src/openzeppelin/token/erc20.cairo +++ b/src/openzeppelin/token/erc20.cairo @@ -15,11 +15,10 @@ trait IERC20 { #[contract] mod ERC20 { use super::IERC20; - use starknet::get_caller_address; + use integer::BoundedInt; use starknet::ContractAddress; - use starknet::ContractAddressZeroable; + use starknet::get_caller_address; use zeroable::Zeroable; - use integer::BoundedInt; struct Storage { _name: felt252, From 5f86f65b564752ec43aa9cd53b51b85761a24484 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 19 May 2023 16:46:06 -0400 Subject: [PATCH 048/124] Migrate security/reentrancyguard (#590) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add reentrancyguard * update Cargo * remove mytest * add reentrancy mocks * add utils * finish tests * remove unused func * add comments * clean up code * clean up code * Apply suggestions from code review Co-authored-by: Martín Triay * remove underscore * remove constructor in mock * update interface name * change count_this_recursive to count_external_recursive * move mocks inside tests dir * remove underscore * update cairo to alpha7 * update Cargo * add withdraw_gas * fix formatting * update cairo to rc0 * update Cargo * fix import * simplify imports * remove duplicate import * rename mod * add mock interface * finish tests * update cairo * add new line * Update src/openzeppelin/tests/mocks/reentrancy_mock.cairo Co-authored-by: Eric Nordelo * import dispatchers * fix formatting * Apply suggestions from code review Co-authored-by: Martín Triay * add deploy fn to utils * use deploy from utils --------- Co-authored-by: Martín Triay Co-authored-by: Eric Nordelo --- cairo | 2 +- src/openzeppelin/security.cairo | 1 + .../security/reentrancyguard.cairo | 17 ++++ src/openzeppelin/tests.cairo | 2 + src/openzeppelin/tests/mocks.cairo | 2 + .../mocks/reentrancy_attacker_mock.cairo | 21 +++++ .../tests/mocks/reentrancy_mock.cairo | 93 +++++++++++++++++++ .../tests/test_reentrancyguard.cairo | 92 ++++++++++++++++++ src/openzeppelin/tests/utils.cairo | 14 +++ 9 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 src/openzeppelin/security/reentrancyguard.cairo create mode 100644 src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/reentrancy_mock.cairo create mode 100644 src/openzeppelin/tests/test_reentrancyguard.cairo create mode 100644 src/openzeppelin/tests/utils.cairo diff --git a/cairo b/cairo index 05867c82d..ee9a0bb1e 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit 05867c82de42d5ee5cfa953dcca1cb826402f74b +Subproject commit ee9a0bb1e496c6e5d922c3a5071d85b45f8bc268 diff --git a/src/openzeppelin/security.cairo b/src/openzeppelin/security.cairo index 871349507..45a9c998a 100644 --- a/src/openzeppelin/security.cairo +++ b/src/openzeppelin/security.cairo @@ -1,2 +1,3 @@ +mod reentrancyguard; mod pausable; mod initializable; diff --git a/src/openzeppelin/security/reentrancyguard.cairo b/src/openzeppelin/security/reentrancyguard.cairo new file mode 100644 index 000000000..4aa7375a6 --- /dev/null +++ b/src/openzeppelin/security/reentrancyguard.cairo @@ -0,0 +1,17 @@ +#[contract] +mod ReentrancyGuard { + use starknet::get_caller_address; + + struct Storage { + entered: bool + } + + fn start() { + assert(!entered::read(), 'ReentrancyGuard: reentrant call'); + entered::write(true); + } + + fn end() { + entered::write(false); + } +} diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index df1dcba06..80288f54b 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,6 +1,8 @@ +mod test_reentrancyguard; mod test_ownable; mod test_erc165; mod test_erc20; mod test_pausable; mod test_initializable; mod mocks; +mod utils; diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 60df001ef..ca522a93c 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -1 +1,3 @@ +mod reentrancy_attacker_mock; +mod reentrancy_mock; mod mock_pausable; diff --git a/src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo b/src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo new file mode 100644 index 000000000..072432d00 --- /dev/null +++ b/src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo @@ -0,0 +1,21 @@ +#[abi] +trait IAttacker { + fn call_sender(); +} + +#[contract] +mod Attacker { + // Dispatcher + use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; + use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcherTrait; + + // Other + use starknet::ContractAddress; + use starknet::get_caller_address; + + #[external] + fn call_sender() { + let caller: ContractAddress = get_caller_address(); + IReentrancyMockDispatcher { contract_address: caller }.callback(); + } +} diff --git a/src/openzeppelin/tests/mocks/reentrancy_mock.cairo b/src/openzeppelin/tests/mocks/reentrancy_mock.cairo new file mode 100644 index 000000000..a950d27f1 --- /dev/null +++ b/src/openzeppelin/tests/mocks/reentrancy_mock.cairo @@ -0,0 +1,93 @@ +use starknet::ContractAddress; + +#[abi] +trait IReentrancyGuarded { + fn count_external_recursive(n: felt252); +} + +#[abi] +trait IReentrancyMock { + #[view] + fn current_count() -> felt252; + #[external] + fn callback(); + #[external] + fn count_local_recursive(n: felt252); + #[external] + fn count_external_recursive(n: felt252); + #[external] + fn count_and_call(attacker: ContractAddress); + #[external] + fn count(); +} + +#[contract] +mod ReentrancyMock { + // OZ modules + use openzeppelin::security::reentrancyguard::ReentrancyGuard; + + // Dispatchers + use super::IReentrancyGuardedDispatcher; + use super::IReentrancyGuardedDispatcherTrait; + use openzeppelin::tests::mocks::reentrancy_attacker_mock::IAttackerDispatcher; + use openzeppelin::tests::mocks::reentrancy_attacker_mock::IAttackerDispatcherTrait; + + // Other + use option::OptionTrait; + use starknet::ContractAddress; + use starknet::get_caller_address; + use starknet::get_contract_address; + + struct Storage { + counter: felt252 + } + + #[view] + fn current_count() -> felt252 { + counter::read() + } + + #[external] + fn callback() { + ReentrancyGuard::start(); + count(); + ReentrancyGuard::end(); + } + + #[external] + fn count_local_recursive(n: felt252) { + ReentrancyGuard::start(); + gas::withdraw_gas().expect('Out of gas'); + if n != 0 { + count(); + count_local_recursive(n - 1); + } + ReentrancyGuard::end(); + } + + #[external] + fn count_external_recursive(n: felt252) { + ReentrancyGuard::start(); + gas::withdraw_gas().expect('Out of gas'); + if n != 0 { + count(); + let this: ContractAddress = get_contract_address(); + IReentrancyGuardedDispatcher { contract_address: this }.count_external_recursive(n - 1) + } + ReentrancyGuard::end(); + } + + #[external] + fn count_and_call(attacker: ContractAddress) { + ReentrancyGuard::start(); + gas::withdraw_gas().expect('Out of gas'); + count(); + IAttackerDispatcher { contract_address: attacker }.call_sender(); + ReentrancyGuard::end(); + } + + #[external] + fn count() { + counter::write(counter::read() + 1); + } +} diff --git a/src/openzeppelin/tests/test_reentrancyguard.cairo b/src/openzeppelin/tests/test_reentrancyguard.cairo new file mode 100644 index 000000000..174035cb7 --- /dev/null +++ b/src/openzeppelin/tests/test_reentrancyguard.cairo @@ -0,0 +1,92 @@ +use openzeppelin::security::reentrancyguard::ReentrancyGuard; +use openzeppelin::tests::mocks::reentrancy_mock::ReentrancyMock; +use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; +use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcherTrait; +use openzeppelin::tests::mocks::reentrancy_attacker_mock::Attacker; +use openzeppelin::tests::utils; + +use array::ArrayTrait; + +fn deploy_mock() -> IReentrancyMockDispatcher { + let calldata = ArrayTrait::new(); + let address = utils::deploy(ReentrancyMock::TEST_CLASS_HASH, calldata); + IReentrancyMockDispatcher { contract_address: address } +} + +// +// ReentrancyGuard direct call tests +// + +#[test] +#[available_gas(2000000)] +fn test_reentrancy_guard_start() { + assert(!ReentrancyGuard::entered::read(), 'Guard should not be active'); + ReentrancyGuard::start(); + assert(ReentrancyGuard::entered::read(), 'Guard should be active'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ReentrancyGuard: reentrant call', ))] +fn test_reentrancy_guard_start_when_started() { + ReentrancyGuard::start(); + ReentrancyGuard::start(); +} + +#[test] +#[available_gas(2000000)] +fn test_reentrancy_guard_end() { + ReentrancyGuard::start(); + ReentrancyGuard::end(); + assert(!ReentrancyGuard::entered::read(), 'Guard should not be active'); +} + +// +// Mock implementation tests +// + +#[test] +#[available_gas(2000000)] +#[should_panic( + expected: ( + 'ReentrancyGuard: reentrant call', + 'ENTRYPOINT_FAILED', + 'ENTRYPOINT_FAILED', + 'ENTRYPOINT_FAILED' + ), +)] +fn test_remote_callback() { + let contract = deploy_mock(); + + // Deploy attacker + let calldata = ArrayTrait::new(); + let attacker_addr = utils::deploy(Attacker::TEST_CLASS_HASH, calldata); + + contract.count_and_call(attacker_addr); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ReentrancyGuard: reentrant call', 'ENTRYPOINT_FAILED'))] +fn test_local_recursion() { + let contract = deploy_mock(); + contract.count_local_recursive(10); +} + +#[test] +#[available_gas(2000000)] +#[should_panic( + expected: ('ReentrancyGuard: reentrant call', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED') +)] +fn test_external_recursion() { + let contract = deploy_mock(); + contract.count_external_recursive(10); +} + +#[test] +#[available_gas(2000000)] +fn test_nonreentrant_function_call() { + let contract = deploy_mock(); + contract.callback(); + assert(contract.current_count() == 1, 'Call should execute'); +} diff --git a/src/openzeppelin/tests/utils.cairo b/src/openzeppelin/tests/utils.cairo new file mode 100644 index 000000000..d3b720cce --- /dev/null +++ b/src/openzeppelin/tests/utils.cairo @@ -0,0 +1,14 @@ +use array::ArrayTrait; +use core::result::ResultTrait; +use option::OptionTrait; +use starknet::class_hash::Felt252TryIntoClassHash; +use starknet::ContractAddress; +use traits::TryInto; + +fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { + let (address, _) = starknet::deploy_syscall( + contract_class_hash.try_into().unwrap(), 0, calldata.span(), false + ) + .unwrap(); + address +} From 897facb5e0750baf76c1de1d587837da85eb9a6a Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 19 May 2023 17:37:19 -0400 Subject: [PATCH 049/124] Migrate access control (#605) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add accesscontrol * add accesscontrol tests * remove mock, add impl to contract * fix formatting * remove accesscontrol mock * formatting, remove unused imports * integrate erc165 * fix typo * update cairo to alpha7 * update Cargo * update expected syntax * update expected syntax * update cairo to rc0 * update Cargo * fix import * simplify imports * Apply suggestions from code review Co-authored-by: Martín Triay * fix storage mapping name * rename impl * add warning * fix comment * remove constructor, setup test constructor in setup * fix format * fix import format * add test for granting already granted role * add clarity to revoke role test * add test for revoking already revoked role * add test for renouncing already renounced role * add test for revoked admin role losing privileges * fix test_role_admin_cycle * add target func as comment * add default admin tests * refactor tests, rename actors * add tests for has_role and set_role_admin * tidy up tests * add general doc for events * fix assert_only_role test * remove redundant test * remove unnecessary assertion * remove duplicate test * Update src/openzeppelin/access/accesscontrol.cairo Co-authored-by: Martín Triay * fix imports, define constants locally * Apply suggestions from code review Co-authored-by: Martín Triay * fix test name * bump cairo * fix formatting --------- Co-authored-by: Martín Triay --- src/openzeppelin/access.cairo | 1 + src/openzeppelin/access/accesscontrol.cairo | 151 +++++++++ src/openzeppelin/tests.cairo | 1 + .../tests/test_accesscontrol.cairo | 291 ++++++++++++++++++ 4 files changed, 444 insertions(+) create mode 100644 src/openzeppelin/access/accesscontrol.cairo create mode 100644 src/openzeppelin/tests/test_accesscontrol.cairo diff --git a/src/openzeppelin/access.cairo b/src/openzeppelin/access.cairo index cadc81b51..8f59b4ad1 100644 --- a/src/openzeppelin/access.cairo +++ b/src/openzeppelin/access.cairo @@ -1 +1,2 @@ +mod accesscontrol; mod ownable; diff --git a/src/openzeppelin/access/accesscontrol.cairo b/src/openzeppelin/access/accesscontrol.cairo new file mode 100644 index 000000000..d6bac6fc6 --- /dev/null +++ b/src/openzeppelin/access/accesscontrol.cairo @@ -0,0 +1,151 @@ +use starknet::ContractAddress; + +const DEFAULT_ADMIN_ROLE: felt252 = 0; +const IACCESSCONTROL_ID: u32 = 0x7965db0b_u32; + +#[abi] +trait IAccessControl { + fn has_role(role: felt252, account: ContractAddress) -> bool; + fn get_role_admin(role: felt252) -> felt252; + fn grant_role(role: felt252, account: ContractAddress); + fn revoke_role(role: felt252, account: ContractAddress); + fn renounce_role(role: felt252, account: ContractAddress); +} + +#[contract] +mod AccessControl { + use super::IAccessControl; + use super::DEFAULT_ADMIN_ROLE; + use super::IACCESSCONTROL_ID; + use openzeppelin::introspection::erc165::ERC165; + use starknet::ContractAddress; + use starknet::get_caller_address; + + struct Storage { + role_admin: LegacyMap, + role_members: LegacyMap<(felt252, ContractAddress), bool>, + } + + /// Emitted when `account` is granted `role`. + /// + /// `sender` is the account that originated the contract call, an admin role + /// bearer (except if `_grant_role` is called during initialization from the constructor). + #[event] + fn RoleGranted(role: felt252, account: ContractAddress, sender: ContractAddress) {} + + /// Emitted when `account` is revoked `role`. + /// + /// `sender` is the account that originated the contract call: + /// - If using `revoke_role`, it is the admin role bearer. + /// - If using `renounce_role`, it is the role bearer (i.e. `account`). + #[event] + fn RoleRevoked(role: felt252, account: ContractAddress, sender: ContractAddress) {} + + /// Emitted when `new_admin_role` is set as `role`'s admin role, replacing `previous_admin_role` + /// + /// `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + /// {RoleAdminChanged} not being emitted signaling this. + #[event] + fn RoleAdminChanged(role: felt252, previous_admin_role: felt252, new_admin_role: felt252) {} + + impl AccessControlImpl of IAccessControl { + fn has_role(role: felt252, account: ContractAddress) -> bool { + role_members::read((role, account)) + } + + fn get_role_admin(role: felt252) -> felt252 { + role_admin::read(role) + } + + fn grant_role(role: felt252, account: ContractAddress) { + let admin = get_role_admin(role); + assert_only_role(admin); + _grant_role(role, account); + } + + fn revoke_role(role: felt252, account: ContractAddress) { + let admin: felt252 = get_role_admin(role); + assert_only_role(admin); + _revoke_role(role, account); + } + + fn renounce_role(role: felt252, account: ContractAddress) { + let caller: ContractAddress = get_caller_address(); + assert(caller == account, 'Can only renounce role for self'); + _revoke_role(role, account); + } + } + + #[view] + fn supports_interface(interface_id: u32) -> bool { + ERC165::supports_interface(interface_id) + } + + #[view] + fn has_role(role: felt252, account: ContractAddress) -> bool { + AccessControlImpl::has_role(role, account) + } + + #[view] + fn get_role_admin(role: felt252) -> felt252 { + AccessControlImpl::get_role_admin(role) + } + + #[external] + fn grant_role(role: felt252, account: ContractAddress) { + AccessControlImpl::grant_role(role, account); + } + + #[external] + fn revoke_role(role: felt252, account: ContractAddress) { + AccessControlImpl::revoke_role(role, account); + } + + #[external] + fn renounce_role(role: felt252, account: ContractAddress) { + AccessControlImpl::renounce_role(role, account); + } + + #[internal] + fn initializer() { + ERC165::register_interface(IACCESSCONTROL_ID); + } + + #[internal] + fn assert_only_role(role: felt252) { + let caller: ContractAddress = get_caller_address(); + let authorized: bool = has_role(role, caller); + assert(authorized, 'Caller is missing role'); + } + + // + // WARNING + // The following internal methods are unprotected and should not be used + // outside of a contract's constructor. + // + + #[internal] + fn _grant_role(role: felt252, account: ContractAddress) { + if !has_role(role, account) { + let caller: ContractAddress = get_caller_address(); + role_members::write((role, account), true); + RoleGranted(role, account, caller); + } + } + + #[internal] + fn _revoke_role(role: felt252, account: ContractAddress) { + if has_role(role, account) { + let caller: ContractAddress = get_caller_address(); + role_members::write((role, account), false); + RoleRevoked(role, account, caller); + } + } + + #[internal] + fn _set_role_admin(role: felt252, admin_role: felt252) { + let previous_admin_role: felt252 = get_role_admin(role); + role_admin::write(role, admin_role); + RoleAdminChanged(role, previous_admin_role, admin_role); + } +} diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 80288f54b..69490bef7 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,3 +1,4 @@ +mod test_accesscontrol; mod test_reentrancyguard; mod test_ownable; mod test_erc165; diff --git a/src/openzeppelin/tests/test_accesscontrol.cairo b/src/openzeppelin/tests/test_accesscontrol.cairo new file mode 100644 index 000000000..16b0a41fa --- /dev/null +++ b/src/openzeppelin/tests/test_accesscontrol.cairo @@ -0,0 +1,291 @@ +use openzeppelin::access::accesscontrol::AccessControl; +use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; +use openzeppelin::access::accesscontrol::IACCESSCONTROL_ID; +use starknet::contract_address_const; +use starknet::ContractAddress; +use starknet::testing; + +const ROLE: felt252 = 41; +const OTHER_ROLE: felt252 = 42; + +fn ADMIN() -> ContractAddress { + contract_address_const::<1>() +} + +fn AUTHORIZED() -> ContractAddress { + contract_address_const::<2>() +} + +fn OTHER() -> ContractAddress { + contract_address_const::<3>() +} + +fn OTHER_ADMIN() -> ContractAddress { + contract_address_const::<4>() +} + +fn setup() { + AccessControl::_grant_role(DEFAULT_ADMIN_ROLE, ADMIN()); + testing::set_caller_address(ADMIN()); +} + +// +// initializer +// + +#[test] +#[available_gas(2000000)] +fn test_initializer() { + AccessControl::initializer(); + assert(AccessControl::supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); +} + +// +// has_role +// + +#[test] +#[available_gas(2000000)] +fn test_has_role() { + setup(); + assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'should not have role'); + AccessControl::_grant_role(ROLE, AUTHORIZED()); + assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'should have role'); +} + + +// +// assert_only_role +// + +#[test] +#[available_gas(2000000)] +fn test_assert_only_role() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); + AccessControl::assert_only_role(ROLE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is missing role', ))] +fn test_assert_only_role_unauthorized() { + setup(); + testing::set_caller_address(OTHER()); + AccessControl::assert_only_role(ROLE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is missing role', ))] +fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); + AccessControl::assert_only_role(OTHER_ROLE); +} + +// +// grant_role +// + +#[test] +#[available_gas(2000000)] +fn test_grant_role() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should be granted'); +} + +#[test] +#[available_gas(2000000)] +fn test_grant_role_multiple_times_for_granted_role() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + AccessControl::grant_role(ROLE, AUTHORIZED()); + assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should still be granted'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is missing role', ))] +fn test_grant_role_unauthorized() { + setup(); + testing::set_caller_address(AUTHORIZED()); + AccessControl::grant_role(ROLE, AUTHORIZED()); +} + +// +// revoke_role +// + +#[test] +#[available_gas(2000000)] +fn test_revoke_role_for_role_not_granted() { + setup(); + AccessControl::revoke_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +fn test_revoke_role_for_granted_role() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + AccessControl::revoke_role(ROLE, AUTHORIZED()); + assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should be revoked'); +} + +#[test] +#[available_gas(2000000)] +fn test_revoke_role_multiple_times_for_granted_role() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + + AccessControl::revoke_role(ROLE, AUTHORIZED()); + AccessControl::revoke_role(ROLE, AUTHORIZED()); + assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should still be revoked'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is missing role', ))] +fn test_revoke_role_unauthorized() { + setup(); + + testing::set_caller_address(OTHER()); + AccessControl::revoke_role(ROLE, AUTHORIZED()); +} + +// +// renounce_role +// + +#[test] +#[available_gas(2000000)] +fn test_renounce_role_for_role_not_granted() { + setup(); + testing::set_caller_address(AUTHORIZED()); + + AccessControl::renounce_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +fn test_renounce_role_for_granted_role() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); + + AccessControl::renounce_role(ROLE, AUTHORIZED()); + assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should be renounced'); +} + +#[test] +#[available_gas(2000000)] +fn test_renounce_role_multiple_times_for_granted_role() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); + + AccessControl::renounce_role(ROLE, AUTHORIZED()); + AccessControl::renounce_role(ROLE, AUTHORIZED()); + assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should still be renounced'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Can only renounce role for self', ))] +fn test_renounce_role_unauthorized() { + setup(); + AccessControl::grant_role(ROLE, AUTHORIZED()); + + // Admin is unauthorized caller + AccessControl::renounce_role(ROLE, AUTHORIZED()); +} + +// +// _set_role_admin +// + +#[test] +#[available_gas(2000000)] +fn test__set_role_admin() { + setup(); + assert( + AccessControl::get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'ROLE admin default should be 0' + ); + AccessControl::_set_role_admin(ROLE, OTHER_ROLE); + assert(AccessControl::get_role_admin(ROLE) == OTHER_ROLE, 'ROLE admin should be OTHER_ROLE'); +} + +#[test] +#[available_gas(2000000)] +fn test_new_admin_can_grant_roles() { + setup(); + AccessControl::_set_role_admin(ROLE, OTHER_ROLE); + AccessControl::grant_role(OTHER_ROLE, OTHER_ADMIN()); + + testing::set_caller_address(OTHER_ADMIN()); + AccessControl::grant_role(ROLE, AUTHORIZED()); + + assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should have ROLE'); +} + +#[test] +#[available_gas(2000000)] +fn test_new_admin_can_revoke_roles() { + setup(); + AccessControl::_set_role_admin(ROLE, OTHER_ROLE); + AccessControl::grant_role(OTHER_ROLE, OTHER_ADMIN()); + + testing::set_caller_address(OTHER_ADMIN()); + AccessControl::grant_role(ROLE, AUTHORIZED()); + AccessControl::revoke_role(ROLE, AUTHORIZED()); + + assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should not have ROLE'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is missing role', ))] +fn test_previous_admin_cannot_grant_roles() { + setup(); + AccessControl::_set_role_admin(ROLE, OTHER_ROLE); + + // Caller is ADMIN + AccessControl::grant_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is missing role', ))] +fn test_previous_admin_cannot_revoke_roles() { + setup(); + AccessControl::_set_role_admin(ROLE, OTHER_ROLE); + + // Caller is ADMIN + AccessControl::revoke_role(ROLE, AUTHORIZED()); +} + +// +// default admin +// + +#[test] +#[available_gas(2000000)] +fn test_other_role_admin_is_the_default_admin_role() { + assert( + AccessControl::get_role_admin(OTHER_ROLE) == DEFAULT_ADMIN_ROLE, + 'Should be DEFAULT_ADMIN_ROLE' + ); +} + +#[test] +#[available_gas(2000000)] +fn test_default_admin_role_is_its_own_admin() { + assert( + AccessControl::get_role_admin(DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE, + 'Should be DEFAULT_ADMIN_ROLE' + ); +} From 372de37a6e9ab3fc2e747baa4d2e8f727f834bc7 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 23 May 2023 18:41:54 -0400 Subject: [PATCH 050/124] Migrate account (#620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * continue account implementation * add missing account interface functions * tidy up module * fix validate * bump cairo + account changes * fix __execute__, add serde, rename felt>felt252 * tidy up code * add account tests * complete account implementation * Apply suggestions from code review Co-authored-by: Andrew Fleming Co-authored-by: Hadrien Croubois * apply review suggestions * remove unused import * clarify __execute__ guard * add account tests * add internals * tidy up * add internal macro * add internal macro * add deregister * update erc165 * feat: refactor account and add validate_transaction test * feat: work on span serde * feat: add test for validate * refactor: remove unnecessary imports * refactor: tests * feat: implement test_execute * Update src/openzeppelin/tests/test_account.cairo Co-authored-by: Martín Triay * Update src/openzeppelin/tests/test_account.cairo Co-authored-by: Martín Triay * feat: update from review * feat: format files * feat: SpanSerde compiling version * feat: update tests and interface * feat: format file * feat: add test for multicall * feat: add more tests * test: remove unused function * refactor: update ERC20 interface and module * feat: add impl again * refactor: apply review comments * test: execute out of gas * refactor: is valid signature because of lack of short circuit condicionals * refactor: apply updates from reviews * feat: add SpanSerde implementation * refactor: remove span_to_array * Update src/openzeppelin/tests/test_account.cairo Co-authored-by: Andrew Fleming * Update src/openzeppelin/account.cairo Co-authored-by: Andrew Fleming * test: update from review * feat: splitting account interface and abi * feat: add new account files * remove underscore on mod api methods * remove comment * remove underscore * move erc1271 id to interface * remove unused import * integrate deploy util * add comments for validate dummy params * add initializer * change error msg * add empty sig tests * move test * replace dummy args, fix comments * fix formatting * tidy up code * add erc20 transfer call in execute test * tidy up imports * remove unused const --------- Co-authored-by: Martín Triay Co-authored-by: Hadrien Croubois Co-authored-by: Eric Nordelo --- src/openzeppelin/account.cairo | 6 + src/openzeppelin/account/account.cairo | 233 +++++++++++ src/openzeppelin/account/interface.cairo | 21 + src/openzeppelin/lib.cairo | 1 + src/openzeppelin/tests.cairo | 1 + src/openzeppelin/tests/test_account.cairo | 457 ++++++++++++++++++++++ src/openzeppelin/token/erc20.cairo | 26 +- src/openzeppelin/utils.cairo | 16 + 8 files changed, 759 insertions(+), 2 deletions(-) create mode 100644 src/openzeppelin/account.cairo create mode 100644 src/openzeppelin/account/account.cairo create mode 100644 src/openzeppelin/account/interface.cairo create mode 100644 src/openzeppelin/tests/test_account.cairo diff --git a/src/openzeppelin/account.cairo b/src/openzeppelin/account.cairo new file mode 100644 index 000000000..75f26fdf1 --- /dev/null +++ b/src/openzeppelin/account.cairo @@ -0,0 +1,6 @@ +mod account; +use account::{ + Account, AccountABIDispatcher, AccountABIDispatcherTrait, TRANSACTION_VERSION, QUERY_VERSION +}; + +mod interface; diff --git a/src/openzeppelin/account/account.cairo b/src/openzeppelin/account/account.cairo new file mode 100644 index 000000000..267aa9534 --- /dev/null +++ b/src/openzeppelin/account/account.cairo @@ -0,0 +1,233 @@ +use array::ArrayTrait; +use array::SpanTrait; +use option::OptionTrait; +use serde::Serde; +use serde::deserialize_array_helper; +use serde::serialize_array_helper; +use starknet::ContractAddress; + +use openzeppelin::account::interface::Call; + +const TRANSACTION_VERSION: felt252 = 1; +// 2**128 + TRANSACTION_VERSION +const QUERY_VERSION: felt252 = 340282366920938463463374607431768211457; + +#[abi] +trait AccountABI { + #[external] + fn __execute__(calls: Array) -> Array>; + #[external] + fn __validate__(calls: Array) -> felt252; + #[external] + fn __validate_declare__(class_hash: felt252) -> felt252; + #[external] + fn __validate_deploy__( + class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + ) -> felt252; + #[external] + fn set_public_key(new_public_key: felt252); + #[view] + fn get_public_key() -> felt252; + #[view] + fn is_valid_signature(message: felt252, signature: Array) -> u32; + #[view] + fn supports_interface(interface_id: u32) -> bool; +} + +#[account_contract] +mod Account { + use array::SpanTrait; + use array::ArrayTrait; + use box::BoxTrait; + use ecdsa::check_ecdsa_signature; + use serde::ArraySerde; + use starknet::get_tx_info; + use starknet::get_caller_address; + use starknet::get_contract_address; + use option::OptionTrait; + use zeroable::Zeroable; + + use openzeppelin::account::interface::ERC1271_VALIDATED; + use openzeppelin::account::interface::IAccount; + use openzeppelin::account::interface::IACCOUNT_ID; + use openzeppelin::introspection::erc165::ERC165; + + use super::Call; + use super::QUERY_VERSION; + use super::SpanSerde; + use super::TRANSACTION_VERSION; + + struct Storage { + public_key: felt252 + } + + impl AccountImpl of IAccount { + fn __execute__(mut calls: Array) -> Array> { + // Avoid calls from other contracts + // https://github.com/OpenZeppelin/cairo-contracts/issues/344 + let sender = get_caller_address(); + assert(sender.is_zero(), 'Account: invalid caller'); + + // Check tx version + let tx_info = get_tx_info().unbox(); + let version = tx_info.version; + if version != TRANSACTION_VERSION { + assert(version == QUERY_VERSION, 'Account: invalid tx version'); + } + + _execute_calls(calls) + } + + fn __validate__(mut calls: Array) -> felt252 { + validate_transaction() + } + + fn __validate_declare__(class_hash: felt252) -> felt252 { + validate_transaction() + } + + fn is_valid_signature(message: felt252, signature: Array) -> u32 { + if _is_valid_signature(message, signature.span()) { + ERC1271_VALIDATED + } else { + 0_u32 + } + } + + fn supports_interface(interface_id: u32) -> bool { + ERC165::supports_interface(interface_id) + } + } + + #[constructor] + fn constructor(_public_key: felt252) { + initializer(_public_key); + } + + // + // Externals + // + + #[external] + fn __execute__(mut calls: Array) -> Array> { + AccountImpl::__execute__(calls) + } + + #[external] + fn __validate__(mut calls: Array) -> felt252 { + AccountImpl::__validate__(calls) + } + + #[external] + fn __validate_declare__(class_hash: felt252) -> felt252 { + AccountImpl::__validate_declare__(class_hash) + } + + #[external] + fn __validate_deploy__( + class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + ) -> felt252 { + validate_transaction() + } + + #[external] + fn set_public_key(new_public_key: felt252) { + assert_only_self(); + public_key::write(new_public_key); + } + + // + // View + // + + #[view] + fn get_public_key() -> felt252 { + public_key::read() + } + + #[view] + fn is_valid_signature(message: felt252, signature: Array) -> u32 { + AccountImpl::is_valid_signature(message, signature) + } + + #[view] + fn supports_interface(interface_id: u32) -> bool { + AccountImpl::supports_interface(interface_id) + } + + // + // Internals + // + + #[internal] + fn initializer(_public_key: felt252) { + ERC165::register_interface(IACCOUNT_ID); + public_key::write(_public_key); + } + + #[internal] + fn assert_only_self() { + let caller = get_caller_address(); + let self = get_contract_address(); + assert(self == caller, 'Account: unauthorized'); + } + + #[internal] + fn validate_transaction() -> felt252 { + let tx_info = get_tx_info().unbox(); + let tx_hash = tx_info.transaction_hash; + let signature = tx_info.signature; + assert(_is_valid_signature(tx_hash, signature), 'Account: invalid signature'); + starknet::VALIDATED + } + + #[internal] + fn _is_valid_signature(message: felt252, signature: Span) -> bool { + let valid_length = signature.len() == 2_u32; + + if valid_length { + check_ecdsa_signature( + message, public_key::read(), *signature.at(0_u32), *signature.at(1_u32) + ) + } else { + false + } + } + + #[internal] + fn _execute_calls(mut calls: Array) -> Array> { + let mut res = ArrayTrait::new(); + loop { + match calls.pop_front() { + Option::Some(call) => { + let _res = _execute_single_call(call); + res.append(_res); + }, + Option::None(_) => { + break (); + }, + }; + }; + res + } + + #[internal] + fn _execute_single_call(call: Call) -> Span { + let Call{to, selector, calldata } = call; + starknet::call_contract_syscall(to, selector, calldata.span()).unwrap_syscall() + } +} + +impl SpanSerde< + T, impl TSerde: Serde, impl TCopy: Copy, impl TDrop: Drop +> of Serde> { + fn serialize(self: @Span, ref output: Array) { + (*self).len().serialize(ref output); + serialize_array_helper(*self, ref output); + } + fn deserialize(ref serialized: Span) -> Option> { + let length = *serialized.pop_front()?; + let mut arr = ArrayTrait::new(); + Option::Some(deserialize_array_helper(ref serialized, arr, length)?.span()) + } +} diff --git a/src/openzeppelin/account/interface.cairo b/src/openzeppelin/account/interface.cairo new file mode 100644 index 000000000..5c77f797b --- /dev/null +++ b/src/openzeppelin/account/interface.cairo @@ -0,0 +1,21 @@ +use array::ArrayTrait; +use array::SpanTrait; +use starknet::ContractAddress; + +const IACCOUNT_ID: u32 = 0xa66bd575_u32; +const ERC1271_VALIDATED: u32 = 0x1626ba7e_u32; + +#[derive(Serde, Drop)] +struct Call { + to: ContractAddress, + selector: felt252, + calldata: Array +} + +trait IAccount { + fn __execute__(calls: Array) -> Array>; + fn __validate__(calls: Array) -> felt252; + fn __validate_declare__(class_hash: felt252) -> felt252; + fn is_valid_signature(message: felt252, signature: Array) -> u32; + fn supports_interface(interface_id: u32) -> bool; +} diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 1f55a830f..47d73c605 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,6 +1,7 @@ mod access; mod introspection; mod security; +mod account; mod token; mod tests; mod utils; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 69490bef7..e13d78136 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -2,6 +2,7 @@ mod test_accesscontrol; mod test_reentrancyguard; mod test_ownable; mod test_erc165; +mod test_account; mod test_erc20; mod test_pausable; mod test_initializable; diff --git a/src/openzeppelin/tests/test_account.cairo b/src/openzeppelin/tests/test_account.cairo new file mode 100644 index 000000000..d53ba3259 --- /dev/null +++ b/src/openzeppelin/tests/test_account.cairo @@ -0,0 +1,457 @@ +use array::ArrayTrait; +use core::traits::Into; +use option::OptionTrait; +use serde::Serde; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing; + +use openzeppelin::account::Account; +use openzeppelin::account::AccountABIDispatcher; +use openzeppelin::account::AccountABIDispatcherTrait; +use openzeppelin::account::interface::Call; +use openzeppelin::account::interface::ERC1271_VALIDATED; +use openzeppelin::account::interface::IACCOUNT_ID; +use openzeppelin::account::QUERY_VERSION; +use openzeppelin::account::TRANSACTION_VERSION; +use openzeppelin::introspection::erc165::IERC165_ID; +use openzeppelin::tests::utils; +use openzeppelin::token::erc20::ERC20; +use openzeppelin::token::erc20::IERC20Dispatcher; +use openzeppelin::token::erc20::IERC20DispatcherTrait; + +const PUBLIC_KEY: felt252 = 0x333333; +const NEW_PUBKEY: felt252 = 0x789789; +const TRANSFER_SELECTOR: felt252 = 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e; +const SALT: felt252 = 123; + +#[derive(Drop)] +struct SignedTransactionData { + private_key: felt252, + public_key: felt252, + transaction_hash: felt252, + r: felt252, + s: felt252 +} + +fn CLASS_HASH() -> felt252 { + Account::TEST_CLASS_HASH +} +fn ACCOUNT_ADDRESS() -> ContractAddress { + contract_address_const::<0x111111>() +} +fn SIGNED_TX_DATA() -> SignedTransactionData { + SignedTransactionData { + private_key: 1234, + public_key: 883045738439352841478194533192765345509759306772397516907181243450667673002, + transaction_hash: 2717105892474786771566982177444710571376803476229898722748888396642649184538, + r: 3068558690657879390136740086327753007413919701043650133111397282816679110801, + s: 3355728545224320878895493649495491771252432631648740019139167265522817576501 + } +} + +fn setup_dispatcher(data: Option<@SignedTransactionData>) -> AccountABIDispatcher { + // Set the transaction version + testing::set_version(TRANSACTION_VERSION); + + // Deploy the account contract + let mut calldata = ArrayTrait::new(); + + if data.is_some() { + let data = data.unwrap(); + + // Set the signature and transaction hash + let mut signature = ArrayTrait::new(); + signature.append(*data.r); + signature.append(*data.s); + testing::set_signature(signature.span()); + testing::set_transaction_hash(*data.transaction_hash); + + calldata.append(*data.public_key); + } else { + calldata.append(PUBLIC_KEY); + } + + let address = utils::deploy(Account::TEST_CLASS_HASH, calldata); + AccountABIDispatcher { contract_address: address } +} + +fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispatcher { + let name = 0; + let symbol = 0; + let mut calldata = ArrayTrait::::new(); + + calldata.append(name); + calldata.append(symbol); + calldata.append(initial_supply.low.into()); + calldata.append(initial_supply.high.into()); + calldata.append(recipient.into()); + + let address = utils::deploy(ERC20::TEST_CLASS_HASH, calldata); + IERC20Dispatcher { contract_address: address } +} + +#[test] +#[available_gas(2000000)] +fn test_constructor() { + Account::constructor(PUBLIC_KEY); + assert(Account::get_public_key() == PUBLIC_KEY, 'Should return public key'); +} + +#[test] +#[available_gas(2000000)] +fn test_interfaces() { + Account::constructor(PUBLIC_KEY); + + let supports_default_interface = Account::supports_interface(IERC165_ID); + assert(supports_default_interface, 'Should support base interface'); + + let supports_account_interface = Account::supports_interface(IACCOUNT_ID); + assert(supports_account_interface, 'Should support account id'); +} + +#[test] +#[available_gas(2000000)] +fn test_is_valid_signature() { + let data = SIGNED_TX_DATA(); + let message = data.transaction_hash; + + let mut good_signature = ArrayTrait::new(); + good_signature.append(data.r); + good_signature.append(data.s); + + let mut bad_signature = ArrayTrait::new(); + bad_signature.append(0x987); + bad_signature.append(0x564); + + Account::set_public_key(data.public_key); + + let is_valid = Account::is_valid_signature(message, good_signature); + assert(is_valid == ERC1271_VALIDATED, 'Should accept valid signature'); + + let is_valid = Account::is_valid_signature(message, bad_signature); + assert(is_valid == 0_u32, 'Should reject invalid signature'); +} + +#[test] +#[available_gas(2000000)] +fn test_validate_deploy() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + + // `__validate_deploy__` does not directly use the passed arguments. Their + // values are already integrated in the tx hash. The passed arguments in this + // testing context are decoupled from the signature and have no effect on the test. + assert( + account.__validate_deploy__(CLASS_HASH(), SALT, PUBLIC_KEY) == starknet::VALIDATED, + 'Should validate correctly' + ); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_invalid_signature_data() { + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher(Option::Some(@data)); + + account.__validate_deploy__(CLASS_HASH(), SALT, PUBLIC_KEY); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_invalid_signature_length() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let mut signature = ArrayTrait::new(); + + signature.append(0x1); + testing::set_signature(signature.span()); + + account.__validate_deploy__(CLASS_HASH(), SALT, PUBLIC_KEY); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_empty_signature() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let empty_sig = ArrayTrait::new(); + + testing::set_signature(empty_sig.span()); + account.__validate_deploy__(CLASS_HASH(), SALT, PUBLIC_KEY); +} + +#[test] +#[available_gas(2000000)] +fn test_validate_declare() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + + // `__validate_declare__` does not directly use the class_hash argument. Its + // value is already integrated in the tx hash. The class_hash argument in this + // testing context is decoupled from the signature and has no effect on the test. + assert( + account.__validate_declare__(CLASS_HASH()) == starknet::VALIDATED, + 'Should validate correctly' + ); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_invalid_signature_data() { + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher(Option::Some(@data)); + + account.__validate_declare__(CLASS_HASH()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_invalid_signature_length() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let mut signature = ArrayTrait::new(); + + signature.append(0x1); + testing::set_signature(signature.span()); + + account.__validate_declare__(CLASS_HASH()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_empty_signature() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let empty_sig = ArrayTrait::new(); + + testing::set_signature(empty_sig.span()); + + account.__validate_declare__(CLASS_HASH()); +} + +fn test_execute_with_version(version: Option) { + let data = SIGNED_TX_DATA(); + let account = setup_dispatcher(Option::Some(@data)); + let erc20 = deploy_erc20(account.contract_address, 1000); + let recipient = contract_address_const::<0x123>(); + + // Craft call and add to calls array + let mut calldata = ArrayTrait::new(); + let amount: u256 = 200; + calldata.append(recipient.into()); + calldata.append(amount.low.into()); + calldata.append(amount.high.into()); + let call = Call { to: erc20.contract_address, selector: TRANSFER_SELECTOR, calldata: calldata }; + let mut calls = ArrayTrait::new(); + calls.append(call); + + // Handle version for test + if version.is_some() { + testing::set_version(version.unwrap()); + } + + // Execute + let ret = account.__execute__(calls); + + // Assert that the transfer was successful + assert(erc20.balance_of(account.contract_address) == 800, 'Should have remainder'); + assert(erc20.balance_of(recipient) == amount, 'Should have transferred'); + + // Test return value + let mut call_serialized_retval = *ret.at(0); + let call_retval = Serde::::deserialize(ref call_serialized_retval); + assert(call_retval.unwrap(), 'Should have succeeded'); +} + +#[test] +#[available_gas(2000000)] +fn test_execute() { + test_execute_with_version(Option::None(())); +} + +#[test] +#[available_gas(2000000)] +fn test_execute_query_version() { + test_execute_with_version(Option::Some(QUERY_VERSION)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid tx version', 'ENTRYPOINT_FAILED'))] +fn test_execute_invalid_version() { + test_execute_with_version(Option::Some(TRANSACTION_VERSION - 1)); +} + +#[test] +#[available_gas(2000000)] +fn test_validate() { + let calls = ArrayTrait::new(); + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + + assert(account.__validate__(calls) == starknet::VALIDATED, 'Should validate correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_invalid() { + let calls = ArrayTrait::new(); + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher(Option::Some(@data)); + + account.__validate__(calls); +} + +#[test] +#[available_gas(2000000)] +fn test_multicall() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let erc20 = deploy_erc20(account.contract_address, 1000); + let recipient1 = contract_address_const::<0x123>(); + let recipient2 = contract_address_const::<0x456>(); + let mut calls = ArrayTrait::new(); + + // Craft call1 + let mut calldata1 = ArrayTrait::new(); + let amount1: u256 = 300; + calldata1.append(recipient1.into()); + calldata1.append(amount1.low.into()); + calldata1.append(amount1.high.into()); + let call1 = Call { + to: erc20.contract_address, selector: TRANSFER_SELECTOR, calldata: calldata1 + }; + + // Craft call2 + let mut calldata2 = ArrayTrait::new(); + let amount2: u256 = 500; + calldata2.append(recipient2.into()); + calldata2.append(amount2.low.into()); + calldata2.append(amount2.high.into()); + let call2 = Call { + to: erc20.contract_address, selector: TRANSFER_SELECTOR, calldata: calldata2 + }; + + // Bundle calls and exeute + calls.append(call1); + calls.append(call2); + let ret = account.__execute__(calls); + + // Assert that the transfers were successful + assert(erc20.balance_of(account.contract_address) == 200, 'Should have remainder'); + assert(erc20.balance_of(recipient1) == 300, 'Should have transferred'); + assert(erc20.balance_of(recipient2) == 500, 'Should have transferred'); + + // Test return value + let mut call1_serialized_retval = *ret.at(0); + let mut call2_serialized_retval = *ret.at(1); + let call1_retval = Serde::::deserialize(ref call1_serialized_retval); + let call2_retval = Serde::::deserialize(ref call2_serialized_retval); + assert(call1_retval.unwrap(), 'Should have succeeded'); + assert(call2_retval.unwrap(), 'Should have succeeded'); +} + +#[test] +#[available_gas(2000000)] +fn test_multicall_zero_calls() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let mut calls = ArrayTrait::new(); + + let ret = account.__execute__(calls); + + // Test return value + assert(ret.len() == 0, 'Should have an empty response'); +} + +#[test] +#[available_gas(2000000)] +fn test_public_key_setter_and_getter() { + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(ACCOUNT_ADDRESS()); + Account::set_public_key(NEW_PUBKEY); + + let public_key = Account::get_public_key(); + assert(public_key == NEW_PUBKEY, 'Should update key'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: unauthorized', ))] +fn test_public_key_setter_different_account() { + let caller = contract_address_const::<0x123>(); + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(caller); + Account::set_public_key(NEW_PUBKEY); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid caller', ))] +fn test_account_called_from_contract() { + let calls = ArrayTrait::new(); + let caller = contract_address_const::<0x123>(); + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(caller); + Account::__execute__(calls); +} + +// +// Test internals +// + +#[test] +#[available_gas(2000000)] +fn test_initializer() { + Account::initializer(PUBLIC_KEY); + assert(Account::get_public_key() == PUBLIC_KEY, 'Should return public key'); +} + +#[test] +#[available_gas(2000000)] +fn test_assert_only_self_true() { + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(ACCOUNT_ADDRESS()); + Account::assert_only_self(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: unauthorized', ))] +fn test_assert_only_self_false() { + testing::set_contract_address(ACCOUNT_ADDRESS()); + let other = contract_address_const::<0x4567>(); + testing::set_caller_address(other); + Account::assert_only_self(); +} + +#[test] +#[available_gas(2000000)] +fn test__is_valid_signature() { + let data = SIGNED_TX_DATA(); + let message = data.transaction_hash; + + let mut good_signature = ArrayTrait::new(); + good_signature.append(data.r); + good_signature.append(data.s); + + let mut bad_signature = ArrayTrait::new(); + bad_signature.append(0x987); + bad_signature.append(0x564); + + let mut invalid_length_signature = ArrayTrait::new(); + invalid_length_signature.append(0x987); + + Account::set_public_key(data.public_key); + + let is_valid = Account::_is_valid_signature(message, good_signature.span()); + assert(is_valid, 'Should accept valid signature'); + + let is_valid = Account::_is_valid_signature(message, bad_signature.span()); + assert(!is_valid, 'Should reject invalid signature'); + + let is_valid = Account::_is_valid_signature(message, invalid_length_signature.span()); + assert(!is_valid, 'Should reject invalid length'); +} diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo index f2350bebc..eca9933d7 100644 --- a/src/openzeppelin/token/erc20.cairo +++ b/src/openzeppelin/token/erc20.cairo @@ -1,15 +1,29 @@ use starknet::ContractAddress; +#[abi] trait IERC20 { + #[view] fn name() -> felt252; + #[view] fn symbol() -> felt252; + #[view] fn decimals() -> u8; + #[view] fn total_supply() -> u256; + #[view] fn balance_of(account: ContractAddress) -> u256; + #[view] fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; + #[external] fn transfer(recipient: ContractAddress, amount: u256) -> bool; + #[external] fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; + #[external] fn approve(spender: ContractAddress, amount: u256) -> bool; + #[external] + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool; + #[external] + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool; } #[contract] @@ -79,6 +93,14 @@ mod ERC20 { _approve(caller, spender, amount); true } + + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { + _increase_allowance(spender, added_value) + } + + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { + _decrease_allowance(spender, subtracted_value) + } } #[constructor] @@ -136,12 +158,12 @@ mod ERC20 { #[external] fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - _increase_allowance(spender, added_value) + ERC20::increase_allowance(spender, added_value) } #[external] fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - _decrease_allowance(spender, subtracted_value) + ERC20::decrease_allowance(spender, subtracted_value) } /// diff --git a/src/openzeppelin/utils.cairo b/src/openzeppelin/utils.cairo index 3709db21f..c8a47ceb8 100644 --- a/src/openzeppelin/utils.cairo +++ b/src/openzeppelin/utils.cairo @@ -1 +1,17 @@ +use array::ArrayTrait; +use array::SpanTrait; +use box::BoxTrait; +use option::OptionTrait; mod constants; + +#[inline(always)] +fn check_gas() { + match gas::withdraw_gas() { + Option::Some(_) => {}, + Option::None(_) => { + let mut data = ArrayTrait::new(); + data.append('Out of gas'); + panic(data); + }, + } +} From d86eb73879c0ae2ef30ab7762ea26235d6c425e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Tue, 30 May 2023 15:36:53 -0300 Subject: [PATCH 051/124] Migrate ERC721 (#619) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * continue account implementation * add missing account interface functions * tidy up module * fix validate * bump cairo + account changes * fix __execute__, add serde, rename felt>felt252 * tidy up code * WIP ERC721 * make format * fix dispatcher call * clean * working on tests * replace match with `is_some()` and `is_none()` for readeability * erc721 tests * use Option.expect * add account tests * check panic reason * rename _owner() to _owner_of() * spacing * complete account implementation * apply recommandation for PR * Apply suggestions from code review Co-authored-by: Andrew Fleming * check low level ownership int * prefix test function with test_ * Apply suggestions from code review Co-authored-by: Andrew Fleming Co-authored-by: Hadrien Croubois * apply review suggestions * remove unused import * clarify __execute__ guard * add account tests * add internals * tidy up * update ERC165 ids to u32 * apply sugestions from code review * Apply suggestions from code review Co-authored-by: Martín Triay * update & expand tests * update lock * add internal macro * add internal macro * add deregister * update erc165 * wip (dispatched issue) * fix abi * start array→span transition * minimise account dependency * add SpanSerde in utils * add dual interfaces * update test message. fix linter * split interfaces from preset module * fix linter * rename metadata id var * add camelCase to traits * fully implement dual interface traits * simplify _owner_of * add constructor and getter tests * add token_uri tests * remove conflictive test * add erc721receiver. add IERC721ABI * add safe_transfer_from tests * add safe_mint tests * Update src/openzeppelin/token/erc721/interface.cairo Co-authored-by: Eric Nordelo * move erc721 abi next to module * address review comments --------- Co-authored-by: Hadrien Croubois Co-authored-by: Andrew Fleming Co-authored-by: Andrew Fleming Co-authored-by: Eric Nordelo --- src/openzeppelin/introspection/erc165.cairo | 1 + src/openzeppelin/tests.cairo | 3 +- src/openzeppelin/tests/mocks.cairo | 1 + .../tests/mocks/erc721_receiver.cairo | 62 ++ src/openzeppelin/tests/test_erc721.cairo | 791 ++++++++++++++++++ src/openzeppelin/token.cairo | 1 + src/openzeppelin/token/erc721.cairo | 3 + src/openzeppelin/token/erc721/erc721.cairo | 462 ++++++++++ src/openzeppelin/token/erc721/interface.cairo | 71 ++ src/openzeppelin/utils.cairo | 1 + src/openzeppelin/utils/serde.cairo | 19 + 11 files changed, 1414 insertions(+), 1 deletion(-) create mode 100644 src/openzeppelin/tests/mocks/erc721_receiver.cairo create mode 100644 src/openzeppelin/tests/test_erc721.cairo create mode 100644 src/openzeppelin/token/erc721.cairo create mode 100644 src/openzeppelin/token/erc721/erc721.cairo create mode 100644 src/openzeppelin/token/erc721/interface.cairo create mode 100644 src/openzeppelin/utils/serde.cairo diff --git a/src/openzeppelin/introspection/erc165.cairo b/src/openzeppelin/introspection/erc165.cairo index 16f13205a..4a3b01778 100644 --- a/src/openzeppelin/introspection/erc165.cairo +++ b/src/openzeppelin/introspection/erc165.cairo @@ -1,6 +1,7 @@ const IERC165_ID: u32 = 0x01ffc9a7_u32; const INVALID_ID: u32 = 0xffffffff_u32; +#[abi] trait IERC165 { fn supports_interface(interface_id: u32) -> bool; } diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index e13d78136..5aa74d96f 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -4,7 +4,8 @@ mod test_ownable; mod test_erc165; mod test_account; mod test_erc20; -mod test_pausable; +mod test_erc721; mod test_initializable; +mod test_pausable; mod mocks; mod utils; diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index ca522a93c..b8f645b23 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -1,3 +1,4 @@ mod reentrancy_attacker_mock; mod reentrancy_mock; +mod erc721_receiver; mod mock_pausable; diff --git a/src/openzeppelin/tests/mocks/erc721_receiver.cairo b/src/openzeppelin/tests/mocks/erc721_receiver.cairo new file mode 100644 index 000000000..c9e848630 --- /dev/null +++ b/src/openzeppelin/tests/mocks/erc721_receiver.cairo @@ -0,0 +1,62 @@ +const SUCCESS: felt252 = 123123; +const FAILURE: felt252 = 456456; + +#[contract] +mod ERC721Receiver { + use openzeppelin::token::erc721::interface::IERC721Receiver; + use openzeppelin::token::erc721::interface::IERC721ReceiverCamel; + use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; + use openzeppelin::introspection::erc165::ERC165; + + use openzeppelin::utils::serde::SpanSerde; + use starknet::ContractAddress; + use array::SpanTrait; + + impl ERC721ReceiverImpl of IERC721Receiver { + fn on_erc721_received( + operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + ) -> u32 { + if *data.at(0) == super::SUCCESS { + IERC721_RECEIVER_ID + } else { + 0 + } + } + } + + impl ERC721ReceiverCamelImpl of IERC721ReceiverCamel { + fn onERC721Received( + operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + ) -> u32 { + ERC721ReceiverImpl::on_erc721_received(operator, from, tokenId, data) + } + } + + #[constructor] + fn constructor() { + ERC165::register_interface(IERC721_RECEIVER_ID); + } + + #[view] + fn supports_interface(interface_id: u32) -> bool { + ERC165::supports_interface(interface_id) + } + + #[external] + fn on_erc721_received( + operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + ) -> u32 { + ERC721ReceiverImpl::on_erc721_received(operator, from, token_id, data) + } + + #[external] + fn onERC721Received( + operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + ) -> u32 { + ERC721ReceiverCamelImpl::onERC721Received(operator, from, tokenId, data) + } +} + + +#[contract] +mod ERC721NonReceiver {} diff --git a/src/openzeppelin/tests/test_erc721.cairo b/src/openzeppelin/tests/test_erc721.cairo new file mode 100644 index 000000000..3b81360ae --- /dev/null +++ b/src/openzeppelin/tests/test_erc721.cairo @@ -0,0 +1,791 @@ +use openzeppelin::introspection::erc165; +use openzeppelin::token::erc721; +use openzeppelin::token::erc721::ERC721; +use openzeppelin::account::Account; + +use openzeppelin::tests::utils; +use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; +use openzeppelin::tests::mocks::erc721_receiver::ERC721NonReceiver; +use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; +use openzeppelin::tests::mocks::erc721_receiver::FAILURE; + +use starknet::contract_address_const; +use starknet::ContractAddress; +use starknet::testing::set_caller_address; +use integer::u256; +use integer::u256_from_felt252; +use array::ArrayTrait; +use traits::Into; +use zeroable::Zeroable; + +const NAME: felt252 = 111; +const SYMBOL: felt252 = 222; +const URI: felt252 = 333; + +fn TOKEN_ID() -> u256 { + 7.into() +} + +fn ZERO() -> ContractAddress { + Zeroable::zero() +} +fn OWNER() -> ContractAddress { + contract_address_const::<10>() +} +fn RECIPIENT() -> ContractAddress { + contract_address_const::<20>() +} +fn SPENDER() -> ContractAddress { + contract_address_const::<30>() +} +fn OPERATOR() -> ContractAddress { + contract_address_const::<40>() +} +fn OTHER() -> ContractAddress { + contract_address_const::<50>() +} + +fn DATA(success: bool) -> Span { + let mut data = ArrayTrait::new(); + if success { + data.append(SUCCESS); + } else { + data.append(FAILURE); + } + data.span() +} + +/// +/// Setup +/// + +fn setup() { + ERC721::initializer(NAME, SYMBOL); + ERC721::_mint(OWNER(), TOKEN_ID()); +} + +fn setup_receiver() -> ContractAddress { + utils::deploy(ERC721Receiver::TEST_CLASS_HASH, ArrayTrait::new()) +} + +fn setup_account() -> ContractAddress { + let mut calldata = ArrayTrait::new(); + let public_key: felt252 = 1234678; + calldata.append(public_key); + utils::deploy(Account::TEST_CLASS_HASH, calldata) +} + +/// +/// Initializers +/// + +#[test] +#[available_gas(2000000)] +fn test_constructor() { + ERC721::constructor(NAME, SYMBOL); + + assert(ERC721::name() == NAME, 'Name should be NAME'); + assert(ERC721::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC721::balance_of(OWNER()) == 0.into(), 'Balance should be zero'); + + assert(ERC721::supports_interface(erc721::interface::IERC721_ID), 'Missing interface ID'); + assert( + ERC721::supports_interface(erc721::interface::IERC721_METADATA_ID), 'missing interface ID' + ); + assert(ERC721::supports_interface(erc165::IERC165_ID), 'missing interface ID'); + assert(!ERC721::supports_interface(erc165::INVALID_ID), 'invalid interface ID'); +} + +#[test] +#[available_gas(2000000)] +fn test_initialize() { + ERC721::initializer(NAME, SYMBOL); + + assert(ERC721::name() == NAME, 'Name should be NAME'); + assert(ERC721::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC721::balance_of(OWNER()) == 0.into(), 'Balance should be zero'); + + assert(ERC721::supports_interface(erc721::interface::IERC721_ID), 'Missing interface ID'); + assert( + ERC721::supports_interface(erc721::interface::IERC721_METADATA_ID), 'missing interface ID' + ); + assert(ERC721::supports_interface(erc165::IERC165_ID), 'missing interface ID'); + assert(!ERC721::supports_interface(erc165::INVALID_ID), 'invalid interface ID'); +} + +/// +/// Getters +/// + +#[test] +#[available_gas(2000000)] +fn test_balance_of() { + setup(); + assert(ERC721::balance_of(OWNER()) == 1.into(), 'Should return balance'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid account', ))] +fn test_balance_of_zero() { + ERC721::balance_of(ZERO()); +} + +#[test] +#[available_gas(2000000)] +fn test_owner_of() { + setup(); + assert(ERC721::owner_of(TOKEN_ID()) == OWNER(), 'Should return owner'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test_owner_of_non_minted() { + ERC721::owner_of(u256_from_felt252(7)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test_token_uri_non_minted() { + ERC721::token_uri(u256_from_felt252(7)); +} + +#[test] +#[available_gas(2000000)] +fn test_get_approved() { + setup(); + let spender = SPENDER(); + let token_id = TOKEN_ID(); + + assert(ERC721::get_approved(token_id) == ZERO(), 'Should return non-approval'); + ERC721::_approve(spender, token_id); + assert(ERC721::get_approved(token_id) == spender, 'Should return approval'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test_get_approved_nonexistent() { + ERC721::get_approved(u256_from_felt252(7)); +} + +#[test] +#[available_gas(2000000)] +fn test__exists() { + let zero = ZERO(); + let token_id = TOKEN_ID(); + assert(!ERC721::_exists(token_id), 'Token should not exist'); + assert(ERC721::_owners::read(token_id) == zero, 'Invalid owner'); + + ERC721::_mint(RECIPIENT(), token_id); + + assert(ERC721::_exists(token_id), 'Token should exist'); + assert(ERC721::_owners::read(token_id) == RECIPIENT(), 'Invalid owner'); + + ERC721::_burn(token_id); + + assert(!ERC721::_exists(token_id), 'Token should not exist'); + assert(ERC721::_owners::read(token_id) == zero, 'Invalid owner'); +} + +/// +/// approve & _approve +/// + +#[test] +#[available_gas(2000000)] +fn test_approve_from_owner() { + setup(); + + set_caller_address(OWNER()); + ERC721::approve(SPENDER(), TOKEN_ID()); + assert(ERC721::get_approved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +fn test_approve_from_operator() { + setup(); + + set_caller_address(OWNER()); + ERC721::set_approval_for_all(OPERATOR(), true); + + set_caller_address(OPERATOR()); + ERC721::approve(SPENDER(), TOKEN_ID()); + assert(ERC721::get_approved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: unauthorized caller', ))] +fn test_approve_from_unauthorized() { + setup(); + + set_caller_address(OTHER()); + ERC721::approve(SPENDER(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: approval to owner', ))] +fn test_approve_to_owner() { + setup(); + + set_caller_address(OWNER()); + ERC721::approve(OWNER(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test_approve_nonexistent() { + ERC721::approve(SPENDER(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +fn test__approve() { + setup(); + + ERC721::_approve(SPENDER(), TOKEN_ID()); + assert(ERC721::get_approved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: approval to owner', ))] +fn test__approve_to_owner() { + setup(); + + ERC721::_approve(OWNER(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test__approve_nonexistent() { + ERC721::_approve(SPENDER(), TOKEN_ID()); +} + +/// +/// set_approval_for_all & _set_approval_for_all +/// + +#[test] +#[available_gas(2000000)] +fn test_set_approval_for_all() { + set_caller_address(OWNER()); + assert(!ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Invalid default value'); + + ERC721::set_approval_for_all(OPERATOR(), true); + assert(ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + + ERC721::set_approval_for_all(OPERATOR(), false); + assert(!ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Approval not revoked correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: self approval', ))] +fn test_set_approval_for_all_owner_equal_operator_true() { + set_caller_address(OWNER()); + ERC721::set_approval_for_all(OWNER(), true); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: self approval', ))] +fn test_set_approval_for_all_owner_equal_operator_false() { + set_caller_address(OWNER()); + ERC721::set_approval_for_all(OWNER(), false); +} + +#[test] +#[available_gas(2000000)] +fn test__set_approval_for_all() { + assert(!ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Invalid default value'); + + ERC721::_set_approval_for_all(OWNER(), OPERATOR(), true); + assert(ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + + ERC721::_set_approval_for_all(OWNER(), OPERATOR(), false); + assert(!ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: self approval', ))] +fn test__set_approval_for_all_owner_equal_operator_true() { + ERC721::_set_approval_for_all(OWNER(), OWNER(), true); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: self approval', ))] +fn test__set_approval_for_all_owner_equal_operator_false() { + ERC721::_set_approval_for_all(OWNER(), OWNER(), false); +} + +/// +/// transfer_from +/// + +#[test] +#[available_gas(2000000)] +fn test_transfer_from_owner() { + setup(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + let recipient = RECIPIENT(); + // set approval to check reset + ERC721::_approve(OTHER(), token_id); + + assert_state_before_transfer(token_id, owner, recipient); + assert(ERC721::get_approved(token_id) == OTHER(), 'Approval not implicitly reset'); + + set_caller_address(owner); + ERC721::transfer_from(owner, recipient, token_id); + + assert_state_after_transfer(token_id, owner, recipient); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test_transfer_from_nonexistent() { + ERC721::transfer_from(ZERO(), RECIPIENT(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid receiver', ))] +fn test_transfer_from_to_zero() { + setup(); + + set_caller_address(OWNER()); + ERC721::transfer_from(OWNER(), ZERO(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from_to_owner() { + setup(); + + assert(ERC721::owner_of(TOKEN_ID()) == OWNER(), 'Ownership before'); + assert(ERC721::balance_of(OWNER()) == 1.into(), 'Balance of owner before'); + + set_caller_address(OWNER()); + ERC721::transfer_from(OWNER(), OWNER(), TOKEN_ID()); + + assert(ERC721::owner_of(TOKEN_ID()) == OWNER(), 'Ownership after'); + assert(ERC721::balance_of(OWNER()) == 1.into(), 'Balance of owner after'); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from_approved() { + setup(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + let recipient = RECIPIENT(); + assert_state_before_transfer(token_id, owner, recipient); + + set_caller_address(owner); + ERC721::approve(OPERATOR(), token_id); + + set_caller_address(OPERATOR()); + ERC721::transfer_from(owner, recipient, token_id); + + assert_state_after_transfer(token_id, owner, recipient); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from_approved_for_all() { + setup(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + let recipient = RECIPIENT(); + + assert_state_before_transfer(token_id, owner, recipient); + + set_caller_address(owner); + ERC721::set_approval_for_all(OPERATOR(), true); + + set_caller_address(OPERATOR()); + ERC721::transfer_from(owner, recipient, token_id); + + assert_state_after_transfer(token_id, owner, recipient); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: unauthorized caller', ))] +fn test_transfer_from_unauthorized() { + setup(); + + set_caller_address(OTHER()); + ERC721::transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); +} + +// +// safe_transfer_from +// + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_to_account() { + setup(); + let account = setup_account(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, account); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, account, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, account); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_to_receiver() { + setup(); + let receiver = setup_receiver(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: safe transfer failed', ))] +fn test_safe_transfer_from_to_receiver_failure() { + setup(); + let receiver = setup_receiver(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, receiver, token_id, DATA(false)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_safe_transfer_from_to_non_receiver() { + setup(); + let recipient = utils::deploy(ERC721NonReceiver::TEST_CLASS_HASH, ArrayTrait::new()); + let token_id = TOKEN_ID(); + let owner = OWNER(); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, recipient, token_id, DATA(true)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test_safe_transfer_from_nonexistent() { + ERC721::safe_transfer_from(ZERO(), RECIPIENT(), TOKEN_ID(), DATA(true)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid receiver', ))] +fn test_safe_transfer_from_to_zero() { + setup(); + + set_caller_address(OWNER()); + ERC721::safe_transfer_from(OWNER(), ZERO(), TOKEN_ID(), DATA(true)); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_to_owner() { + let token_id = TOKEN_ID(); + let owner = setup_receiver(); + ERC721::initializer(NAME, SYMBOL); + ERC721::_mint(owner, token_id); + + assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); + assert(ERC721::balance_of(owner) == 1.into(), 'Balance of owner before'); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, owner, token_id, DATA(true)); + + assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); + assert(ERC721::balance_of(owner) == 1.into(), 'Balance of owner after'); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_approved() { + setup(); + let receiver = setup_receiver(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::approve(OPERATOR(), token_id); + + set_caller_address(OPERATOR()); + ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_approved_for_all() { + setup(); + let receiver = setup_receiver(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::set_approval_for_all(OPERATOR(), true); + + set_caller_address(OPERATOR()); + ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: unauthorized caller', ))] +fn test_safe_transfer_from_unauthorized() { + setup(); + set_caller_address(OTHER()); + ERC721::safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID(), DATA(true)); +} + +// +// __transfer +// + +#[test] +#[available_gas(2000000)] +fn test__transfer() { + setup(); + let token_id = TOKEN_ID(); + let owner = OWNER(); + let recipient = RECIPIENT(); + + assert_state_before_transfer(token_id, owner, recipient); + ERC721::_transfer(owner, recipient, token_id); + assert_state_after_transfer(token_id, owner, recipient); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test__transfer_nonexistent() { + ERC721::_transfer(ZERO(), RECIPIENT(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid receiver', ))] +fn test__transfer_to_zero() { + setup(); + + ERC721::_transfer(OWNER(), ZERO(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: wrong sender', ))] +fn test__transfer_from_invalid_owner() { + setup(); + + ERC721::_transfer(RECIPIENT(), OWNER(), TOKEN_ID()); +} + +/// +/// Mint +/// + +#[test] +#[available_gas(2000000)] +fn test__mint() { + let recipient = RECIPIENT(); + let token_id = TOKEN_ID(); + assert_state_before_mint(recipient); + ERC721::_mint(RECIPIENT(), TOKEN_ID()); + assert_state_after_mint(token_id, recipient); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid receiver', ))] +fn test__mint_to_zero() { + ERC721::_mint(ZERO(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: token already minted', ))] +fn test__mint_already_exist() { + setup(); + + ERC721::_mint(RECIPIENT(), TOKEN_ID()); +} + +/// +/// _safe_mint +/// + +#[test] +#[available_gas(2000000)] +fn test__safe_mint_to_receiver() { + let recipient = setup_receiver(); + let token_id = TOKEN_ID(); + + assert_state_before_mint(recipient); + ERC721::_safe_mint(recipient, token_id, DATA(true)); + assert_state_after_mint(token_id, recipient); +} + +#[test] +#[available_gas(2000000)] +fn test__safe_mint_to_account() { + let account = setup_account(); + let token_id = TOKEN_ID(); + + assert_state_before_mint(account); + ERC721::_safe_mint(account, token_id, DATA(true)); + assert_state_after_mint(token_id, account); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test__safe_mint_to_non_receiver() { + let recipient = utils::deploy(ERC721NonReceiver::TEST_CLASS_HASH, ArrayTrait::new()); + let token_id = TOKEN_ID(); + + assert_state_before_mint(recipient); + ERC721::_safe_mint(recipient, token_id, DATA(true)); + assert_state_after_mint(token_id, recipient); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: safe mint failed', ))] +fn test__safe_mint_to_receiver_failure() { + let recipient = setup_receiver(); + let token_id = TOKEN_ID(); + + assert_state_before_mint(recipient); + ERC721::_safe_mint(recipient, token_id, DATA(false)); + assert_state_after_mint(token_id, recipient); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid receiver', ))] +fn test__safe_mint_to_zero() { + ERC721::_safe_mint(ZERO(), TOKEN_ID(), DATA(true)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: token already minted', ))] +fn test__safe_mint_already_exist() { + setup(); + ERC721::_safe_mint(RECIPIENT(), TOKEN_ID(), DATA(true)); +} + +/// +/// Burn +/// + +#[test] +#[available_gas(2000000)] +fn test__burn() { + setup(); + + ERC721::_approve(OTHER(), TOKEN_ID()); + + assert(ERC721::owner_of(TOKEN_ID()) == OWNER(), 'Ownership before'); + assert(ERC721::balance_of(OWNER()) == 1.into(), 'Balance of owner before'); + assert(ERC721::get_approved(TOKEN_ID()) == OTHER(), 'Approval before'); + + ERC721::_burn(TOKEN_ID()); + + assert(ERC721::_owners::read(TOKEN_ID()) == ZERO(), 'Ownership after'); + assert(ERC721::balance_of(OWNER()) == 0.into(), 'Balance of owner after'); + assert(ERC721::_token_approvals::read(TOKEN_ID()) == ZERO(), 'Approval after'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test__burn_nonexistent() { + ERC721::_burn(TOKEN_ID()); +} + +/// +/// _set_token_uri +/// + +#[test] +#[available_gas(2000000)] +fn test__set_token_uri() { + setup(); + + assert(ERC721::token_uri(TOKEN_ID()) == 0, 'URI should be 0'); + ERC721::_set_token_uri(TOKEN_ID(), URI); + assert(ERC721::token_uri(TOKEN_ID()) == URI, 'URI should be set'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test__set_token_uri_nonexistent() { + ERC721::_set_token_uri(TOKEN_ID(), URI); +} + +// +// Helpers +// + +fn assert_state_before_transfer( + token_id: u256, owner: ContractAddress, recipient: ContractAddress +) { + assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); + assert(ERC721::balance_of(owner) == 1.into(), 'Balance of owner before'); + assert(ERC721::balance_of(recipient) == 0.into(), 'Balance of recipient before'); +} + +fn assert_state_after_transfer(token_id: u256, owner: ContractAddress, recipient: ContractAddress) { + assert(ERC721::owner_of(token_id) == recipient, 'Ownership after'); + assert(ERC721::balance_of(owner) == 0.into(), 'Balance of owner after'); + assert(ERC721::balance_of(recipient) == 1.into(), 'Balance of recipient after'); + assert(ERC721::get_approved(token_id) == ZERO(), 'Approval not implicitly reset'); +} + +fn assert_state_before_mint(recipient: ContractAddress) { + assert(ERC721::balance_of(recipient) == 0.into(), 'Balance of recipient before'); +} + +fn assert_state_after_mint(token_id: u256, recipient: ContractAddress) { + assert(ERC721::owner_of(token_id) == recipient, 'Ownership after'); + assert(ERC721::balance_of(recipient) == 1.into(), 'Balance of recipient after'); + assert(ERC721::get_approved(token_id) == ZERO(), 'Approval implicitly set'); +} diff --git a/src/openzeppelin/token.cairo b/src/openzeppelin/token.cairo index bfe4665e0..f9a848d01 100644 --- a/src/openzeppelin/token.cairo +++ b/src/openzeppelin/token.cairo @@ -1 +1,2 @@ mod erc20; +mod erc721; diff --git a/src/openzeppelin/token/erc721.cairo b/src/openzeppelin/token/erc721.cairo new file mode 100644 index 000000000..2dde68df8 --- /dev/null +++ b/src/openzeppelin/token/erc721.cairo @@ -0,0 +1,3 @@ +mod erc721; +use erc721::ERC721; +mod interface; diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/openzeppelin/token/erc721/erc721.cairo new file mode 100644 index 000000000..e22466078 --- /dev/null +++ b/src/openzeppelin/token/erc721/erc721.cairo @@ -0,0 +1,462 @@ +use starknet::ContractAddress; + +#[abi] +trait ERC721ABI { + // case agnostic + #[view] + fn name() -> felt252; + #[view] + fn symbol() -> felt252; + #[external] + fn approve(to: ContractAddress, token_id: u256); + // snake_case + #[view] + fn balance_of(account: ContractAddress) -> u256; + #[view] + fn owner_of(token_id: u256) -> ContractAddress; + #[external] + fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256); + #[external] + fn safe_transfer_from( + from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ); + #[external] + fn set_approval_for_all(operator: ContractAddress, approved: bool); + #[view] + fn get_approved(token_id: u256) -> ContractAddress; + #[view] + fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool; + #[view] + fn token_uri(token_id: u256) -> felt252; + // camelCase + #[view] + fn balanceOf(account: ContractAddress) -> u256; + #[view] + fn ownerOf(tokenId: u256) -> ContractAddress; + #[external] + fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256); + #[external] + fn safeTransferFrom( + from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ); + #[external] + fn setApprovalForAll(operator: ContractAddress, approved: bool); + #[view] + fn getApproved(tokenId: u256) -> ContractAddress; + #[view] + fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool; + #[view] + fn tokenUri(tokenId: u256) -> felt252; +} + +#[contract] +mod ERC721 { + // OZ modules + use openzeppelin::account; + use openzeppelin::introspection::erc165; + use openzeppelin::token::erc721; + + // Dispatchers + use openzeppelin::introspection::erc165::IERC165Dispatcher; + use openzeppelin::introspection::erc165::IERC165DispatcherTrait; + use super::super::interface::IERC721ReceiverABIDispatcher; + use super::super::interface::IERC721ReceiverABIDispatcherTrait; + + // Other + use starknet::ContractAddress; + use starknet::get_caller_address; + use zeroable::Zeroable; + use option::OptionTrait; + use array::SpanTrait; + use traits::Into; + use openzeppelin::utils::serde::SpanSerde; + + struct Storage { + _name: felt252, + _symbol: felt252, + _owners: LegacyMap, + _balances: LegacyMap, + _token_approvals: LegacyMap, + _operator_approvals: LegacyMap<(ContractAddress, ContractAddress), bool>, + _token_uri: LegacyMap, + } + + #[event] + fn Transfer(from: ContractAddress, to: ContractAddress, token_id: u256) {} + + #[event] + fn Approval(owner: ContractAddress, approved: ContractAddress, token_id: u256) {} + + #[event] + fn ApprovalForAll(owner: ContractAddress, operator: ContractAddress, approved: bool) {} + + #[constructor] + fn constructor(name: felt252, symbol: felt252) { + initializer(name, symbol); + } + + impl ERC721Impl of erc721::interface::IERC721 { + fn name() -> felt252 { + _name::read() + } + + fn symbol() -> felt252 { + _symbol::read() + } + + fn token_uri(token_id: u256) -> felt252 { + assert(_exists(token_id), 'ERC721: invalid token ID'); + _token_uri::read(token_id) + } + + fn balance_of(account: ContractAddress) -> u256 { + assert(!account.is_zero(), 'ERC721: invalid account'); + _balances::read(account) + } + + fn owner_of(token_id: u256) -> ContractAddress { + _owner_of(token_id) + } + + fn get_approved(token_id: u256) -> ContractAddress { + assert(_exists(token_id), 'ERC721: invalid token ID'); + _token_approvals::read(token_id) + } + + fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool { + _operator_approvals::read((owner, operator)) + } + + fn approve(to: ContractAddress, token_id: u256) { + let owner = _owner_of(token_id); + + let caller = get_caller_address(); + assert( + owner == caller | is_approved_for_all(owner, caller), 'ERC721: unauthorized caller' + ); + _approve(to, token_id); + } + + fn set_approval_for_all(operator: ContractAddress, approved: bool) { + _set_approval_for_all(get_caller_address(), operator, approved) + } + + fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) { + assert( + _is_approved_or_owner(get_caller_address(), token_id), 'ERC721: unauthorized caller' + ); + _transfer(from, to, token_id); + } + + fn safe_transfer_from( + from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ) { + assert( + _is_approved_or_owner(get_caller_address(), token_id), 'ERC721: unauthorized caller' + ); + _safe_transfer(from, to, token_id, data); + } + } + + impl ERC721CamelImpl of erc721::interface::IERC721Camel { + fn name() -> felt252 { + ERC721Impl::name() + } + + fn symbol() -> felt252 { + ERC721Impl::symbol() + } + + fn tokenUri(tokenId: u256) -> felt252 { + ERC721Impl::token_uri(tokenId) + } + + fn balanceOf(account: ContractAddress) -> u256 { + ERC721Impl::balance_of(account) + } + + fn ownerOf(tokenId: u256) -> ContractAddress { + ERC721Impl::owner_of(tokenId) + } + + fn approve(to: ContractAddress, tokenId: u256) { + ERC721Impl::approve(to, tokenId) + } + + fn getApproved(tokenId: u256) -> ContractAddress { + ERC721Impl::get_approved(tokenId) + } + + fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool { + ERC721Impl::is_approved_for_all(owner, operator) + } + + fn setApprovalForAll(operator: ContractAddress, approved: bool) { + ERC721Impl::set_approval_for_all(operator, approved) + } + + fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256) { + ERC721Impl::transfer_from(from, to, tokenId) + } + + fn safeTransferFrom( + from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ) { + ERC721Impl::safe_transfer_from(from, to, tokenId, data) + } + } + + // View + + #[view] + fn supports_interface(interface_id: u32) -> bool { + erc165::ERC165::supports_interface(interface_id) + } + + #[view] + fn supportsInterface(interfaceId: u32) -> bool { + erc165::ERC165::supports_interface(interfaceId) + } + + #[view] + fn name() -> felt252 { + ERC721Impl::name() + } + + #[view] + fn symbol() -> felt252 { + ERC721Impl::symbol() + } + + #[view] + fn token_uri(token_id: u256) -> felt252 { + ERC721Impl::token_uri(token_id) + } + + #[view] + fn tokenUri(tokenId: u256) -> felt252 { + ERC721CamelImpl::tokenUri(tokenId) + } + + #[view] + fn balance_of(account: ContractAddress) -> u256 { + ERC721Impl::balance_of(account) + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + ERC721CamelImpl::balanceOf(account) + } + + #[view] + fn owner_of(token_id: u256) -> ContractAddress { + ERC721Impl::owner_of(token_id) + } + + #[view] + fn ownerOf(tokenId: u256) -> ContractAddress { + ERC721CamelImpl::ownerOf(tokenId) + } + + #[view] + fn get_approved(token_id: u256) -> ContractAddress { + ERC721Impl::get_approved(token_id) + } + + #[view] + fn getApproved(tokenId: u256) -> ContractAddress { + ERC721CamelImpl::getApproved(tokenId) + } + + #[view] + fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool { + ERC721Impl::is_approved_for_all(owner, operator) + } + + #[view] + fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool { + ERC721CamelImpl::isApprovedForAll(owner, operator) + } + + // External + + #[external] + fn approve(to: ContractAddress, token_id: u256) { + ERC721Impl::approve(to, token_id) + } + + #[external] + fn set_approval_for_all(operator: ContractAddress, approved: bool) { + ERC721Impl::set_approval_for_all(operator, approved) + } + + #[external] + fn setApprovalForAll(operator: ContractAddress, approved: bool) { + ERC721CamelImpl::setApprovalForAll(operator, approved) + } + + #[external] + fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) { + ERC721Impl::transfer_from(from, to, token_id) + } + + #[external] + fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256) { + ERC721CamelImpl::transferFrom(from, to, tokenId) + } + + #[external] + fn safe_transfer_from( + from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ) { + ERC721Impl::safe_transfer_from(from, to, token_id, data) + } + + #[external] + fn safeTransferFrom( + from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ) { + ERC721CamelImpl::safeTransferFrom(from, to, tokenId, data) + } + + // Internal + + #[internal] + fn initializer(name_: felt252, symbol_: felt252) { + _name::write(name_); + _symbol::write(symbol_); + erc165::ERC165::register_interface(erc721::interface::IERC721_ID); + erc165::ERC165::register_interface(erc721::interface::IERC721_METADATA_ID); + } + + #[internal] + fn _owner_of(token_id: u256) -> ContractAddress { + let owner = _owners::read(token_id); + match owner.is_zero() { + bool::False(()) => owner, + bool::True(()) => panic_with_felt252('ERC721: invalid token ID') + } + } + + #[internal] + fn _exists(token_id: u256) -> bool { + !_owners::read(token_id).is_zero() + } + + #[internal] + fn _is_approved_or_owner(spender: ContractAddress, token_id: u256) -> bool { + let owner = _owner_of(token_id); + owner == spender | is_approved_for_all(owner, spender) | spender == get_approved(token_id) + } + + #[internal] + fn _approve(to: ContractAddress, token_id: u256) { + let owner = _owner_of(token_id); + assert(owner != to, 'ERC721: approval to owner'); + _token_approvals::write(token_id, to); + Approval(owner, to, token_id); + } + + #[internal] + fn _set_approval_for_all(owner: ContractAddress, operator: ContractAddress, approved: bool) { + assert(owner != operator, 'ERC721: self approval'); + _operator_approvals::write((owner, operator), approved); + ApprovalForAll(owner, operator, approved); + } + + #[internal] + fn _mint(to: ContractAddress, token_id: u256) { + assert(!to.is_zero(), 'ERC721: invalid receiver'); + assert(!_exists(token_id), 'ERC721: token already minted'); + + // Update balances + _balances::write(to, _balances::read(to) + 1.into()); + + // Update token_id owner + _owners::write(token_id, to); + + // Emit event + Transfer(Zeroable::zero(), to, token_id); + } + + #[internal] + fn _transfer(from: ContractAddress, to: ContractAddress, token_id: u256) { + assert(!to.is_zero(), 'ERC721: invalid receiver'); + let owner = _owner_of(token_id); + assert(from == owner, 'ERC721: wrong sender'); + + // Implicit clear approvals, no need to emit an event + _token_approvals::write(token_id, Zeroable::zero()); + + // Update balances + _balances::write(from, _balances::read(from) - 1.into()); + _balances::write(to, _balances::read(to) + 1.into()); + + // Update token_id owner + _owners::write(token_id, to); + + // Emit event + Transfer(from, to, token_id); + } + + #[internal] + fn _burn(token_id: u256) { + let owner = _owner_of(token_id); + + // Implicit clear approvals, no need to emit an event + _token_approvals::write(token_id, Zeroable::zero()); + + // Update balances + _balances::write(owner, _balances::read(owner) - 1.into()); + + // Delete owner + _owners::write(token_id, Zeroable::zero()); + + // Emit event + Transfer(owner, Zeroable::zero(), token_id); + } + + #[internal] + fn _safe_mint(to: ContractAddress, token_id: u256, data: Span) { + _mint(to, token_id); + assert( + _check_on_erc721_received(Zeroable::zero(), to, token_id, data), + 'ERC721: safe mint failed' + ); + } + + #[internal] + fn _safe_transfer( + from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ) { + _transfer(from, to, token_id); + assert(_check_on_erc721_received(from, to, token_id, data), 'ERC721: safe transfer failed'); + } + + #[internal] + fn _set_token_uri(token_id: u256, token_uri: felt252) { + assert(_exists(token_id), 'ERC721: invalid token ID'); + _token_uri::write(token_id, token_uri) + } + + #[private] + fn _check_on_erc721_received( + from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ) -> bool { + if (IERC165Dispatcher { + contract_address: to + }.supports_interface(erc721::interface::IERC721_RECEIVER_ID)) { + // todo add casing fallback mechanism + IERC721ReceiverABIDispatcher { + contract_address: to + } + .on_erc721_received( + get_caller_address(), from, token_id, data + ) == erc721::interface::IERC721_RECEIVER_ID + } else { + IERC165Dispatcher { + contract_address: to + }.supports_interface(account::interface::IACCOUNT_ID) + } + } +} diff --git a/src/openzeppelin/token/erc721/interface.cairo b/src/openzeppelin/token/erc721/interface.cairo new file mode 100644 index 000000000..a8b21f60e --- /dev/null +++ b/src/openzeppelin/token/erc721/interface.cairo @@ -0,0 +1,71 @@ +use openzeppelin::utils::serde::SpanSerde; +use starknet::ContractAddress; +use array::SpanTrait; + +const IERC721_ID: u32 = 0x80ac58cd_u32; +const IERC721_METADATA_ID: u32 = 0x5b5e139f_u32; +const IERC721_RECEIVER_ID: u32 = 0x150b7a02_u32; + +#[abi] +trait IERC721 { + fn balance_of(account: ContractAddress) -> u256; + fn owner_of(token_id: u256) -> ContractAddress; + fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256); + fn safe_transfer_from( + from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ); + fn approve(to: ContractAddress, token_id: u256); + fn set_approval_for_all(operator: ContractAddress, approved: bool); + fn get_approved(token_id: u256) -> ContractAddress; + fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool; + // IERC721Metadata + fn name() -> felt252; + fn symbol() -> felt252; + fn token_uri(token_id: u256) -> felt252; +} + +#[abi] +trait IERC721Camel { + fn balanceOf(account: ContractAddress) -> u256; + fn ownerOf(tokenId: u256) -> ContractAddress; + fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256); + fn safeTransferFrom( + from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ); + fn approve(to: ContractAddress, tokenId: u256); + fn setApprovalForAll(operator: ContractAddress, approved: bool); + fn getApproved(tokenId: u256) -> ContractAddress; + fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool; + // IERC721Metadata + fn name() -> felt252; + fn symbol() -> felt252; + fn tokenUri(tokenId: u256) -> felt252; +} + +// +// ERC721Receiver +// + +#[abi] +trait IERC721ReceiverABI { + fn on_erc721_received( + operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + ) -> u32; + fn onERC721Received( + operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + ) -> u32; +} + +#[abi] +trait IERC721Receiver { + fn on_erc721_received( + operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + ) -> u32; +} + +#[abi] +trait IERC721ReceiverCamel { + fn onERC721Received( + operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + ) -> u32; +} diff --git a/src/openzeppelin/utils.cairo b/src/openzeppelin/utils.cairo index c8a47ceb8..8dab269b1 100644 --- a/src/openzeppelin/utils.cairo +++ b/src/openzeppelin/utils.cairo @@ -3,6 +3,7 @@ use array::SpanTrait; use box::BoxTrait; use option::OptionTrait; mod constants; +mod serde; #[inline(always)] fn check_gas() { diff --git a/src/openzeppelin/utils/serde.cairo b/src/openzeppelin/utils/serde.cairo new file mode 100644 index 000000000..68c3720f0 --- /dev/null +++ b/src/openzeppelin/utils/serde.cairo @@ -0,0 +1,19 @@ +use array::ArrayTrait; +use array::SpanTrait; +use serde::Serde; +use serde::serialize_array_helper; +use serde::deserialize_array_helper; + +impl SpanSerde< + T, impl TSerde: Serde, impl TCopy: Copy, impl TDrop: Drop +> of Serde> { + fn serialize(self: @Span, ref output: Array) { + (*self).len().serialize(ref output); + serialize_array_helper(*self, ref output); + } + fn deserialize(ref serialized: Span) -> Option> { + let length = *serialized.pop_front()?; + let mut arr = ArrayTrait::new(); + Option::Some(deserialize_array_helper(ref serialized, arr, length)?.span()) + } +} From 62688e797d20fd3aafc1a86b3b60aa02eab212bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Sun, 2 Jul 2023 19:32:03 -0300 Subject: [PATCH 052/124] Dual interface dispatcher for ERC721 (#623) * add dual interface dispatcher draft * complete dual721 implementation * fix format * add felt252 <> bool casts * simplify Felt252IntoBool * make felt252 into -> try_into * add base test suite * implement most tests * add mocks * add tests for panic cases * fix some tests * fix format * fix more tests * fix tests * apply review feedback * normalize mock names * add token_uri tests * rename non implementing mock * move comment * upgrade to cairo 1.1.1 * Update src/openzeppelin/utils.cairo Co-authored-by: Eric Nordelo * address review comments --------- Co-authored-by: Eric Nordelo --- Cargo.lock | 56 +- Cargo.toml | 2 +- cairo | 2 +- src/openzeppelin/tests.cairo | 1 + src/openzeppelin/tests/mocks.cairo | 4 + .../tests/mocks/camel721_mock.cairo | 80 +++ .../tests/mocks/erc721_panic_mock.cairo | 139 +++++ .../tests/mocks/non_implementing_mock.cairo | 7 + .../tests/mocks/snake721_mock.cairo | 80 +++ src/openzeppelin/tests/test_account.cairo | 2 +- src/openzeppelin/tests/test_dual721.cairo | 525 ++++++++++++++++++ src/openzeppelin/tests/utils.cairo | 7 +- src/openzeppelin/token/erc721.cairo | 1 + src/openzeppelin/token/erc721/dual721.cairo | 198 +++++++ src/openzeppelin/utils.cairo | 43 +- src/openzeppelin/utils/selectors.cairo | 27 + 16 files changed, 1140 insertions(+), 34 deletions(-) create mode 100644 src/openzeppelin/tests/mocks/camel721_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/erc721_panic_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/non_implementing_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/snake721_mock.cairo create mode 100644 src/openzeppelin/tests/test_dual721.cairo create mode 100644 src/openzeppelin/token/erc721/dual721.cairo create mode 100644 src/openzeppelin/utils/selectors.cairo diff --git a/Cargo.lock b/Cargo.lock index 85aa935ae..a5ca15c63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,7 +301,7 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-utils", "env_logger", @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "anyhow", "cairo-lang-defs", @@ -343,7 +343,7 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-proc-macros", "cairo-lang-utils", @@ -354,7 +354,7 @@ dependencies = [ [[package]] name = "cairo-lang-defs" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -375,7 +375,7 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-filesystem", "cairo-lang-proc-macros", @@ -390,7 +390,7 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-utils", "env_logger", @@ -404,7 +404,7 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -419,7 +419,7 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -442,7 +442,7 @@ dependencies = [ [[package]] name = "cairo-lang-language-server" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -474,7 +474,7 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -503,7 +503,7 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -527,7 +527,7 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -550,7 +550,7 @@ dependencies = [ [[package]] name = "cairo-lang-proc-macros" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-debug", "quote", @@ -559,7 +559,7 @@ dependencies = [ [[package]] name = "cairo-lang-project" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-filesystem", "indoc", @@ -572,7 +572,7 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "anyhow", "ark-ff 0.4.0-alpha.7", @@ -607,7 +607,7 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "assert_matches", "cairo-lang-debug", @@ -636,7 +636,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "assert_matches", "bimap", @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -679,7 +679,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -696,7 +696,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -727,7 +727,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "anyhow", "assert_matches", @@ -752,7 +752,7 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "anyhow", "cairo-felt", @@ -796,7 +796,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -814,7 +814,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-utils", "env_logger", @@ -826,7 +826,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-runner" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "anyhow", "cairo-felt", @@ -860,7 +860,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-utils" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "cairo-lang-utils", "env_logger", @@ -871,7 +871,7 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "env_logger", "indexmap", @@ -2761,7 +2761,7 @@ dependencies = [ [[package]] name = "tests" -version = "1.0.0-rc0" +version = "1.1.1" dependencies = [ "assert_matches", "cairo-felt", diff --git a/Cargo.toml b/Cargo.toml index 49e71907f..3927b6991 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ members = [ ] [workspace.package] -version = "1.0.0-rc0" +version = "1.1.1" edition = "2021" repository = "https://github.com/starkware-libs/cairo/" license = "Apache-2.0" diff --git a/cairo b/cairo index ee9a0bb1e..c6b003cc4 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit ee9a0bb1e496c6e5d922c3a5071d85b45f8bc268 +Subproject commit c6b003cc425907ac5fc846375a48737d5125f5b5 diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 5aa74d96f..fd9d9d0c0 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -5,6 +5,7 @@ mod test_erc165; mod test_account; mod test_erc20; mod test_erc721; +mod test_dual721; mod test_initializable; mod test_pausable; mod mocks; diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index b8f645b23..4ab029428 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -1,4 +1,8 @@ mod reentrancy_attacker_mock; mod reentrancy_mock; mod erc721_receiver; +mod erc721_panic_mock; mod mock_pausable; +mod snake721_mock; +mod camel721_mock; +mod non_implementing_mock; diff --git a/src/openzeppelin/tests/mocks/camel721_mock.cairo b/src/openzeppelin/tests/mocks/camel721_mock.cairo new file mode 100644 index 000000000..2b2715ec9 --- /dev/null +++ b/src/openzeppelin/tests/mocks/camel721_mock.cairo @@ -0,0 +1,80 @@ +#[contract] +mod CamelERC721Mock { + use starknet::ContractAddress; + use starknet::get_caller_address; + use openzeppelin::token::erc721::ERC721; + use openzeppelin::utils::serde::SpanSerde; + + #[constructor] + fn constructor(name: felt252, symbol: felt252, tokenId: u256, uri: felt252) { + ERC721::initializer(name, symbol); + ERC721::_mint(get_caller_address(), tokenId); + ERC721::_set_token_uri(tokenId, uri); + } + + // View + + #[view] + fn supportsInterface(interfaceId: u32) -> bool { + ERC721::supports_interface(interfaceId) + } + + #[view] + fn name() -> felt252 { + ERC721::name() + } + + #[view] + fn symbol() -> felt252 { + ERC721::symbol() + } + + #[view] + fn tokenUri(tokenId: u256) -> felt252 { + ERC721::tokenUri(tokenId) + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + ERC721::balanceOf(account) + } + + #[view] + fn ownerOf(tokenId: u256) -> ContractAddress { + ERC721::ownerOf(tokenId) + } + + #[view] + fn getApproved(tokenId: u256) -> ContractAddress { + ERC721::getApproved(tokenId) + } + + #[view] + fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool { + ERC721::isApprovedForAll(owner, operator) + } + + // External + + #[external] + fn approve(to: ContractAddress, tokenId: u256) { + ERC721::approve(to, tokenId) + } + + #[external] + fn setApprovalForAll(operator: ContractAddress, approved: bool) { + ERC721::setApprovalForAll(operator, approved) + } + + #[external] + fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256) { + ERC721::transferFrom(from, to, tokenId) + } + + #[external] + fn safeTransferFrom( + from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ) { + ERC721::safeTransferFrom(from, to, tokenId, data) + } +} diff --git a/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo b/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo new file mode 100644 index 000000000..d7f1702dd --- /dev/null +++ b/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo @@ -0,0 +1,139 @@ +// Although these modules are designed to panic, functions +// still need a valid return value. We chose: +// +// 3 for felt252 +// zero for ContractAddress +// u256 { 3, 3 } for u256 + +#[contract] +mod SnakeERC721PanicMock { + use openzeppelin::utils::serde::SpanSerde; + use starknet::ContractAddress; + use zeroable::Zeroable; + + // + // agnostic + // + + #[view] + fn name() -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn symbol() -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[external] + fn approve(to: ContractAddress, token_id: u256) { + panic_with_felt252('Some error'); + } + + // + // snake + // + + #[view] + fn token_uri(token_id: u256) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn balance_of(account: ContractAddress) -> u256 { + panic_with_felt252('Some error'); + u256 { low: 3, high: 3 } + } + + #[view] + fn owner_of(token_id: u256) -> ContractAddress { + panic_with_felt252('Some error'); + Zeroable::zero() + } + + #[view] + fn get_approved(token_id: u256) -> ContractAddress { + panic_with_felt252('Some error'); + Zeroable::zero() + } + + #[view] + fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool { + panic_with_felt252('Some error'); + false + } + + #[external] + fn set_approval_for_all(operator: ContractAddress, approved: bool) { + panic_with_felt252('Some error'); + } + + #[external] + fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) { + panic_with_felt252('Some error'); + } + + #[external] + fn safe_transfer_from( + from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ) { + panic_with_felt252('Some error'); + } +} + +#[contract] +mod CamelERC721PanicMock { + use openzeppelin::utils::serde::SpanSerde; + use starknet::ContractAddress; + use zeroable::Zeroable; + + #[view] + fn tokenUri(tokenId: u256) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + panic_with_felt252('Some error'); + u256 { low: 3, high: 3 } + } + + #[view] + fn ownerOf(tokenId: u256) -> ContractAddress { + panic_with_felt252('Some error'); + Zeroable::zero() + } + + #[view] + fn getApproved(tokenId: u256) -> ContractAddress { + panic_with_felt252('Some error'); + Zeroable::zero() + } + + #[view] + fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool { + panic_with_felt252('Some error'); + false + } + + #[external] + fn setApprovalForAll(operator: ContractAddress, approved: bool) { + panic_with_felt252('Some error'); + } + + #[external] + fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256) { + panic_with_felt252('Some error'); + } + + #[external] + fn safeTransferFrom( + from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ) { + panic_with_felt252('Some error'); + } +} diff --git a/src/openzeppelin/tests/mocks/non_implementing_mock.cairo b/src/openzeppelin/tests/mocks/non_implementing_mock.cairo new file mode 100644 index 000000000..d614d1da7 --- /dev/null +++ b/src/openzeppelin/tests/mocks/non_implementing_mock.cairo @@ -0,0 +1,7 @@ +#[contract] +mod NonImplementingMock { + #[view] + fn nope() -> bool { + false + } +} diff --git a/src/openzeppelin/tests/mocks/snake721_mock.cairo b/src/openzeppelin/tests/mocks/snake721_mock.cairo new file mode 100644 index 000000000..44f4e91d9 --- /dev/null +++ b/src/openzeppelin/tests/mocks/snake721_mock.cairo @@ -0,0 +1,80 @@ +#[contract] +mod SnakeERC721Mock { + use starknet::ContractAddress; + use starknet::get_caller_address; + use openzeppelin::token::erc721::ERC721; + use openzeppelin::utils::serde::SpanSerde; + + #[constructor] + fn constructor(name: felt252, symbol: felt252, token_id: u256, uri: felt252) { + ERC721::initializer(name, symbol); + ERC721::_mint(get_caller_address(), token_id); + ERC721::_set_token_uri(token_id, uri); + } + + // View + + #[view] + fn supports_interface(interface_id: u32) -> bool { + ERC721::supports_interface(interface_id) + } + + #[view] + fn name() -> felt252 { + ERC721::name() + } + + #[view] + fn symbol() -> felt252 { + ERC721::symbol() + } + + #[view] + fn token_uri(token_id: u256) -> felt252 { + ERC721::token_uri(token_id) + } + + #[view] + fn balance_of(account: ContractAddress) -> u256 { + ERC721::balance_of(account) + } + + #[view] + fn owner_of(token_id: u256) -> ContractAddress { + ERC721::owner_of(token_id) + } + + #[view] + fn get_approved(token_id: u256) -> ContractAddress { + ERC721::get_approved(token_id) + } + + #[view] + fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool { + ERC721::is_approved_for_all(owner, operator) + } + + // External + + #[external] + fn approve(to: ContractAddress, token_id: u256) { + ERC721::approve(to, token_id) + } + + #[external] + fn set_approval_for_all(operator: ContractAddress, approved: bool) { + ERC721::set_approval_for_all(operator, approved) + } + + #[external] + fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) { + ERC721::transfer_from(from, to, token_id) + } + + #[external] + fn safe_transfer_from( + from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ) { + ERC721::safe_transfer_from(from, to, token_id, data) + } +} diff --git a/src/openzeppelin/tests/test_account.cairo b/src/openzeppelin/tests/test_account.cairo index d53ba3259..210e91f50 100644 --- a/src/openzeppelin/tests/test_account.cairo +++ b/src/openzeppelin/tests/test_account.cairo @@ -79,7 +79,7 @@ fn setup_dispatcher(data: Option<@SignedTransactionData>) -> AccountABIDispatche fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispatcher { let name = 0; let symbol = 0; - let mut calldata = ArrayTrait::::new(); + let mut calldata = ArrayTrait::new(); calldata.append(name); calldata.append(symbol); diff --git a/src/openzeppelin/tests/test_dual721.cairo b/src/openzeppelin/tests/test_dual721.cairo new file mode 100644 index 000000000..98d7459f9 --- /dev/null +++ b/src/openzeppelin/tests/test_dual721.cairo @@ -0,0 +1,525 @@ +use traits::Into; +use array::ArrayTrait; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_caller_address; +use starknet::testing::set_contract_address; +use openzeppelin::token::erc721::interface::IERC721Dispatcher; +use openzeppelin::token::erc721::interface::IERC721CamelDispatcher; +use openzeppelin::token::erc721::interface::IERC721DispatcherTrait; +use openzeppelin::token::erc721::interface::IERC721CamelDispatcherTrait; +use openzeppelin::token::erc721::dual721::DualCaseERC721Trait; +use openzeppelin::token::erc721::dual721::DualCaseERC721; +use openzeppelin::tests::mocks::snake721_mock::SnakeERC721Mock; +use openzeppelin::tests::mocks::camel721_mock::CamelERC721Mock; +use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; +use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; +use openzeppelin::tests::mocks::erc721_receiver::FAILURE; +use openzeppelin::tests::mocks::erc721_panic_mock::SnakeERC721PanicMock; +use openzeppelin::tests::mocks::erc721_panic_mock::CamelERC721PanicMock; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils; + +/// +/// Constants +/// + +const NAME: felt252 = 111; +const SYMBOL: felt252 = 222; +const URI: felt252 = 333; + +fn TOKEN_ID() -> u256 { + 7.into() +} +fn OWNER() -> ContractAddress { + contract_address_const::<10>() +} +fn RECIPIENT() -> ContractAddress { + contract_address_const::<20>() +} +fn SPENDER() -> ContractAddress { + contract_address_const::<30>() +} +fn OPERATOR() -> ContractAddress { + contract_address_const::<40>() +} +fn DATA(success: bool) -> Span { + let mut data = ArrayTrait::new(); + if success { + data.append(SUCCESS); + } else { + data.append(FAILURE); + } + data.span() +} + +/// +/// Setup +/// + +fn setup_snake() -> (DualCaseERC721, IERC721Dispatcher) { + let mut calldata = ArrayTrait::new(); + calldata.append(NAME); + calldata.append(SYMBOL); + calldata.append(TOKEN_ID().low.into()); + calldata.append(TOKEN_ID().high.into()); + calldata.append(URI); + set_caller_address(OWNER()); + let target = utils::deploy(SnakeERC721Mock::TEST_CLASS_HASH, calldata); + (DualCaseERC721 { contract_address: target }, IERC721Dispatcher { contract_address: target }) +} + +fn setup_camel() -> (DualCaseERC721, IERC721CamelDispatcher) { + let mut calldata = ArrayTrait::new(); + calldata.append(NAME); + calldata.append(SYMBOL); + calldata.append(TOKEN_ID().low.into()); + calldata.append(TOKEN_ID().high.into()); + calldata.append(URI); + set_caller_address(OWNER()); + let target = utils::deploy(CamelERC721Mock::TEST_CLASS_HASH, calldata); + ( + DualCaseERC721 { + contract_address: target + }, IERC721CamelDispatcher { + contract_address: target + } + ) +} + +fn setup_non_erc721() -> DualCaseERC721 { + let calldata = ArrayTrait::new(); + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); + DualCaseERC721 { contract_address: target } +} + +fn setup_erc721_panic() -> (DualCaseERC721, DualCaseERC721) { + let snake_target = utils::deploy(SnakeERC721PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + let camel_target = utils::deploy(CamelERC721PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + ( + DualCaseERC721 { + contract_address: snake_target + }, DualCaseERC721 { + contract_address: camel_target + } + ) +} + +fn setup_receiver() -> ContractAddress { + utils::deploy(ERC721Receiver::TEST_CLASS_HASH, ArrayTrait::new()) +} + +/// +/// Case agnostic methods +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_name() { + let (snake_dispatcher, _) = setup_snake(); + let (camel_dispatcher, _) = setup_camel(); + assert(snake_dispatcher.name() == NAME, 'Should return name'); + assert(camel_dispatcher.name() == NAME, 'Should return name'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_name() { + let dispatcher = setup_non_erc721(); + dispatcher.name(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_name_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.name(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_symbol() { + let (snake_dispatcher, _) = setup_snake(); + let (camel_dispatcher, _) = setup_camel(); + assert(snake_dispatcher.symbol() == SYMBOL, 'Should return symbol'); + assert(camel_dispatcher.symbol() == SYMBOL, 'Should return symbol'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_symbol() { + let dispatcher = setup_non_erc721(); + dispatcher.symbol(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_symbol_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.symbol(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_approve() { + let (snake_dispatcher, snake_target) = setup_snake(); + set_contract_address(OWNER()); + snake_dispatcher.approve(SPENDER(), TOKEN_ID()); + assert(snake_target.get_approved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); + + let (camel_dispatcher, camel_target) = setup_camel(); + set_contract_address(OWNER()); + camel_dispatcher.approve(SPENDER(), TOKEN_ID()); + assert(camel_target.getApproved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_approve() { + let dispatcher = setup_non_erc721(); + dispatcher.approve(SPENDER(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_approve_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.approve(SPENDER(), TOKEN_ID()); +} + +/// +/// snake_case target +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_balance_of() { + let (dispatcher, _) = setup_snake(); + assert(dispatcher.balance_of(OWNER()) == 1, 'Should return balance'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_balance_of() { + let dispatcher = setup_non_erc721(); + dispatcher.balance_of(OWNER()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_balance_of_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.balance_of(OWNER()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_owner_of() { + let (dispatcher, target) = setup_snake(); + assert(dispatcher.owner_of(TOKEN_ID()) == OWNER(), 'Should return owner'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_owner_of() { + let dispatcher = setup_non_erc721(); + dispatcher.owner_of(TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_owner_of_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.owner_of(TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_transfer_from() { + let (dispatcher, target) = setup_snake(); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); + assert(target.owner_of(TOKEN_ID()) == RECIPIENT(), 'Should transfer token'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_transfer_from() { + let dispatcher = setup_non_erc721(); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_transfer_from_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_safe_transfer_from() { + let (dispatcher, target) = setup_snake(); + let receiver = setup_receiver(); + dispatcher.safe_transfer_from(OWNER(), receiver, TOKEN_ID(), DATA(true)); + assert(target.owner_of(TOKEN_ID()) == receiver, 'Should transfer token'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_safe_transfer_from() { + let dispatcher = setup_non_erc721(); + dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID(), DATA(true)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_safe_transfer_from_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID(), DATA(true)); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_get_approved() { + let (dispatcher, target) = setup_snake(); + set_contract_address(OWNER()); + target.approve(SPENDER(), TOKEN_ID()); + assert(dispatcher.get_approved(TOKEN_ID()) == SPENDER(), 'Should return approval'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_get_approved() { + let dispatcher = setup_non_erc721(); + dispatcher.get_approved(TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_get_approved_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.get_approved(TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_set_approval_for_all() { + let (dispatcher, target) = setup_snake(); + set_contract_address(OWNER()); + dispatcher.set_approval_for_all(OPERATOR(), true); + assert(target.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_set_approval_for_all() { + let dispatcher = setup_non_erc721(); + dispatcher.set_approval_for_all(OPERATOR(), true); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_set_approval_for_all_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.set_approval_for_all(OPERATOR(), true); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_is_approved_for_all() { + let (dispatcher, target) = setup_snake(); + set_contract_address(OWNER()); + target.set_approval_for_all(OPERATOR(), true); + assert(dispatcher.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_is_approved_for_all() { + let dispatcher = setup_non_erc721(); + dispatcher.is_approved_for_all(OWNER(), OPERATOR()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_is_approved_for_all_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.is_approved_for_all(OWNER(), OPERATOR()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_token_uri() { + let (dispatcher, target) = setup_snake(); + assert(dispatcher.token_uri(TOKEN_ID()) == URI, 'Should return URI'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_token_uri() { + let dispatcher = setup_non_erc721(); + dispatcher.token_uri(TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_token_uri_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.token_uri(TOKEN_ID()); +} + +/// +/// camelCase target +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_balanceOf() { + let (dispatcher, _) = setup_camel(); + assert(dispatcher.balance_of(OWNER()) == 1, 'Should return balance'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_balanceOf_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.balance_of(OWNER()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_ownerOf() { + let (dispatcher, target) = setup_camel(); + assert(dispatcher.owner_of(TOKEN_ID()) == OWNER(), 'Should return owner'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_ownerOf_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.owner_of(TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_transferFrom() { + let (dispatcher, target) = setup_camel(); + set_contract_address(OWNER()); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); + assert(target.ownerOf(TOKEN_ID()) == RECIPIENT(), 'Should transfer token'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_transferFrom_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_safeTransferFrom() { + let (dispatcher, target) = setup_camel(); + let receiver = setup_receiver(); + dispatcher.safe_transfer_from(OWNER(), receiver, TOKEN_ID(), DATA(true)); + assert(target.ownerOf(TOKEN_ID()) == receiver, 'Should transfer token'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_safeTransferFrom_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID(), DATA(true)); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_getApproved() { + let (dispatcher, target) = setup_camel(); + set_contract_address(OWNER()); + target.approve(SPENDER(), TOKEN_ID()); + assert(dispatcher.get_approved(TOKEN_ID()) == SPENDER(), 'Should return approval'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_getApproved_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.get_approved(TOKEN_ID()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_setApprovalForAll() { + let (dispatcher, target) = setup_camel(); + set_contract_address(OWNER()); + dispatcher.set_approval_for_all(OPERATOR(), true); + assert(target.isApprovedForAll(OWNER(), OPERATOR()), 'Operator not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_setApprovalForAll_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.set_approval_for_all(OPERATOR(), true); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_isApprovedForAll() { + let (dispatcher, target) = setup_camel(); + set_contract_address(OWNER()); + target.setApprovalForAll(OPERATOR(), true); + assert(dispatcher.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_isApprovedForAll_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.is_approved_for_all(OWNER(), OPERATOR()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_tokenUri() { + let (dispatcher, target) = setup_camel(); + assert(dispatcher.token_uri(TOKEN_ID()) == URI, 'Should return URI'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_tokenUri_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.token_uri(TOKEN_ID()); +} diff --git a/src/openzeppelin/tests/utils.cairo b/src/openzeppelin/tests/utils.cairo index d3b720cce..e0eaea264 100644 --- a/src/openzeppelin/tests/utils.cairo +++ b/src/openzeppelin/tests/utils.cairo @@ -1,9 +1,12 @@ -use array::ArrayTrait; use core::result::ResultTrait; use option::OptionTrait; +use array::ArrayTrait; +use traits::TryInto; +use traits::Into; + +use openzeppelin::utils::BoolIntoFelt252; use starknet::class_hash::Felt252TryIntoClassHash; use starknet::ContractAddress; -use traits::TryInto; fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { let (address, _) = starknet::deploy_syscall( diff --git a/src/openzeppelin/token/erc721.cairo b/src/openzeppelin/token/erc721.cairo index 2dde68df8..9b6c34399 100644 --- a/src/openzeppelin/token/erc721.cairo +++ b/src/openzeppelin/token/erc721.cairo @@ -1,3 +1,4 @@ mod erc721; use erc721::ERC721; mod interface; +mod dual721; diff --git a/src/openzeppelin/token/erc721/dual721.cairo b/src/openzeppelin/token/erc721/dual721.cairo new file mode 100644 index 000000000..e71b08874 --- /dev/null +++ b/src/openzeppelin/token/erc721/dual721.cairo @@ -0,0 +1,198 @@ +use core::result::ResultTrait; +use traits::Into; +use traits::TryInto; +use array::SpanTrait; +use array::ArrayTrait; +use option::OptionTrait; +use starknet::ContractAddress; +use starknet::SyscallResultTrait; +use starknet::call_contract_syscall; +use starknet::Felt252TryIntoContractAddress; +use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::Felt252TryIntoBool; +use openzeppelin::utils::BoolIntoFelt252; +use openzeppelin::utils::selectors; + +#[derive(Copy, Drop)] +struct DualCaseERC721 { + contract_address: ContractAddress +} + +trait DualCaseERC721Trait { + fn name(self: @DualCaseERC721) -> felt252; + fn symbol(self: @DualCaseERC721) -> felt252; + fn token_uri(self: @DualCaseERC721, token_id: u256) -> felt252; + fn balance_of(self: @DualCaseERC721, account: ContractAddress) -> u256; + fn owner_of(self: @DualCaseERC721, token_id: u256) -> ContractAddress; + fn get_approved(self: @DualCaseERC721, token_id: u256) -> ContractAddress; + fn approve(self: @DualCaseERC721, to: ContractAddress, token_id: u256); + fn set_approval_for_all(self: @DualCaseERC721, operator: ContractAddress, approved: bool); + fn transfer_from( + self: @DualCaseERC721, from: ContractAddress, to: ContractAddress, token_id: u256 + ); + fn is_approved_for_all( + self: @DualCaseERC721, owner: ContractAddress, operator: ContractAddress + ) -> bool; + fn safe_transfer_from( + self: @DualCaseERC721, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span + ); +} + +impl DualCaseERC721Impl of DualCaseERC721Trait { + fn name(self: @DualCaseERC721) -> felt252 { + *call_contract_syscall(*self.contract_address, selectors::name, ArrayTrait::new().span()) + .unwrap_syscall() + .at(0) + } + + fn symbol(self: @DualCaseERC721) -> felt252 { + *call_contract_syscall(*self.contract_address, selectors::symbol, ArrayTrait::new().span()) + .unwrap_syscall() + .at(0) + } + + fn token_uri(self: @DualCaseERC721, token_id: u256) -> felt252 { + let mut args = ArrayTrait::new(); + args.append(token_id.low.into()); + args.append(token_id.high.into()); + + *try_selector_with_fallback( + *self.contract_address, selectors::token_uri, selectors::tokenUri, args.span() + ) + .unwrap_syscall() + .at(0) + } + + fn balance_of(self: @DualCaseERC721, account: ContractAddress) -> u256 { + let mut args = ArrayTrait::new(); + args.append(account.into()); + + let res = try_selector_with_fallback( + *self.contract_address, selectors::balance_of, selectors::balanceOf, args.span() + ) + .unwrap_syscall(); + + u256 { low: (*res.at(0)).try_into().unwrap(), high: (*res.at(1)).try_into().unwrap(), } + } + + fn owner_of(self: @DualCaseERC721, token_id: u256) -> ContractAddress { + let mut args = ArrayTrait::new(); + args.append(token_id.low.into()); + args.append(token_id.high.into()); + + (*try_selector_with_fallback( + *self.contract_address, selectors::owner_of, selectors::ownerOf, args.span() + ) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } + + fn get_approved(self: @DualCaseERC721, token_id: u256) -> ContractAddress { + let mut args = ArrayTrait::new(); + args.append(token_id.low.into()); + args.append(token_id.high.into()); + + (*try_selector_with_fallback( + *self.contract_address, selectors::get_approved, selectors::getApproved, args.span() + ) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } + + fn is_approved_for_all( + self: @DualCaseERC721, owner: ContractAddress, operator: ContractAddress + ) -> bool { + let mut args = ArrayTrait::new(); + args.append(owner.into()); + args.append(operator.into()); + + (*try_selector_with_fallback( + *self.contract_address, + selectors::is_approved_for_all, + selectors::isApprovedForAll, + args.span() + ) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } + + fn approve(self: @DualCaseERC721, to: ContractAddress, token_id: u256) { + let mut args = ArrayTrait::new(); + args.append(to.into()); + args.append(token_id.low.into()); + args.append(token_id.high.into()); + call_contract_syscall(*self.contract_address, selectors::approve, args.span()) + .unwrap_syscall(); + } + + fn set_approval_for_all(self: @DualCaseERC721, operator: ContractAddress, approved: bool) { + let mut args = ArrayTrait::new(); + args.append(operator.into()); + args.append(approved.into()); + + try_selector_with_fallback( + *self.contract_address, + selectors::set_approval_for_all, + selectors::setApprovalForAll, + args.span() + ) + .unwrap_syscall(); + } + + fn transfer_from( + self: @DualCaseERC721, from: ContractAddress, to: ContractAddress, token_id: u256 + ) { + let mut args = ArrayTrait::new(); + args.append(from.into()); + args.append(to.into()); + args.append(token_id.low.into()); + args.append(token_id.high.into()); + + try_selector_with_fallback( + *self.contract_address, selectors::transfer_from, selectors::transferFrom, args.span() + ) + .unwrap_syscall(); + } + + fn safe_transfer_from( + self: @DualCaseERC721, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + mut data: Span + ) { + let mut args = ArrayTrait::new(); + args.append(from.into()); + args.append(to.into()); + args.append(token_id.low.into()); + args.append(token_id.high.into()); + args.append(data.len().into()); + + loop { + match data.pop_front() { + Option::Some(x) => args.append(*x), + Option::None(_) => { + break (); + } + }; + }; + + try_selector_with_fallback( + *self.contract_address, + selectors::safe_transfer_from, + selectors::safeTransferFrom, + args.span() + ) + .unwrap_syscall(); + } +} diff --git a/src/openzeppelin/utils.cairo b/src/openzeppelin/utils.cairo index 8dab269b1..433693466 100644 --- a/src/openzeppelin/utils.cairo +++ b/src/openzeppelin/utils.cairo @@ -1,10 +1,51 @@ +use starknet::call_contract_syscall; +use starknet::ContractAddress; +use starknet::SyscallResult; +use option::OptionTrait; use array::ArrayTrait; use array::SpanTrait; use box::BoxTrait; -use option::OptionTrait; mod constants; +mod selectors; mod serde; +fn try_selector_with_fallback( + target: ContractAddress, snake_selector: felt252, camel_selector: felt252, args: Span +) -> SyscallResult> { + match call_contract_syscall(target, snake_selector, args) { + Result::Ok(ret) => Result::Ok(ret), + Result::Err(errors) => { + if *errors.at(0) == 'ENTRYPOINT_NOT_FOUND' { + return call_contract_syscall(target, camel_selector, args); + } else { + Result::Err(errors) + } + } + } +} + +impl BoolIntoFelt252 of Into { + fn into(self: bool) -> felt252 { + if self { + return 1; + } else { + return 0; + } + } +} + +impl Felt252TryIntoBool of TryInto { + fn try_into(self: felt252) -> Option { + if self == 0 { + Option::Some(false) + } else if self == 1 { + Option::Some(true) + } else { + Option::None(()) + } + } +} + #[inline(always)] fn check_gas() { match gas::withdraw_gas() { diff --git a/src/openzeppelin/utils/selectors.cairo b/src/openzeppelin/utils/selectors.cairo new file mode 100644 index 000000000..839bd0c12 --- /dev/null +++ b/src/openzeppelin/utils/selectors.cairo @@ -0,0 +1,27 @@ +// +// ERC721 Selectors +// + +const name: felt252 = 0x361458367e696363fbcc70777d07ebbd2394e89fd0adcaf147faccd1d294d60; +const symbol: felt252 = 0x216b05c387bab9ac31918a3e61672f4618601f3c598a2f3f2710f37053e1ea4; +const token_uri: felt252 = 0x226ad7e84c1fe08eb4c525ed93cccadf9517670341304571e66f7c4f95cbe54; +const tokenUri: felt252 = 0x362dec5b8b67ab667ad08e83a2c3ba1db7fdb4ab8dc3a33c057c4fddec8d3de; +const balance_of: felt252 = 0x35a73cd311a05d46deda634c5ee045db92f811b4e74bca4437fcb5302b7af33; +const balanceOf: felt252 = 0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e; +const owner_of: felt252 = 0x3552df12bdc6089cf963c40c4cf56fbfd4bd14680c244d1c5494c2790f1ea5c; +const ownerOf: felt252 = 0x2962ba17806af798afa6eaf4aa8c93a9fb60a3e305045b6eea33435086cae9; +const get_approved: felt252 = 0x309065f1424d76d4a4ace2ff671391d59536e0297409434908d38673290a749; +const getApproved: felt252 = 0xb180e2fe9f14914416216da76338ac0beb980443725c802af615f8431fdb1e; +const is_approved_for_all: felt252 = + 0x2aa3ea196f9b8a4f65613b67fcf185e69d8faa9601a3382871d15b3060e30dd; +const isApprovedForAll: felt252 = 0x21cdf9aedfed41bc4485ae779fda471feca12075d9127a0fc70ac6b3b3d9c30; +const approve: felt252 = 0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c; +const set_approval_for_all: felt252 = + 0xd86ca3d41635e20c180181046b11abcf19e1bdef3dcaa4c180300ccca1813f; +const setApprovalForAll: felt252 = + 0x2d4c8ea4c8fb9f571d1f6f9b7692fff8e5ceaf73b1df98e7da8c1109b39ae9a; +const transfer_from: felt252 = 0x3704ffe8fba161be0e994951751a5033b1462b918ff785c0a636be718dfdb68; +const transferFrom: felt252 = 0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20; +const safe_transfer_from: felt252 = + 0x16f0218b33b5cf273196787d7cf139a9ad13d58e6674dcdce722b3bf8389863; +const safeTransferFrom: felt252 = 0x19d59d013d4aa1a8b1ce4c8299086f070733b453c02d0dc46e735edc04d6444; From ba69328ba0e22ca77dc678b7a97886880727de54 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 3 Jul 2023 00:32:56 +0200 Subject: [PATCH 053/124] Replace ERC-165 with SRC-5 (Update Interface Ids) (#637) * feat: add src5 module * refactor: interface ids and account standard interface * refactor: naming convention * refactor: separate interfaces * feat: apply last SNIP update * fix: account interface signature * feat: apply updates from review * fix: accesscontrol interface id * Update src/openzeppelin/account/account.cairo Co-authored-by: Andrew Fleming * feat: apply update from review --------- Co-authored-by: Andrew Fleming --- src/openzeppelin/access/accesscontrol.cairo | 11 ++-- src/openzeppelin/account/account.cairo | 28 ++++----- src/openzeppelin/account/interface.cairo | 4 +- src/openzeppelin/introspection.cairo | 2 +- src/openzeppelin/introspection/erc165.cairo | 42 -------------- src/openzeppelin/introspection/src5.cairo | 40 +++++++++++++ src/openzeppelin/tests.cairo | 2 +- .../tests/mocks/erc721_receiver.cairo | 16 +++--- src/openzeppelin/tests/test_account.cairo | 6 +- src/openzeppelin/tests/test_erc165.cairo | 57 ------------------- src/openzeppelin/tests/test_erc721.cairo | 8 +-- src/openzeppelin/tests/test_src5.cairo | 42 ++++++++++++++ src/openzeppelin/token/erc721/erc721.cairo | 28 ++++----- src/openzeppelin/token/erc721/interface.cairo | 22 ++++--- src/openzeppelin/utils/constants.cairo | 31 ++++------ 15 files changed, 155 insertions(+), 184 deletions(-) delete mode 100644 src/openzeppelin/introspection/erc165.cairo create mode 100644 src/openzeppelin/introspection/src5.cairo delete mode 100644 src/openzeppelin/tests/test_erc165.cairo create mode 100644 src/openzeppelin/tests/test_src5.cairo diff --git a/src/openzeppelin/access/accesscontrol.cairo b/src/openzeppelin/access/accesscontrol.cairo index d6bac6fc6..43b483585 100644 --- a/src/openzeppelin/access/accesscontrol.cairo +++ b/src/openzeppelin/access/accesscontrol.cairo @@ -1,7 +1,8 @@ use starknet::ContractAddress; const DEFAULT_ADMIN_ROLE: felt252 = 0; -const IACCESSCONTROL_ID: u32 = 0x7965db0b_u32; +const IACCESSCONTROL_ID: felt252 = + 0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751; #[abi] trait IAccessControl { @@ -17,7 +18,7 @@ mod AccessControl { use super::IAccessControl; use super::DEFAULT_ADMIN_ROLE; use super::IACCESSCONTROL_ID; - use openzeppelin::introspection::erc165::ERC165; + use openzeppelin::introspection::src5::SRC5; use starknet::ContractAddress; use starknet::get_caller_address; @@ -77,8 +78,8 @@ mod AccessControl { } #[view] - fn supports_interface(interface_id: u32) -> bool { - ERC165::supports_interface(interface_id) + fn supports_interface(interface_id: felt252) -> bool { + SRC5::supports_interface(interface_id) } #[view] @@ -108,7 +109,7 @@ mod AccessControl { #[internal] fn initializer() { - ERC165::register_interface(IACCESSCONTROL_ID); + SRC5::register_interface(IACCESSCONTROL_ID); } #[internal] diff --git a/src/openzeppelin/account/account.cairo b/src/openzeppelin/account/account.cairo index 267aa9534..4061052b0 100644 --- a/src/openzeppelin/account/account.cairo +++ b/src/openzeppelin/account/account.cairo @@ -31,7 +31,7 @@ trait AccountABI { #[view] fn is_valid_signature(message: felt252, signature: Array) -> u32; #[view] - fn supports_interface(interface_id: u32) -> bool; + fn supports_interface(interface_id: felt252) -> bool; } #[account_contract] @@ -40,17 +40,17 @@ mod Account { use array::ArrayTrait; use box::BoxTrait; use ecdsa::check_ecdsa_signature; + use option::OptionTrait; use serde::ArraySerde; use starknet::get_tx_info; use starknet::get_caller_address; use starknet::get_contract_address; - use option::OptionTrait; use zeroable::Zeroable; - use openzeppelin::account::interface::ERC1271_VALIDATED; use openzeppelin::account::interface::IAccount; use openzeppelin::account::interface::IACCOUNT_ID; - use openzeppelin::introspection::erc165::ERC165; + use openzeppelin::account::interface::ERC1271_VALIDATED; + use openzeppelin::introspection::src5::SRC5; use super::Call; use super::QUERY_VERSION; @@ -61,6 +61,11 @@ mod Account { public_key: felt252 } + #[constructor] + fn constructor(_public_key: felt252) { + initializer(_public_key); + } + impl AccountImpl of IAccount { fn __execute__(mut calls: Array) -> Array> { // Avoid calls from other contracts @@ -90,20 +95,15 @@ mod Account { if _is_valid_signature(message, signature.span()) { ERC1271_VALIDATED } else { - 0_u32 + 0 } } - fn supports_interface(interface_id: u32) -> bool { - ERC165::supports_interface(interface_id) + fn supports_interface(interface_id: felt252) -> bool { + SRC5::supports_interface(interface_id) } } - #[constructor] - fn constructor(_public_key: felt252) { - initializer(_public_key); - } - // // Externals // @@ -151,7 +151,7 @@ mod Account { } #[view] - fn supports_interface(interface_id: u32) -> bool { + fn supports_interface(interface_id: felt252) -> bool { AccountImpl::supports_interface(interface_id) } @@ -161,7 +161,7 @@ mod Account { #[internal] fn initializer(_public_key: felt252) { - ERC165::register_interface(IACCOUNT_ID); + SRC5::register_interface(IACCOUNT_ID); public_key::write(_public_key); } diff --git a/src/openzeppelin/account/interface.cairo b/src/openzeppelin/account/interface.cairo index 5c77f797b..6f30f12d7 100644 --- a/src/openzeppelin/account/interface.cairo +++ b/src/openzeppelin/account/interface.cairo @@ -2,7 +2,7 @@ use array::ArrayTrait; use array::SpanTrait; use starknet::ContractAddress; -const IACCOUNT_ID: u32 = 0xa66bd575_u32; +const IACCOUNT_ID: felt252 = 0x36c738c1c375b993078fe6b517d477e5a3c9b104e40c04662c4bdd3e2f5fa4a; const ERC1271_VALIDATED: u32 = 0x1626ba7e_u32; #[derive(Serde, Drop)] @@ -17,5 +17,5 @@ trait IAccount { fn __validate__(calls: Array) -> felt252; fn __validate_declare__(class_hash: felt252) -> felt252; fn is_valid_signature(message: felt252, signature: Array) -> u32; - fn supports_interface(interface_id: u32) -> bool; + fn supports_interface(interface_id: felt252) -> bool; } diff --git a/src/openzeppelin/introspection.cairo b/src/openzeppelin/introspection.cairo index 4391460f4..2d1a93a9f 100644 --- a/src/openzeppelin/introspection.cairo +++ b/src/openzeppelin/introspection.cairo @@ -1 +1 @@ -mod erc165; +mod src5; diff --git a/src/openzeppelin/introspection/erc165.cairo b/src/openzeppelin/introspection/erc165.cairo deleted file mode 100644 index 4a3b01778..000000000 --- a/src/openzeppelin/introspection/erc165.cairo +++ /dev/null @@ -1,42 +0,0 @@ -const IERC165_ID: u32 = 0x01ffc9a7_u32; -const INVALID_ID: u32 = 0xffffffff_u32; - -#[abi] -trait IERC165 { - fn supports_interface(interface_id: u32) -> bool; -} - -#[contract] -mod ERC165 { - use openzeppelin::introspection::erc165; - - struct Storage { - supported_interfaces: LegacyMap - } - - impl ERC165 of erc165::IERC165 { - fn supports_interface(interface_id: u32) -> bool { - if interface_id == erc165::IERC165_ID { - return true; - } - supported_interfaces::read(interface_id) - } - } - - #[view] - fn supports_interface(interface_id: u32) -> bool { - ERC165::supports_interface(interface_id) - } - - #[internal] - fn register_interface(interface_id: u32) { - assert(interface_id != erc165::INVALID_ID, 'Invalid id'); - supported_interfaces::write(interface_id, true); - } - - #[internal] - fn deregister_interface(interface_id: u32) { - assert(interface_id != erc165::IERC165_ID, 'Invalid id'); - supported_interfaces::write(interface_id, false); - } -} diff --git a/src/openzeppelin/introspection/src5.cairo b/src/openzeppelin/introspection/src5.cairo new file mode 100644 index 000000000..424a6faf1 --- /dev/null +++ b/src/openzeppelin/introspection/src5.cairo @@ -0,0 +1,40 @@ +const ISRC5_ID: felt252 = 0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055; + +#[abi] +trait ISRC5 { + fn supports_interface(interface_id: felt252) -> bool; +} + +#[contract] +mod SRC5 { + use openzeppelin::introspection::src5; + + struct Storage { + supported_interfaces: LegacyMap + } + + impl SRC5Impl of src5::ISRC5 { + fn supports_interface(interface_id: felt252) -> bool { + if interface_id == src5::ISRC5_ID { + return true; + } + supported_interfaces::read(interface_id) + } + } + + #[view] + fn supports_interface(interface_id: felt252) -> bool { + SRC5Impl::supports_interface(interface_id) + } + + #[internal] + fn register_interface(interface_id: felt252) { + supported_interfaces::write(interface_id, true); + } + + #[internal] + fn deregister_interface(interface_id: felt252) { + assert(interface_id != src5::ISRC5_ID, 'SRC5: invalid id'); + supported_interfaces::write(interface_id, false); + } +} diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index fd9d9d0c0..4ecdf57dc 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,7 +1,7 @@ mod test_accesscontrol; mod test_reentrancyguard; mod test_ownable; -mod test_erc165; +mod test_src5; mod test_account; mod test_erc20; mod test_erc721; diff --git a/src/openzeppelin/tests/mocks/erc721_receiver.cairo b/src/openzeppelin/tests/mocks/erc721_receiver.cairo index c9e848630..4bb3556bf 100644 --- a/src/openzeppelin/tests/mocks/erc721_receiver.cairo +++ b/src/openzeppelin/tests/mocks/erc721_receiver.cairo @@ -6,7 +6,7 @@ mod ERC721Receiver { use openzeppelin::token::erc721::interface::IERC721Receiver; use openzeppelin::token::erc721::interface::IERC721ReceiverCamel; use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; - use openzeppelin::introspection::erc165::ERC165; + use openzeppelin::introspection::src5::SRC5; use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; @@ -15,7 +15,7 @@ mod ERC721Receiver { impl ERC721ReceiverImpl of IERC721Receiver { fn on_erc721_received( operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span - ) -> u32 { + ) -> felt252 { if *data.at(0) == super::SUCCESS { IERC721_RECEIVER_ID } else { @@ -27,32 +27,32 @@ mod ERC721Receiver { impl ERC721ReceiverCamelImpl of IERC721ReceiverCamel { fn onERC721Received( operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span - ) -> u32 { + ) -> felt252 { ERC721ReceiverImpl::on_erc721_received(operator, from, tokenId, data) } } #[constructor] fn constructor() { - ERC165::register_interface(IERC721_RECEIVER_ID); + SRC5::register_interface(IERC721_RECEIVER_ID); } #[view] - fn supports_interface(interface_id: u32) -> bool { - ERC165::supports_interface(interface_id) + fn supports_interface(interface_id: felt252) -> bool { + SRC5::supports_interface(interface_id) } #[external] fn on_erc721_received( operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span - ) -> u32 { + ) -> felt252 { ERC721ReceiverImpl::on_erc721_received(operator, from, token_id, data) } #[external] fn onERC721Received( operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span - ) -> u32 { + ) -> felt252 { ERC721ReceiverCamelImpl::onERC721Received(operator, from, tokenId, data) } } diff --git a/src/openzeppelin/tests/test_account.cairo b/src/openzeppelin/tests/test_account.cairo index 210e91f50..5a833327f 100644 --- a/src/openzeppelin/tests/test_account.cairo +++ b/src/openzeppelin/tests/test_account.cairo @@ -14,7 +14,7 @@ use openzeppelin::account::interface::ERC1271_VALIDATED; use openzeppelin::account::interface::IACCOUNT_ID; use openzeppelin::account::QUERY_VERSION; use openzeppelin::account::TRANSACTION_VERSION; -use openzeppelin::introspection::erc165::IERC165_ID; +use openzeppelin::introspection::src5::ISRC5_ID; use openzeppelin::tests::utils; use openzeppelin::token::erc20::ERC20; use openzeppelin::token::erc20::IERC20Dispatcher; @@ -103,7 +103,7 @@ fn test_constructor() { fn test_interfaces() { Account::constructor(PUBLIC_KEY); - let supports_default_interface = Account::supports_interface(IERC165_ID); + let supports_default_interface = Account::supports_interface(ISRC5_ID); assert(supports_default_interface, 'Should support base interface'); let supports_account_interface = Account::supports_interface(IACCOUNT_ID); @@ -130,7 +130,7 @@ fn test_is_valid_signature() { assert(is_valid == ERC1271_VALIDATED, 'Should accept valid signature'); let is_valid = Account::is_valid_signature(message, bad_signature); - assert(is_valid == 0_u32, 'Should reject invalid signature'); + assert(is_valid == 0, 'Should reject invalid signature'); } #[test] diff --git a/src/openzeppelin/tests/test_erc165.cairo b/src/openzeppelin/tests/test_erc165.cairo deleted file mode 100644 index c66c1b034..000000000 --- a/src/openzeppelin/tests/test_erc165.cairo +++ /dev/null @@ -1,57 +0,0 @@ -use openzeppelin::introspection::erc165::ERC165; -use openzeppelin::introspection::erc165::IERC165_ID; -use openzeppelin::introspection::erc165::INVALID_ID; - -const OTHER_ID: u32 = 0x12345678_u32; - -#[test] -#[available_gas(2000000)] -fn test_default_behavior() { - let supports_default_interface: bool = ERC165::supports_interface(IERC165_ID); - assert(supports_default_interface, 'Should support base interface'); -} - -#[test] -#[available_gas(2000000)] -fn test_not_registered_interface() { - let supports_unregistered_interface: bool = ERC165::supports_interface(OTHER_ID); - assert(!supports_unregistered_interface, 'Should not support unregistered'); -} - -#[test] -#[available_gas(2000000)] -fn test_supports_invalid_interface() { - let supports_invalid_interface: bool = ERC165::supports_interface(INVALID_ID); - assert(!supports_invalid_interface, 'Should not support invalid id'); -} - -#[test] -#[available_gas(2000000)] -fn test_register_interface() { - ERC165::register_interface(OTHER_ID); - let supports_new_interface: bool = ERC165::supports_interface(OTHER_ID); - assert(supports_new_interface, 'Should support new interface'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Invalid id', ))] -fn test_register_invalid_interface() { - ERC165::register_interface(INVALID_ID); -} - -#[test] -#[available_gas(2000000)] -fn test_deregister_interface() { - ERC165::register_interface(OTHER_ID); - ERC165::deregister_interface(OTHER_ID); - let supports_old_interface: bool = ERC165::supports_interface(OTHER_ID); - assert(!supports_old_interface, 'Should not support interface'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Invalid id', ))] -fn test_deregister_default_interface() { - ERC165::deregister_interface(IERC165_ID); -} diff --git a/src/openzeppelin/tests/test_erc721.cairo b/src/openzeppelin/tests/test_erc721.cairo index 3b81360ae..d37a495a8 100644 --- a/src/openzeppelin/tests/test_erc721.cairo +++ b/src/openzeppelin/tests/test_erc721.cairo @@ -1,4 +1,4 @@ -use openzeppelin::introspection::erc165; +use openzeppelin::introspection::src5; use openzeppelin::token::erc721; use openzeppelin::token::erc721::ERC721; use openzeppelin::account::Account; @@ -92,8 +92,7 @@ fn test_constructor() { assert( ERC721::supports_interface(erc721::interface::IERC721_METADATA_ID), 'missing interface ID' ); - assert(ERC721::supports_interface(erc165::IERC165_ID), 'missing interface ID'); - assert(!ERC721::supports_interface(erc165::INVALID_ID), 'invalid interface ID'); + assert(ERC721::supports_interface(src5::ISRC5_ID), 'missing interface ID'); } #[test] @@ -109,8 +108,7 @@ fn test_initialize() { assert( ERC721::supports_interface(erc721::interface::IERC721_METADATA_ID), 'missing interface ID' ); - assert(ERC721::supports_interface(erc165::IERC165_ID), 'missing interface ID'); - assert(!ERC721::supports_interface(erc165::INVALID_ID), 'invalid interface ID'); + assert(ERC721::supports_interface(src5::ISRC5_ID), 'missing interface ID'); } /// diff --git a/src/openzeppelin/tests/test_src5.cairo b/src/openzeppelin/tests/test_src5.cairo new file mode 100644 index 000000000..9b43bf894 --- /dev/null +++ b/src/openzeppelin/tests/test_src5.cairo @@ -0,0 +1,42 @@ +use openzeppelin::introspection::src5::SRC5; +use openzeppelin::introspection::src5::ISRC5_ID; + +const OTHER_ID: felt252 = 0x12345678; + +#[test] +#[available_gas(2000000)] +fn test_default_behavior() { + let supports_default_interface: bool = SRC5::supports_interface(ISRC5_ID); + assert(supports_default_interface, 'Should support base interface'); +} + +#[test] +#[available_gas(2000000)] +fn test_not_registered_interface() { + let supports_unregistered_interface: bool = SRC5::supports_interface(OTHER_ID); + assert(!supports_unregistered_interface, 'Should not support unregistered'); +} + +#[test] +#[available_gas(2000000)] +fn test_register_interface() { + SRC5::register_interface(OTHER_ID); + let supports_new_interface: bool = SRC5::supports_interface(OTHER_ID); + assert(supports_new_interface, 'Should support new interface'); +} + +#[test] +#[available_gas(2000000)] +fn test_deregister_interface() { + SRC5::register_interface(OTHER_ID); + SRC5::deregister_interface(OTHER_ID); + let supports_old_interface: bool = SRC5::supports_interface(OTHER_ID); + assert(!supports_old_interface, 'Should not support interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('SRC5: invalid id', ))] +fn test_deregister_default_interface() { + SRC5::deregister_interface(ISRC5_ID); +} diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/openzeppelin/token/erc721/erc721.cairo index e22466078..7c1345447 100644 --- a/src/openzeppelin/token/erc721/erc721.cairo +++ b/src/openzeppelin/token/erc721/erc721.cairo @@ -53,14 +53,14 @@ trait ERC721ABI { mod ERC721 { // OZ modules use openzeppelin::account; - use openzeppelin::introspection::erc165; + use openzeppelin::introspection::src5; use openzeppelin::token::erc721; // Dispatchers - use openzeppelin::introspection::erc165::IERC165Dispatcher; - use openzeppelin::introspection::erc165::IERC165DispatcherTrait; - use super::super::interface::IERC721ReceiverABIDispatcher; - use super::super::interface::IERC721ReceiverABIDispatcherTrait; + use openzeppelin::introspection::src5::ISRC5Dispatcher; + use openzeppelin::introspection::src5::ISRC5DispatcherTrait; + use super::super::interface::ERC721ReceiverABIDispatcher; + use super::super::interface::ERC721ReceiverABIDispatcherTrait; // Other use starknet::ContractAddress; @@ -209,13 +209,13 @@ mod ERC721 { // View #[view] - fn supports_interface(interface_id: u32) -> bool { - erc165::ERC165::supports_interface(interface_id) + fn supports_interface(interface_id: felt252) -> bool { + src5::SRC5::supports_interface(interface_id) } #[view] - fn supportsInterface(interfaceId: u32) -> bool { - erc165::ERC165::supports_interface(interfaceId) + fn supportsInterface(interfaceId: felt252) -> bool { + src5::SRC5::supports_interface(interfaceId) } #[view] @@ -325,8 +325,8 @@ mod ERC721 { fn initializer(name_: felt252, symbol_: felt252) { _name::write(name_); _symbol::write(symbol_); - erc165::ERC165::register_interface(erc721::interface::IERC721_ID); - erc165::ERC165::register_interface(erc721::interface::IERC721_METADATA_ID); + src5::SRC5::register_interface(erc721::interface::IERC721_ID); + src5::SRC5::register_interface(erc721::interface::IERC721_METADATA_ID); } #[internal] @@ -443,18 +443,18 @@ mod ERC721 { fn _check_on_erc721_received( from: ContractAddress, to: ContractAddress, token_id: u256, data: Span ) -> bool { - if (IERC165Dispatcher { + if (ISRC5Dispatcher { contract_address: to }.supports_interface(erc721::interface::IERC721_RECEIVER_ID)) { // todo add casing fallback mechanism - IERC721ReceiverABIDispatcher { + ERC721ReceiverABIDispatcher { contract_address: to } .on_erc721_received( get_caller_address(), from, token_id, data ) == erc721::interface::IERC721_RECEIVER_ID } else { - IERC165Dispatcher { + ISRC5Dispatcher { contract_address: to }.supports_interface(account::interface::IACCOUNT_ID) } diff --git a/src/openzeppelin/token/erc721/interface.cairo b/src/openzeppelin/token/erc721/interface.cairo index a8b21f60e..78283dbde 100644 --- a/src/openzeppelin/token/erc721/interface.cairo +++ b/src/openzeppelin/token/erc721/interface.cairo @@ -2,11 +2,12 @@ use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; use array::SpanTrait; -const IERC721_ID: u32 = 0x80ac58cd_u32; -const IERC721_METADATA_ID: u32 = 0x5b5e139f_u32; -const IERC721_RECEIVER_ID: u32 = 0x150b7a02_u32; +const IERC721_ID: felt252 = 0x33eb2f84c309543403fd69f0d0f363781ef06ef6faeb0131ff16ea3175bd943; +const IERC721_METADATA_ID: felt252 = + 0x6069a70848f907fa57668ba1875164eb4dcee693952468581406d131081bbd; +const IERC721_RECEIVER_ID: felt252 = + 0x3a0dff5f70d80458ad14ae37bb182a728e3c8cdda0402a5daa86620bdf910bc; -#[abi] trait IERC721 { fn balance_of(account: ContractAddress) -> u256; fn owner_of(token_id: u256) -> ContractAddress; @@ -24,7 +25,6 @@ trait IERC721 { fn token_uri(token_id: u256) -> felt252; } -#[abi] trait IERC721Camel { fn balanceOf(account: ContractAddress) -> u256; fn ownerOf(tokenId: u256) -> ContractAddress; @@ -47,25 +47,23 @@ trait IERC721Camel { // #[abi] -trait IERC721ReceiverABI { +trait ERC721ReceiverABI { fn on_erc721_received( operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span - ) -> u32; + ) -> felt252; fn onERC721Received( operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span - ) -> u32; + ) -> felt252; } -#[abi] trait IERC721Receiver { fn on_erc721_received( operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span - ) -> u32; + ) -> felt252; } -#[abi] trait IERC721ReceiverCamel { fn onERC721Received( operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span - ) -> u32; + ) -> felt252; } diff --git a/src/openzeppelin/utils/constants.cairo b/src/openzeppelin/utils/constants.cairo index d7346bf55..7ab63d0da 100644 --- a/src/openzeppelin/utils/constants.cairo +++ b/src/openzeppelin/utils/constants.cairo @@ -2,34 +2,25 @@ // Interface ids // -// ERC165 -// See: https://eips.ethereum.org/EIPS/eip-165 -const IERC165_ID: u32 = 0x01ffc9a7_u32; -const INVALID_ID: u32 = 0xffffffff_u32; +// SRC5 +// See: https://github.com/starknet-io/SNIPs/pull/24 +const ISRC5_ID: felt252 = 0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055; // Account -// See: https://github.com/OpenZeppelin/cairo-contracts/pull/449#discussion_r966242914 -const IACCOUNT_ID: u32 = 0xa66bd575_u32; +const IACCOUNT_ID: felt252 = 0x36c738c1c375b993078fe6b517d477e5a3c9b104e40c04662c4bdd3e2f5fa4a; // ERC721 // See: https://eips.ethereum.org/EIPS/eip-721 -const IERC721_ID: u32 = 0x80ac58cd_u32; -const IERC721_RECEIVER_ID: u32 = 0x150b7a02_u32; -const IERC721_METADATA_ID: u32 = 0x5b5e139f_u32; -const IERC721_ENUMERABLE_ID: u32 = 0x780e9d63_u32; - -// ERC1155 -// See: https://eips.ethereum.org/EIPS/eip-1155 -const IERC1155_ID: u32 = 0xd9b67a26_u32; -const IERC1155_METADATA_ID: u32 = 0x0e89341c_u32; -const IERC1155_RECEIVER_ID: u32 = 0x4e2312e0_u32; -const ON_ERC1155_RECEIVED_SELECTOR: u32 = 0xf23a6e61_u32; -const ON_ERC1155_BATCH_RECEIVED_SELECTOR: u32 = 0xbc197c81_u32; +const IERC721_ID: felt252 = 0x33eb2f84c309543403fd69f0d0f363781ef06ef6faeb0131ff16ea3175bd943; +const IERC721_METADATA_ID: felt252 = + 0x6069a70848f907fa57668ba1875164eb4dcee693952468581406d131081bbd; +const IERC721_RECEIVER_ID: felt252 = + 0x3a0dff5f70d80458ad14ae37bb182a728e3c8cdda0402a5daa86620bdf910bc; // AccessControl -// Calculated from XOR of all function selectors in IAccessControl. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/IAccessControl.sol -const IACCESSCONTROL_ID: u32 = 0x7965db0b_u32; +const IACCESSCONTROL_ID: felt252 = + 0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751; // // Roles From 8534ec6904d488507b8c062ee76cdeb82fde3203 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Mon, 3 Jul 2023 10:21:47 -0400 Subject: [PATCH 054/124] Fix conflicts from the dual721 and src5 merge (#641) * add abi to interfaces * change u32 to felt --- src/openzeppelin/tests/mocks/camel721_mock.cairo | 2 +- src/openzeppelin/tests/mocks/snake721_mock.cairo | 2 +- src/openzeppelin/token/erc721/interface.cairo | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openzeppelin/tests/mocks/camel721_mock.cairo b/src/openzeppelin/tests/mocks/camel721_mock.cairo index 2b2715ec9..ef0d95ed2 100644 --- a/src/openzeppelin/tests/mocks/camel721_mock.cairo +++ b/src/openzeppelin/tests/mocks/camel721_mock.cairo @@ -15,7 +15,7 @@ mod CamelERC721Mock { // View #[view] - fn supportsInterface(interfaceId: u32) -> bool { + fn supportsInterface(interfaceId: felt252) -> bool { ERC721::supports_interface(interfaceId) } diff --git a/src/openzeppelin/tests/mocks/snake721_mock.cairo b/src/openzeppelin/tests/mocks/snake721_mock.cairo index 44f4e91d9..eca3d70cb 100644 --- a/src/openzeppelin/tests/mocks/snake721_mock.cairo +++ b/src/openzeppelin/tests/mocks/snake721_mock.cairo @@ -15,7 +15,7 @@ mod SnakeERC721Mock { // View #[view] - fn supports_interface(interface_id: u32) -> bool { + fn supports_interface(interface_id: felt252) -> bool { ERC721::supports_interface(interface_id) } diff --git a/src/openzeppelin/token/erc721/interface.cairo b/src/openzeppelin/token/erc721/interface.cairo index 78283dbde..53292dd94 100644 --- a/src/openzeppelin/token/erc721/interface.cairo +++ b/src/openzeppelin/token/erc721/interface.cairo @@ -8,6 +8,7 @@ const IERC721_METADATA_ID: felt252 = const IERC721_RECEIVER_ID: felt252 = 0x3a0dff5f70d80458ad14ae37bb182a728e3c8cdda0402a5daa86620bdf910bc; +#[abi] trait IERC721 { fn balance_of(account: ContractAddress) -> u256; fn owner_of(token_id: u256) -> ContractAddress; @@ -25,6 +26,7 @@ trait IERC721 { fn token_uri(token_id: u256) -> felt252; } +#[abi] trait IERC721Camel { fn balanceOf(account: ContractAddress) -> u256; fn ownerOf(tokenId: u256) -> ContractAddress; From bc90bd5bcf5894963249bb099aff8c35a9eb5955 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Mon, 3 Jul 2023 12:32:43 -0400 Subject: [PATCH 055/124] Add camel support for ownable (#625) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add camel support * add camel tests * nest ownable into dir * move interface * add dual ownable * add const selectors * add try_selector_with_fallback and bool impl * nest access tests in test dirs * move accesscontrol and ownable test mods * move tests * move tests * add mocks * add dual ownable tests * add panic traits * tidy up tests * fix formatting * remove comments * fix hierarchy * remove import comments * remove comment * Apply suggestions from code review Co-authored-by: Martín Triay * remove unused import * fix camel dispatcher * normalize assert error msg * fix formatting * remove redundant assertion * change selector casing * remove unused import * fix comments, add ref for ignored tests * fix comments * remove panic trait * bump to cairo v1.1.1 * update Cargo * remove ignore from tests * Apply suggestions from code review Co-authored-by: Eric Nordelo * remove selectors from constants * add selectors to selectors.cairo * remove selector bindings * fix comment * remove/fix comments * fix conflicts * Update src/openzeppelin/utils/selectors.cairo Co-authored-by: Eric Nordelo --------- Co-authored-by: Martín Triay Co-authored-by: Eric Nordelo --- src/openzeppelin/access/ownable.cairo | 55 +---- .../access/ownable/dual_ownable.cairo | 60 ++++++ .../access/ownable/interface.cairo | 21 ++ src/openzeppelin/access/ownable/ownable.cairo | 93 ++++++++ src/openzeppelin/tests.cairo | 3 +- src/openzeppelin/tests/access.cairo | 3 + .../{ => access}/test_accesscontrol.cairo | 0 .../tests/access/test_dual_ownable.cairo | 198 ++++++++++++++++++ .../tests/{ => access}/test_ownable.cairo | 72 ++++++- src/openzeppelin/tests/mocks.cairo | 1 + .../tests/mocks/dual_ownable_mocks.cairo | 93 ++++++++ src/openzeppelin/utils/selectors.cairo | 14 +- 12 files changed, 558 insertions(+), 55 deletions(-) create mode 100644 src/openzeppelin/access/ownable/dual_ownable.cairo create mode 100644 src/openzeppelin/access/ownable/interface.cairo create mode 100644 src/openzeppelin/access/ownable/ownable.cairo create mode 100644 src/openzeppelin/tests/access.cairo rename src/openzeppelin/tests/{ => access}/test_accesscontrol.cairo (100%) create mode 100644 src/openzeppelin/tests/access/test_dual_ownable.cairo rename src/openzeppelin/tests/{ => access}/test_ownable.cairo (57%) create mode 100644 src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo diff --git a/src/openzeppelin/access/ownable.cairo b/src/openzeppelin/access/ownable.cairo index 69bf5b2b1..7b8e812b9 100644 --- a/src/openzeppelin/access/ownable.cairo +++ b/src/openzeppelin/access/ownable.cairo @@ -1,52 +1,5 @@ -#[contract] -mod Ownable { - use starknet::ContractAddress; - use starknet::get_caller_address; - use zeroable::Zeroable; +mod ownable; +use ownable::Ownable; - struct Storage { - _owner: ContractAddress - } - - #[event] - fn OwnershipTransferred(previous_owner: ContractAddress, new_owner: ContractAddress) {} - - #[internal] - fn initializer() { - let caller: ContractAddress = get_caller_address(); - _transfer_ownership(caller); - } - - #[internal] - fn assert_only_owner() { - let owner: ContractAddress = _owner::read(); - let caller: ContractAddress = get_caller_address(); - assert(!caller.is_zero(), 'Caller is the zero address'); - assert(caller == owner, 'Caller is not the owner'); - } - - #[internal] - fn owner() -> ContractAddress { - _owner::read() - } - - #[internal] - fn transfer_ownership(new_owner: ContractAddress) { - assert(!new_owner.is_zero(), 'New owner is the zero address'); - assert_only_owner(); - _transfer_ownership(new_owner); - } - - #[internal] - fn renounce_ownership() { - assert_only_owner(); - _transfer_ownership(Zeroable::zero()); - } - - #[internal] - fn _transfer_ownership(new_owner: ContractAddress) { - let previous_owner: ContractAddress = _owner::read(); - _owner::write(new_owner); - OwnershipTransferred(previous_owner, new_owner); - } -} +mod interface; +mod dual_ownable; diff --git a/src/openzeppelin/access/ownable/dual_ownable.cairo b/src/openzeppelin/access/ownable/dual_ownable.cairo new file mode 100644 index 000000000..840c371f5 --- /dev/null +++ b/src/openzeppelin/access/ownable/dual_ownable.cairo @@ -0,0 +1,60 @@ +use array::SpanTrait; +use array::ArrayTrait; +use core::result::ResultTrait; +use option::OptionTrait; +use starknet::ContractAddress; +use starknet::Felt252TryIntoContractAddress; +use starknet::SyscallResultTrait; +use starknet::call_contract_syscall; +use traits::Into; +use traits::TryInto; + +use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::Felt252TryIntoBool; +use openzeppelin::utils::selectors; + +#[derive(Copy, Drop)] +struct DualCaseOwnable { + contract_address: ContractAddress +} + +trait DualCaseOwnableTrait { + fn owner(self: @DualCaseOwnable) -> ContractAddress; + fn transfer_ownership(self: @DualCaseOwnable, new_owner: ContractAddress); + fn renounce_ownership(self: @DualCaseOwnable); +} + +impl DualCaseOwnableImpl of DualCaseOwnableTrait { + fn owner(self: @DualCaseOwnable) -> ContractAddress { + (*call_contract_syscall(*self.contract_address, selectors::owner, ArrayTrait::new().span()) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } + + fn transfer_ownership(self: @DualCaseOwnable, new_owner: ContractAddress) { + let mut args = ArrayTrait::new(); + args.append(new_owner.into()); + + try_selector_with_fallback( + *self.contract_address, + selectors::transfer_ownership, + selectors::transferOwnership, + args.span() + ) + .unwrap_syscall(); + } + + fn renounce_ownership(self: @DualCaseOwnable) { + let mut args = ArrayTrait::new(); + + try_selector_with_fallback( + *self.contract_address, + selectors::renounce_ownership, + selectors::renounceOwnership, + args.span() + ) + .unwrap_syscall(); + } +} diff --git a/src/openzeppelin/access/ownable/interface.cairo b/src/openzeppelin/access/ownable/interface.cairo new file mode 100644 index 000000000..41cd27a69 --- /dev/null +++ b/src/openzeppelin/access/ownable/interface.cairo @@ -0,0 +1,21 @@ +use starknet::ContractAddress; + +#[abi] +trait IOwnable { + #[view] + fn owner() -> ContractAddress; + #[external] + fn transfer_ownership(new_owner: ContractAddress); + #[external] + fn renounce_ownership(); +} + +#[abi] +trait IOwnableCamel { + #[view] + fn owner() -> ContractAddress; + #[external] + fn transferOwnership(newOwner: ContractAddress); + #[external] + fn renounceOwnership(); +} diff --git a/src/openzeppelin/access/ownable/ownable.cairo b/src/openzeppelin/access/ownable/ownable.cairo new file mode 100644 index 000000000..1027d4ca7 --- /dev/null +++ b/src/openzeppelin/access/ownable/ownable.cairo @@ -0,0 +1,93 @@ +#[contract] +mod Ownable { + use openzeppelin::access::ownable::interface; + use starknet::ContractAddress; + use starknet::get_caller_address; + use zeroable::Zeroable; + + struct Storage { + _owner: ContractAddress + } + + #[event] + fn OwnershipTransferred(previous_owner: ContractAddress, new_owner: ContractAddress) {} + + impl OwnableImpl of interface::IOwnable { + fn owner() -> ContractAddress { + _owner::read() + } + + fn transfer_ownership(new_owner: ContractAddress) { + assert(!new_owner.is_zero(), 'New owner is the zero address'); + assert_only_owner(); + _transfer_ownership(new_owner); + } + + fn renounce_ownership() { + assert_only_owner(); + _transfer_ownership(Zeroable::zero()); + } + } + + impl OwnableCamelImpl of interface::IOwnableCamel { + fn owner() -> ContractAddress { + OwnableImpl::owner() + } + + fn transferOwnership(newOwner: ContractAddress) { + OwnableImpl::transfer_ownership(newOwner); + } + + fn renounceOwnership() { + OwnableImpl::renounce_ownership(); + } + } + + #[view] + fn owner() -> ContractAddress { + OwnableImpl::owner() + } + + #[external] + fn transfer_ownership(new_owner: ContractAddress) { + OwnableImpl::transfer_ownership(new_owner); + } + + #[external] + fn transferOwnership(newOwner: ContractAddress) { + OwnableCamelImpl::transferOwnership(newOwner); + } + + #[external] + fn renounce_ownership() { + OwnableImpl::renounce_ownership(); + } + + #[external] + fn renounceOwnership() { + OwnableCamelImpl::renounceOwnership(); + } + + // Internals + + #[internal] + fn initializer() { + let caller: ContractAddress = get_caller_address(); + _transfer_ownership(caller); + } + + #[internal] + fn assert_only_owner() { + let owner: ContractAddress = _owner::read(); + let caller: ContractAddress = get_caller_address(); + assert(!caller.is_zero(), 'Caller is the zero address'); + assert(caller == owner, 'Caller is not the owner'); + } + + #[internal] + fn _transfer_ownership(new_owner: ContractAddress) { + let previous_owner: ContractAddress = _owner::read(); + _owner::write(new_owner); + OwnershipTransferred(previous_owner, new_owner); + } +} diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 4ecdf57dc..e50d9f319 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,6 +1,5 @@ -mod test_accesscontrol; +mod access; mod test_reentrancyguard; -mod test_ownable; mod test_src5; mod test_account; mod test_erc20; diff --git a/src/openzeppelin/tests/access.cairo b/src/openzeppelin/tests/access.cairo new file mode 100644 index 000000000..f5857e98d --- /dev/null +++ b/src/openzeppelin/tests/access.cairo @@ -0,0 +1,3 @@ +mod test_accesscontrol; +mod test_ownable; +mod test_dual_ownable; diff --git a/src/openzeppelin/tests/test_accesscontrol.cairo b/src/openzeppelin/tests/access/test_accesscontrol.cairo similarity index 100% rename from src/openzeppelin/tests/test_accesscontrol.cairo rename to src/openzeppelin/tests/access/test_accesscontrol.cairo diff --git a/src/openzeppelin/tests/access/test_dual_ownable.cairo b/src/openzeppelin/tests/access/test_dual_ownable.cairo new file mode 100644 index 000000000..dca5595f7 --- /dev/null +++ b/src/openzeppelin/tests/access/test_dual_ownable.cairo @@ -0,0 +1,198 @@ +use array::ArrayTrait; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_caller_address; +use starknet::testing::set_contract_address; +use zeroable::Zeroable; + +use openzeppelin::access::ownable::interface::IOwnableDispatcher; +use openzeppelin::access::ownable::interface::IOwnableCamelDispatcher; +use openzeppelin::access::ownable::interface::IOwnableDispatcherTrait; +use openzeppelin::access::ownable::interface::IOwnableCamelDispatcherTrait; +use openzeppelin::access::ownable::dual_ownable::DualCaseOwnableTrait; +use openzeppelin::access::ownable::dual_ownable::DualCaseOwnable; +use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnableMock; +use openzeppelin::tests::mocks::dual_ownable_mocks::CamelOwnableMock; +use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnablePanicMock; +use openzeppelin::tests::mocks::dual_ownable_mocks::CamelOwnablePanicMock; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils; + +/// +/// Constants +/// + +fn OWNER() -> ContractAddress { + contract_address_const::<10>() +} + +fn NEW_OWNER() -> ContractAddress { + contract_address_const::<20>() +} + +/// +/// Setup +/// + +fn setup_snake() -> (DualCaseOwnable, IOwnableDispatcher) { + let mut calldata = ArrayTrait::new(); + set_caller_address(OWNER()); + let target = utils::deploy(SnakeOwnableMock::TEST_CLASS_HASH, calldata); + (DualCaseOwnable { contract_address: target }, IOwnableDispatcher { contract_address: target }) +} + +fn setup_camel() -> (DualCaseOwnable, IOwnableCamelDispatcher) { + let mut calldata = ArrayTrait::new(); + set_caller_address(OWNER()); + let target = utils::deploy(CamelOwnableMock::TEST_CLASS_HASH, calldata); + ( + DualCaseOwnable { + contract_address: target + }, IOwnableCamelDispatcher { + contract_address: target + } + ) +} + +fn setup_non_ownable() -> DualCaseOwnable { + let calldata = ArrayTrait::new(); + set_caller_address(OWNER()); + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); + DualCaseOwnable { contract_address: target } +} + +fn setup_ownable_panic() -> (DualCaseOwnable, DualCaseOwnable) { + set_caller_address(OWNER()); + let snake_target = utils::deploy(SnakeOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + let camel_target = utils::deploy(CamelOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + ( + DualCaseOwnable { + contract_address: snake_target + }, DualCaseOwnable { + contract_address: camel_target + } + ) +} + +/// +/// Case agnostic methods +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_owner() { + let (snake_dispatcher, _) = setup_snake(); + let (camel_dispatcher, _) = setup_camel(); + assert(snake_dispatcher.owner() == OWNER(), 'Should return OWNER'); + assert(camel_dispatcher.owner() == OWNER(), 'Should return OWNER'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_owner() { + let dispatcher = setup_non_ownable(); + dispatcher.owner(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_owner_exists_and_panics() { + let (dispatcher, _) = setup_ownable_panic(); + dispatcher.owner(); +} + +/// +/// snake_case target +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_transfer_ownership() { + let (dispatcher, target) = setup_snake(); + set_contract_address(OWNER()); + dispatcher.transfer_ownership(NEW_OWNER()); + assert(target.owner() == NEW_OWNER(), 'Should be new owner'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_transfer_ownership() { + let dispatcher = setup_non_ownable(); + dispatcher.transfer_ownership(NEW_OWNER()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_transfer_ownership_exists_and_panics() { + let (dispatcher, _) = setup_ownable_panic(); + dispatcher.transfer_ownership(NEW_OWNER()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_renounce_ownership() { + let (dispatcher, target) = setup_snake(); + set_contract_address(OWNER()); + dispatcher.renounce_ownership(); + assert(target.owner().is_zero(), 'Should be zero'); +} + + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_renounce_ownership() { + let dispatcher = setup_non_ownable(); + dispatcher.renounce_ownership(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_renounce_ownership_exists_and_panics() { + let (dispatcher, _) = setup_ownable_panic(); + dispatcher.renounce_ownership(); +} + +/// +/// camelCase target +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_transferOwnership() { + let (dispatcher, target) = setup_camel(); + set_contract_address(OWNER()); + dispatcher.transfer_ownership(NEW_OWNER()); + assert(target.owner() == NEW_OWNER(), 'Should be new owner'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_transferOwnership_exists_and_panics() { + let (_, dispatcher) = setup_ownable_panic(); + dispatcher.transfer_ownership(NEW_OWNER()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_renounceOwnership() { + let (dispatcher, target) = setup_camel(); + set_contract_address(OWNER()); + dispatcher.renounce_ownership(); + assert(target.owner().is_zero(), 'Should be zero'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_renounceOwnership_exists_and_panics() { + let (_, dispatcher) = setup_ownable_panic(); + dispatcher.renounce_ownership(); +} + diff --git a/src/openzeppelin/tests/test_ownable.cairo b/src/openzeppelin/tests/access/test_ownable.cairo similarity index 57% rename from src/openzeppelin/tests/test_ownable.cairo rename to src/openzeppelin/tests/access/test_ownable.cairo index 424cc0546..99a717ff6 100644 --- a/src/openzeppelin/tests/test_ownable.cairo +++ b/src/openzeppelin/tests/access/test_ownable.cairo @@ -22,6 +22,10 @@ fn setup() { Ownable::initializer(); } +/// +/// initializer +/// + #[test] #[available_gas(2000000)] fn test_initializer() { @@ -30,6 +34,10 @@ fn test_initializer() { assert(Ownable::owner() == OWNER(), 'Owner should be set'); } +/// +/// transfer_ownership & transferOwnership +/// + #[test] #[available_gas(2000000)] fn test_transfer_ownership() { @@ -50,7 +58,6 @@ fn test_transfer_ownership_to_zero() { #[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address', ))] fn test_transfer_ownership_from_zero() { - assert(Ownable::owner() == ZERO(), 'Should be zero with no owner'); Ownable::transfer_ownership(OTHER()); } @@ -63,6 +70,42 @@ fn test_transfer_ownership_from_nonowner() { Ownable::transfer_ownership(OTHER()); } +#[test] +#[available_gas(2000000)] +fn test_transferOwnership() { + setup(); + Ownable::transferOwnership(OTHER()); + assert(Ownable::owner() == OTHER(), 'Should transfer ownership'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('New owner is the zero address', ))] +fn test_transferOwnership_to_zero() { + setup(); + Ownable::transferOwnership(ZERO()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is the zero address', ))] +fn test_transferOwnership_from_zero() { + Ownable::transferOwnership(OTHER()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is not the owner', ))] +fn test_transferOwnership_from_nonowner() { + setup(); + testing::set_caller_address(OTHER()); + Ownable::transferOwnership(OTHER()); +} + +/// +/// renounce_ownership & renounceOwnership +/// + #[test] #[available_gas(2000000)] fn test_renounce_ownership() { @@ -88,3 +131,30 @@ fn test_renounce_ownership_from_nonowner() { testing::set_caller_address(OTHER()); Ownable::renounce_ownership(); } + +#[test] +#[available_gas(2000000)] +fn test_renounceOwnership() { + setup(); + Ownable::renounceOwnership(); + assert(Ownable::owner() == ZERO(), 'Should renounce ownership'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is the zero address', ))] +fn test_renounceOwnership_from_zero_address() { + setup(); + testing::set_caller_address(ZERO()); + Ownable::renounceOwnership(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is not the owner', ))] +fn test_renounceOwnership_from_nonowner() { + setup(); + testing::set_caller_address(OTHER()); + Ownable::renounceOwnership(); +} + diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 4ab029428..0f36b9086 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -3,6 +3,7 @@ mod reentrancy_mock; mod erc721_receiver; mod erc721_panic_mock; mod mock_pausable; +mod dual_ownable_mocks; mod snake721_mock; mod camel721_mock; mod non_implementing_mock; diff --git a/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo b/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo new file mode 100644 index 000000000..f84bc195e --- /dev/null +++ b/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo @@ -0,0 +1,93 @@ +#[contract] +mod SnakeOwnableMock { + use starknet::ContractAddress; + use openzeppelin::access::ownable::Ownable; + + #[constructor] + fn constructor() { + Ownable::initializer(); + } + + #[view] + fn owner() -> ContractAddress { + Ownable::owner() + } + + #[external] + fn transfer_ownership(new_owner: ContractAddress) { + Ownable::transfer_ownership(new_owner); + } + + #[external] + fn renounce_ownership() { + Ownable::renounce_ownership(); + } +} + +#[contract] +mod CamelOwnableMock { + use starknet::ContractAddress; + use openzeppelin::access::ownable::Ownable; + + #[constructor] + fn constructor() { + Ownable::initializer(); + } + + #[view] + fn owner() -> ContractAddress { + Ownable::owner() + } + + #[external] + fn transferOwnership(newOwner: ContractAddress) { + Ownable::transferOwnership(newOwner); + } + + #[external] + fn renounceOwnership() { + Ownable::renounceOwnership(); + } +} + +#[contract] +mod SnakeOwnablePanicMock { + use starknet::ContractAddress; + + #[view] + fn owner() -> ContractAddress { + panic_with_felt252('Some error'); + Zeroable::zero() + } + + #[external] + fn transfer_ownership(new_owner: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external] + fn renounce_ownership() { + panic_with_felt252('Some error'); + } +} + +#[contract] +mod CamelOwnablePanicMock { + use starknet::ContractAddress; + + #[view] + fn owner() -> ContractAddress { + panic_with_felt252('Some error'); + Zeroable::zero() + } + + #[external] + fn transfer_ownership(new_owner: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external] + fn renounce_ownership() { + panic_with_felt252('Some error'); + } +} diff --git a/src/openzeppelin/utils/selectors.cairo b/src/openzeppelin/utils/selectors.cairo index 839bd0c12..8f56ff9d5 100644 --- a/src/openzeppelin/utils/selectors.cairo +++ b/src/openzeppelin/utils/selectors.cairo @@ -1,5 +1,17 @@ // -// ERC721 Selectors +// Ownable +// + +const owner: felt252 = 0x2016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0; +const transfer_ownership: felt252 = + 0x2a3bb1eaa05b77c4b0eeee0116a3177c6d62319dd7149ae148185d9e09de74a; +const transferOwnership: felt252 = + 0x14a390f291e2e1f29874769efdef47ddad94d76f77ff516fad206a385e8995f; +const renounce_ownership: felt252 = 0x52580a92c73f4428f1a260c5d768ef462b25955307de00f99957df119865d; +const renounceOwnership: felt252 = 0xd5d33d590e6660853069b37a2aea67c6fdaa0268626bc760350b590490feb5; + +// +// ERC721 // const name: felt252 = 0x361458367e696363fbcc70777d07ebbd2394e89fd0adcaf147faccd1d294d60; From c8fa9f945811e6c7a7b73382c589b7b154e37fa2 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Wed, 5 Jul 2023 15:53:58 -0400 Subject: [PATCH 056/124] Add camel support for access control (#626) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add camel support * add camel tests * move accesscontrol into dir * separate interface * add try_selector_with_fallback and bool impl * add const selectors * add dual accesscontrol * move access tests * add panic trait * add accesscontrol mocks * add dual accesscontrol tests * fix formatting * Apply suggestions from code review Co-authored-by: Eric Nordelo * add comment to supportsInterface * add tests for supports_interface * remove comments * alphabetize use clauses * remove util panic trait * remove unused imports * remove unused imports * remove unused import * update selector casings * Apply suggestions from code review Co-authored-by: Martín Triay * fix casing on target calls * add space to comments * remove comments, add ref with ignored tests * remove unused imports * remove selectors from constants * add selectors to selectors mod * fix formatting * reorder selectors * fix comment * update interface id * replace erc165 with src5 * fix conflicts * replace u32 with felt * add abi to interfaces * remove ignore from tests * fix formatting * fix comment * remove camel supportsInterface * fix comment consistency * Update src/openzeppelin/tests/access/test_dual_accesscontrol.cairo Co-authored-by: Eric Nordelo * add append_serde * change append to append_serde * remove unused import * remove bindings --------- Co-authored-by: Eric Nordelo Co-authored-by: Martín Triay --- src/openzeppelin/access/accesscontrol.cairo | 155 +-------- .../access/accesscontrol/accesscontrol.cairo | 194 ++++++++++++ .../accesscontrol/dual_accesscontrol.cairo | 86 +++++ .../access/accesscontrol/interface.cairo | 32 ++ src/openzeppelin/tests/access.cairo | 1 + .../tests/access/test_accesscontrol.cairo | 136 +++++++- .../access/test_dual_accesscontrol.cairo | 297 ++++++++++++++++++ src/openzeppelin/tests/mocks.cairo | 3 + .../mocks/accesscontrol_panic_mock.cairo | 69 ++++ .../mocks/camel_accesscontrol_mock.cairo | 39 +++ .../mocks/snake_accesscontrol_mock.cairo | 39 +++ src/openzeppelin/utils/selectors.cairo | 15 + src/openzeppelin/utils/serde.cairo | 10 + 13 files changed, 921 insertions(+), 155 deletions(-) create mode 100644 src/openzeppelin/access/accesscontrol/accesscontrol.cairo create mode 100644 src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo create mode 100644 src/openzeppelin/access/accesscontrol/interface.cairo create mode 100644 src/openzeppelin/tests/access/test_dual_accesscontrol.cairo create mode 100644 src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo diff --git a/src/openzeppelin/access/accesscontrol.cairo b/src/openzeppelin/access/accesscontrol.cairo index 43b483585..025142e68 100644 --- a/src/openzeppelin/access/accesscontrol.cairo +++ b/src/openzeppelin/access/accesscontrol.cairo @@ -1,152 +1,7 @@ -use starknet::ContractAddress; +mod accesscontrol; +use accesscontrol::AccessControl; -const DEFAULT_ADMIN_ROLE: felt252 = 0; -const IACCESSCONTROL_ID: felt252 = - 0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751; - -#[abi] -trait IAccessControl { - fn has_role(role: felt252, account: ContractAddress) -> bool; - fn get_role_admin(role: felt252) -> felt252; - fn grant_role(role: felt252, account: ContractAddress); - fn revoke_role(role: felt252, account: ContractAddress); - fn renounce_role(role: felt252, account: ContractAddress); -} - -#[contract] -mod AccessControl { - use super::IAccessControl; - use super::DEFAULT_ADMIN_ROLE; - use super::IACCESSCONTROL_ID; - use openzeppelin::introspection::src5::SRC5; - use starknet::ContractAddress; - use starknet::get_caller_address; - - struct Storage { - role_admin: LegacyMap, - role_members: LegacyMap<(felt252, ContractAddress), bool>, - } - - /// Emitted when `account` is granted `role`. - /// - /// `sender` is the account that originated the contract call, an admin role - /// bearer (except if `_grant_role` is called during initialization from the constructor). - #[event] - fn RoleGranted(role: felt252, account: ContractAddress, sender: ContractAddress) {} - - /// Emitted when `account` is revoked `role`. - /// - /// `sender` is the account that originated the contract call: - /// - If using `revoke_role`, it is the admin role bearer. - /// - If using `renounce_role`, it is the role bearer (i.e. `account`). - #[event] - fn RoleRevoked(role: felt252, account: ContractAddress, sender: ContractAddress) {} - - /// Emitted when `new_admin_role` is set as `role`'s admin role, replacing `previous_admin_role` - /// - /// `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite - /// {RoleAdminChanged} not being emitted signaling this. - #[event] - fn RoleAdminChanged(role: felt252, previous_admin_role: felt252, new_admin_role: felt252) {} - - impl AccessControlImpl of IAccessControl { - fn has_role(role: felt252, account: ContractAddress) -> bool { - role_members::read((role, account)) - } - - fn get_role_admin(role: felt252) -> felt252 { - role_admin::read(role) - } - - fn grant_role(role: felt252, account: ContractAddress) { - let admin = get_role_admin(role); - assert_only_role(admin); - _grant_role(role, account); - } - - fn revoke_role(role: felt252, account: ContractAddress) { - let admin: felt252 = get_role_admin(role); - assert_only_role(admin); - _revoke_role(role, account); - } - - fn renounce_role(role: felt252, account: ContractAddress) { - let caller: ContractAddress = get_caller_address(); - assert(caller == account, 'Can only renounce role for self'); - _revoke_role(role, account); - } - } +mod dual_accesscontrol; +mod interface; - #[view] - fn supports_interface(interface_id: felt252) -> bool { - SRC5::supports_interface(interface_id) - } - - #[view] - fn has_role(role: felt252, account: ContractAddress) -> bool { - AccessControlImpl::has_role(role, account) - } - - #[view] - fn get_role_admin(role: felt252) -> felt252 { - AccessControlImpl::get_role_admin(role) - } - - #[external] - fn grant_role(role: felt252, account: ContractAddress) { - AccessControlImpl::grant_role(role, account); - } - - #[external] - fn revoke_role(role: felt252, account: ContractAddress) { - AccessControlImpl::revoke_role(role, account); - } - - #[external] - fn renounce_role(role: felt252, account: ContractAddress) { - AccessControlImpl::renounce_role(role, account); - } - - #[internal] - fn initializer() { - SRC5::register_interface(IACCESSCONTROL_ID); - } - - #[internal] - fn assert_only_role(role: felt252) { - let caller: ContractAddress = get_caller_address(); - let authorized: bool = has_role(role, caller); - assert(authorized, 'Caller is missing role'); - } - - // - // WARNING - // The following internal methods are unprotected and should not be used - // outside of a contract's constructor. - // - - #[internal] - fn _grant_role(role: felt252, account: ContractAddress) { - if !has_role(role, account) { - let caller: ContractAddress = get_caller_address(); - role_members::write((role, account), true); - RoleGranted(role, account, caller); - } - } - - #[internal] - fn _revoke_role(role: felt252, account: ContractAddress) { - if has_role(role, account) { - let caller: ContractAddress = get_caller_address(); - role_members::write((role, account), false); - RoleRevoked(role, account, caller); - } - } - - #[internal] - fn _set_role_admin(role: felt252, admin_role: felt252) { - let previous_admin_role: felt252 = get_role_admin(role); - role_admin::write(role, admin_role); - RoleAdminChanged(role, previous_admin_role, admin_role); - } -} +const DEFAULT_ADMIN_ROLE: felt252 = 0; diff --git a/src/openzeppelin/access/accesscontrol/accesscontrol.cairo b/src/openzeppelin/access/accesscontrol/accesscontrol.cairo new file mode 100644 index 000000000..af4e9ce04 --- /dev/null +++ b/src/openzeppelin/access/accesscontrol/accesscontrol.cairo @@ -0,0 +1,194 @@ +#[contract] +mod AccessControl { + use openzeppelin::access::accesscontrol::interface; + use openzeppelin::introspection::src5::SRC5; + use starknet::ContractAddress; + use starknet::get_caller_address; + + struct Storage { + role_admin: LegacyMap, + role_members: LegacyMap<(felt252, ContractAddress), bool>, + } + + /// Emitted when `account` is granted `role`. + /// + /// `sender` is the account that originated the contract call, an admin role + /// bearer (except if `_grant_role` is called during initialization from the constructor). + #[event] + fn RoleGranted(role: felt252, account: ContractAddress, sender: ContractAddress) {} + + /// Emitted when `account` is revoked `role`. + /// + /// `sender` is the account that originated the contract call: + /// - If using `revoke_role`, it is the admin role bearer. + /// - If using `renounce_role`, it is the role bearer (i.e. `account`). + #[event] + fn RoleRevoked(role: felt252, account: ContractAddress, sender: ContractAddress) {} + + /// Emitted when `new_admin_role` is set as `role`'s admin role, replacing `previous_admin_role` + /// + /// `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + /// {RoleAdminChanged} not being emitted signaling this. + #[event] + fn RoleAdminChanged(role: felt252, previous_admin_role: felt252, new_admin_role: felt252) {} + + impl AccessControlImpl of interface::IAccessControl { + fn has_role(role: felt252, account: ContractAddress) -> bool { + role_members::read((role, account)) + } + + fn get_role_admin(role: felt252) -> felt252 { + role_admin::read(role) + } + + fn grant_role(role: felt252, account: ContractAddress) { + let admin = get_role_admin(role); + assert_only_role(admin); + _grant_role(role, account); + } + + fn revoke_role(role: felt252, account: ContractAddress) { + let admin: felt252 = get_role_admin(role); + assert_only_role(admin); + _revoke_role(role, account); + } + + fn renounce_role(role: felt252, account: ContractAddress) { + let caller: ContractAddress = get_caller_address(); + assert(caller == account, 'Can only renounce role for self'); + _revoke_role(role, account); + } + } + + impl AccessControlCamelImpl of interface::IAccessControlCamel { + fn hasRole(role: felt252, account: ContractAddress) -> bool { + AccessControlImpl::has_role(role, account) + } + + fn getRoleAdmin(role: felt252) -> felt252 { + AccessControlImpl::get_role_admin(role) + } + + fn grantRole(role: felt252, account: ContractAddress) { + AccessControlImpl::grant_role(role, account); + } + + fn revokeRole(role: felt252, account: ContractAddress) { + AccessControlImpl::revoke_role(role, account); + } + + fn renounceRole(role: felt252, account: ContractAddress) { + AccessControlImpl::renounce_role(role, account); + } + } + + // + // View + // + + #[view] + fn supports_interface(interface_id: felt252) -> bool { + SRC5::supports_interface(interface_id) + } + + #[view] + fn has_role(role: felt252, account: ContractAddress) -> bool { + AccessControlImpl::has_role(role, account) + } + + #[view] + fn hasRole(role: felt252, account: ContractAddress) -> bool { + AccessControlCamelImpl::hasRole(role, account) + } + + #[view] + fn get_role_admin(role: felt252) -> felt252 { + AccessControlImpl::get_role_admin(role) + } + + #[view] + fn getRoleAdmin(role: felt252) -> felt252 { + AccessControlCamelImpl::getRoleAdmin(role) + } + + // + // External + // + + #[external] + fn grant_role(role: felt252, account: ContractAddress) { + AccessControlImpl::grant_role(role, account); + } + + #[external] + fn grantRole(role: felt252, account: ContractAddress) { + AccessControlCamelImpl::grantRole(role, account); + } + + #[external] + fn revoke_role(role: felt252, account: ContractAddress) { + AccessControlImpl::revoke_role(role, account); + } + + #[external] + fn revokeRole(role: felt252, account: ContractAddress) { + AccessControlCamelImpl::revokeRole(role, account); + } + + #[external] + fn renounce_role(role: felt252, account: ContractAddress) { + AccessControlImpl::renounce_role(role, account); + } + + #[external] + fn renounceRole(role: felt252, account: ContractAddress) { + AccessControlCamelImpl::renounceRole(role, account); + } + + // + // Internals + // + + #[internal] + fn initializer() { + SRC5::register_interface(interface::IACCESSCONTROL_ID); + } + + #[internal] + fn assert_only_role(role: felt252) { + let caller: ContractAddress = get_caller_address(); + let authorized: bool = has_role(role, caller); + assert(authorized, 'Caller is missing role'); + } + + // + // WARNING + // The following internal methods are unprotected and should not be used + // outside of a contract's constructor. + // + + #[internal] + fn _grant_role(role: felt252, account: ContractAddress) { + if !has_role(role, account) { + let caller: ContractAddress = get_caller_address(); + role_members::write((role, account), true); + RoleGranted(role, account, caller); + } + } + + #[internal] + fn _revoke_role(role: felt252, account: ContractAddress) { + if has_role(role, account) { + let caller: ContractAddress = get_caller_address(); + role_members::write((role, account), false); + RoleRevoked(role, account, caller); + } + } + + #[internal] + fn _set_role_admin(role: felt252, admin_role: felt252) { + let previous_admin_role: felt252 = get_role_admin(role); + role_admin::write(role, admin_role); + RoleAdminChanged(role, previous_admin_role, admin_role); + } +} diff --git a/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo b/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo new file mode 100644 index 000000000..3e9c0151a --- /dev/null +++ b/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo @@ -0,0 +1,86 @@ +use array::ArrayTrait; +use array::SpanTrait; +use core::result::ResultTrait; +use option::OptionTrait; +use starknet::ContractAddress; +use starknet::Felt252TryIntoContractAddress; +use starknet::SyscallResultTrait; +use traits::TryInto; + +use openzeppelin::utils::Felt252TryIntoBool; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::try_selector_with_fallback; + +#[derive(Copy, Drop)] +struct DualCaseAccessControl { + contract_address: ContractAddress +} + +trait DualCaseAccessControlTrait { + fn has_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) -> bool; + fn get_role_admin(self: @DualCaseAccessControl, role: felt252) -> felt252; + fn grant_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress); + fn revoke_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress); + fn renounce_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress); +} + +impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { + fn has_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) -> bool { + let mut args = ArrayTrait::new(); + args.append_serde(role); + args.append_serde(account); + + (*try_selector_with_fallback( + *self.contract_address, selectors::has_role, selectors::hasRole, args.span() + ) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } + + fn get_role_admin(self: @DualCaseAccessControl, role: felt252) -> felt252 { + let mut args = ArrayTrait::new(); + args.append_serde(role); + + *try_selector_with_fallback( + *self.contract_address, selectors::get_role_admin, selectors::getRoleAdmin, args.span() + ) + .unwrap_syscall() + .at(0) + } + + fn grant_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) { + let mut args = ArrayTrait::new(); + args.append_serde(role); + args.append_serde(account); + + try_selector_with_fallback( + *self.contract_address, selectors::grant_role, selectors::grantRole, args.span() + ) + .unwrap_syscall(); + } + + fn revoke_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) { + let mut args = ArrayTrait::new(); + args.append_serde(role); + args.append_serde(account); + + try_selector_with_fallback( + *self.contract_address, selectors::revoke_role, selectors::revokeRole, args.span() + ) + .unwrap_syscall(); + } + + fn renounce_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) { + let mut args = ArrayTrait::new(); + args.append_serde(role); + args.append_serde(account); + + try_selector_with_fallback( + *self.contract_address, selectors::renounce_role, selectors::renounceRole, args.span() + ) + .unwrap_syscall(); + } +} diff --git a/src/openzeppelin/access/accesscontrol/interface.cairo b/src/openzeppelin/access/accesscontrol/interface.cairo new file mode 100644 index 000000000..9f333dc0f --- /dev/null +++ b/src/openzeppelin/access/accesscontrol/interface.cairo @@ -0,0 +1,32 @@ +use starknet::ContractAddress; + +const IACCESSCONTROL_ID: felt252 = + 0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751; + +#[abi] +trait IAccessControl { + #[view] + fn has_role(role: felt252, account: ContractAddress) -> bool; + #[view] + fn get_role_admin(role: felt252) -> felt252; + #[external] + fn grant_role(role: felt252, account: ContractAddress); + #[external] + fn revoke_role(role: felt252, account: ContractAddress); + #[external] + fn renounce_role(role: felt252, account: ContractAddress); +} + +#[abi] +trait IAccessControlCamel { + #[view] + fn hasRole(role: felt252, account: ContractAddress) -> bool; + #[view] + fn getRoleAdmin(role: felt252) -> felt252; + #[external] + fn grantRole(role: felt252, account: ContractAddress); + #[external] + fn revokeRole(role: felt252, account: ContractAddress); + #[external] + fn renounceRole(role: felt252, account: ContractAddress); +} diff --git a/src/openzeppelin/tests/access.cairo b/src/openzeppelin/tests/access.cairo index f5857e98d..149c62b59 100644 --- a/src/openzeppelin/tests/access.cairo +++ b/src/openzeppelin/tests/access.cairo @@ -1,3 +1,4 @@ mod test_accesscontrol; +mod test_dual_accesscontrol; mod test_ownable; mod test_dual_ownable; diff --git a/src/openzeppelin/tests/access/test_accesscontrol.cairo b/src/openzeppelin/tests/access/test_accesscontrol.cairo index 16b0a41fa..241f01553 100644 --- a/src/openzeppelin/tests/access/test_accesscontrol.cairo +++ b/src/openzeppelin/tests/access/test_accesscontrol.cairo @@ -1,6 +1,6 @@ use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; -use openzeppelin::access::accesscontrol::IACCESSCONTROL_ID; +use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; use starknet::contract_address_const; use starknet::ContractAddress; use starknet::testing; @@ -41,7 +41,18 @@ fn test_initializer() { } // -// has_role +// supports_interface +// + +#[test] +#[available_gas(2000000)] +fn test_supports_interface() { + AccessControl::initializer(); + assert(AccessControl::supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); +} + +// +// has_role & hasRole // #[test] @@ -53,6 +64,15 @@ fn test_has_role() { assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'should have role'); } +#[test] +#[available_gas(2000000)] +fn test_hasRole() { + setup(); + assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'should not have role'); + AccessControl::_grant_role(ROLE, AUTHORIZED()); + assert(AccessControl::hasRole(ROLE, AUTHORIZED()), 'should have role'); +} + // // assert_only_role @@ -87,7 +107,7 @@ fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { } // -// grant_role +// grant_role & grantRole // #[test] @@ -116,8 +136,34 @@ fn test_grant_role_unauthorized() { AccessControl::grant_role(ROLE, AUTHORIZED()); } +#[test] +#[available_gas(2000000)] +fn test_grantRole() { + setup(); + AccessControl::grantRole(ROLE, AUTHORIZED()); + assert(AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should be granted'); +} + +#[test] +#[available_gas(2000000)] +fn test_grantRole_multiple_times_for_granted_role() { + setup(); + AccessControl::grantRole(ROLE, AUTHORIZED()); + AccessControl::grantRole(ROLE, AUTHORIZED()); + assert(AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should still be granted'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is missing role', ))] +fn test_grantRole_unauthorized() { + setup(); + testing::set_caller_address(AUTHORIZED()); + AccessControl::grantRole(ROLE, AUTHORIZED()); +} + // -// revoke_role +// revoke_role & revokeRole // #[test] @@ -157,8 +203,45 @@ fn test_revoke_role_unauthorized() { AccessControl::revoke_role(ROLE, AUTHORIZED()); } +#[test] +#[available_gas(2000000)] +fn test_revokeRole_for_role_not_granted() { + setup(); + AccessControl::revokeRole(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +fn test_revokeRole_for_granted_role() { + setup(); + AccessControl::grantRole(ROLE, AUTHORIZED()); + AccessControl::revokeRole(ROLE, AUTHORIZED()); + assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should be revoked'); +} + +#[test] +#[available_gas(2000000)] +fn test_revokeRole_multiple_times_for_granted_role() { + setup(); + AccessControl::grantRole(ROLE, AUTHORIZED()); + + AccessControl::revokeRole(ROLE, AUTHORIZED()); + AccessControl::revokeRole(ROLE, AUTHORIZED()); + assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should still be revoked'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is missing role', ))] +fn test_revokeRole_unauthorized() { + setup(); + + testing::set_caller_address(OTHER()); + AccessControl::revokeRole(ROLE, AUTHORIZED()); +} + // -// renounce_role +// renounce_role & renounceRole // #[test] @@ -204,6 +287,49 @@ fn test_renounce_role_unauthorized() { AccessControl::renounce_role(ROLE, AUTHORIZED()); } +#[test] +#[available_gas(2000000)] +fn test_renounceRole_for_role_not_granted() { + setup(); + testing::set_caller_address(AUTHORIZED()); + + AccessControl::renounceRole(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +fn test_renounceRole_for_granted_role() { + setup(); + AccessControl::grantRole(ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); + + AccessControl::renounceRole(ROLE, AUTHORIZED()); + assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should be renounced'); +} + +#[test] +#[available_gas(2000000)] +fn test_renounceRole_multiple_times_for_granted_role() { + setup(); + AccessControl::grantRole(ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); + + AccessControl::renounceRole(ROLE, AUTHORIZED()); + AccessControl::renounceRole(ROLE, AUTHORIZED()); + assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should still be renounced'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Can only renounce role for self', ))] +fn test_renounceRole_unauthorized() { + setup(); + AccessControl::grantRole(ROLE, AUTHORIZED()); + + // Admin is unauthorized caller + AccessControl::renounceRole(ROLE, AUTHORIZED()); +} + // // _set_role_admin // diff --git a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo new file mode 100644 index 000000000..19ae46a4f --- /dev/null +++ b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo @@ -0,0 +1,297 @@ +use array::ArrayTrait; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_contract_address; + +use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; +use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; +use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; +use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; +use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; +use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::tests::mocks::accesscontrol_panic_mock::CamelAccessControlPanicMock; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils; +use openzeppelin::utils::serde::SerializedAppend; + +/// +/// Constants +/// + +const ROLE: felt252 = 41; + +fn ADMIN() -> ContractAddress { + contract_address_const::<10>() +} + +fn AUTHORIZED() -> ContractAddress { + contract_address_const::<20>() +} + +/// +/// Setup +/// + +fn setup_snake() -> (DualCaseAccessControl, IAccessControlDispatcher) { + let mut calldata = ArrayTrait::new(); + calldata.append_serde(ADMIN()); + let target = utils::deploy(SnakeAccessControlMock::TEST_CLASS_HASH, calldata); + ( + DualCaseAccessControl { + contract_address: target + }, IAccessControlDispatcher { + contract_address: target + } + ) +} + +fn setup_camel() -> (DualCaseAccessControl, IAccessControlCamelDispatcher) { + let mut calldata = ArrayTrait::new(); + calldata.append_serde(ADMIN()); + let target = utils::deploy(CamelAccessControlMock::TEST_CLASS_HASH, calldata); + ( + DualCaseAccessControl { + contract_address: target + }, IAccessControlCamelDispatcher { + contract_address: target + } + ) +} + +fn setup_non_accesscontrol() -> DualCaseAccessControl { + let calldata = ArrayTrait::new(); + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); + DualCaseAccessControl { contract_address: target } +} + +fn setup_accesscontrol_panic() -> (DualCaseAccessControl, DualCaseAccessControl) { + let snake_target = utils::deploy( + SnakeAccessControlPanicMock::TEST_CLASS_HASH, ArrayTrait::new() + ); + let camel_target = utils::deploy( + CamelAccessControlPanicMock::TEST_CLASS_HASH, ArrayTrait::new() + ); + ( + DualCaseAccessControl { + contract_address: snake_target + }, DualCaseAccessControl { + contract_address: camel_target + } + ) +} + +/// +/// snake_case target +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_has_role() { + let (dispatcher, _) = setup_snake(); + assert(dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()), 'Should have role'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_has_role() { + let dispatcher = setup_non_accesscontrol(); + dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_has_role_exists_and_panics() { + let (dispatcher, _) = setup_accesscontrol_panic(); + dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_get_role_admin() { + let (dispatcher, _) = setup_snake(); + assert(dispatcher.get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'Should get admin'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_get_role_admin() { + let dispatcher = setup_non_accesscontrol(); + dispatcher.get_role_admin(ROLE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_get_role_admin_exists_and_panics() { + let (dispatcher, _) = setup_accesscontrol_panic(); + dispatcher.get_role_admin(ROLE); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_grant_role() { + let (dispatcher, target) = setup_snake(); + set_contract_address(ADMIN()); + dispatcher.grant_role(ROLE, AUTHORIZED()); + assert(target.has_role(ROLE, AUTHORIZED()), 'Should grant role'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_grant_role() { + let dispatcher = setup_non_accesscontrol(); + dispatcher.grant_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_grant_role_exists_and_panics() { + let (dispatcher, _) = setup_accesscontrol_panic(); + dispatcher.grant_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_revoke_role() { + let (dispatcher, target) = setup_snake(); + set_contract_address(ADMIN()); + dispatcher.revoke_role(ROLE, AUTHORIZED()); + assert(!target.has_role(ROLE, AUTHORIZED()), 'Should revoke role'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_revoke_role() { + let dispatcher = setup_non_accesscontrol(); + dispatcher.revoke_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_revoke_role_exists_and_panics() { + let (dispatcher, _) = setup_accesscontrol_panic(); + dispatcher.revoke_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_renounce_role() { + let (dispatcher, target) = setup_snake(); + set_contract_address(ADMIN()); + dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); + assert(!target.has_role(DEFAULT_ADMIN_ROLE, ADMIN()), 'Should renounce role'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_renounce_role() { + let dispatcher = setup_non_accesscontrol(); + dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_renounce_role_exists_and_panics() { + let (dispatcher, _) = setup_accesscontrol_panic(); + dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); +} + +/// +/// camelCase target +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_hasRole() { + let (dispatcher, _) = setup_camel(); + assert(dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()), 'Should have role'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_hasRole_exists_and_panics() { + let (_, dispatcher) = setup_accesscontrol_panic(); + dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_getRoleAdmin() { + let (dispatcher, _) = setup_camel(); + assert(dispatcher.get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'Should get admin'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_getRoleAdmin_exists_and_panics() { + let (_, dispatcher) = setup_accesscontrol_panic(); + dispatcher.get_role_admin(ROLE); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_grantRole() { + let (dispatcher, target) = setup_camel(); + set_contract_address(ADMIN()); + dispatcher.grant_role(ROLE, AUTHORIZED()); + assert(target.hasRole(ROLE, AUTHORIZED()), 'Should grant role'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_grantRole_exists_and_panics() { + let (_, dispatcher) = setup_accesscontrol_panic(); + dispatcher.grant_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_revokeRole() { + let (dispatcher, target) = setup_camel(); + set_contract_address(ADMIN()); + dispatcher.grant_role(ROLE, AUTHORIZED()); + dispatcher.revoke_role(ROLE, AUTHORIZED()); + assert(!target.hasRole(ROLE, AUTHORIZED()), 'Should revoke role'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_revokeRole_exists_and_panics() { + let (_, dispatcher) = setup_accesscontrol_panic(); + dispatcher.revoke_role(ROLE, AUTHORIZED()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_renounceRole() { + let (dispatcher, target) = setup_camel(); + set_contract_address(ADMIN()); + dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); + assert(!target.hasRole(DEFAULT_ADMIN_ROLE, ADMIN()), 'Should renounce role'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_renounceRole_exists_and_panics() { + let (_, dispatcher) = setup_accesscontrol_panic(); + dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); +} + diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 0f36b9086..bb101efc0 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -3,6 +3,9 @@ mod reentrancy_mock; mod erc721_receiver; mod erc721_panic_mock; mod mock_pausable; +mod accesscontrol_panic_mock; +mod camel_accesscontrol_mock; +mod snake_accesscontrol_mock; mod dual_ownable_mocks; mod snake721_mock; mod camel721_mock; diff --git a/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo b/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo new file mode 100644 index 000000000..a1c13cf66 --- /dev/null +++ b/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo @@ -0,0 +1,69 @@ +// Although these modules are designed to panic, functions +// still need a valid return value. We chose: +// +// 3 for felt252 +// false for bool + +#[contract] +mod SnakeAccessControlPanicMock { + use starknet::ContractAddress; + + #[view] + fn has_role(role: felt252, account: ContractAddress) -> bool { + panic_with_felt252('Some error'); + false + } + + #[view] + fn get_role_admin(role: felt252) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[external] + fn grant_role(role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external] + fn revoke_role(role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external] + fn renounce_role(role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } +} + +#[contract] +mod CamelAccessControlPanicMock { + use starknet::ContractAddress; + + #[view] + fn hasRole(role: felt252, account: ContractAddress) -> bool { + panic_with_felt252('Some error'); + false + } + + #[view] + fn getRoleAdmin(role: felt252) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[external] + fn grantRole(role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external] + fn revokeRole(role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external] + fn renounceRole(role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } +} diff --git a/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo b/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo new file mode 100644 index 000000000..4d6cc6f7e --- /dev/null +++ b/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo @@ -0,0 +1,39 @@ +#[contract] +mod CamelAccessControlMock { + use starknet::ContractAddress; + use starknet::get_caller_address; + use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::utils::serde::SpanSerde; + + #[constructor] + fn constructor(admin: ContractAddress) { + AccessControl::initializer(); + AccessControl::_grant_role(DEFAULT_ADMIN_ROLE, admin); + } + + #[view] + fn hasRole(role: felt252, account: ContractAddress) -> bool { + AccessControl::hasRole(role, account) + } + + #[view] + fn getRoleAdmin(role: felt252) -> felt252 { + AccessControl::getRoleAdmin(role) + } + + #[external] + fn grantRole(role: felt252, account: ContractAddress) { + AccessControl::grantRole(role, account); + } + + #[external] + fn revokeRole(role: felt252, account: ContractAddress) { + AccessControl::revokeRole(role, account); + } + + #[external] + fn renounceRole(role: felt252, account: ContractAddress) { + AccessControl::renounceRole(role, account); + } +} diff --git a/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo b/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo new file mode 100644 index 000000000..76c2d9f26 --- /dev/null +++ b/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo @@ -0,0 +1,39 @@ +#[contract] +mod SnakeAccessControlMock { + use starknet::ContractAddress; + use starknet::get_caller_address; + use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::utils::serde::SpanSerde; + + #[constructor] + fn constructor(admin: ContractAddress) { + AccessControl::initializer(); + AccessControl::_grant_role(DEFAULT_ADMIN_ROLE, admin); + } + + #[view] + fn has_role(role: felt252, account: ContractAddress) -> bool { + AccessControl::has_role(role, account) + } + + #[view] + fn get_role_admin(role: felt252) -> felt252 { + AccessControl::get_role_admin(role) + } + + #[external] + fn grant_role(role: felt252, account: ContractAddress) { + AccessControl::grant_role(role, account); + } + + #[external] + fn revoke_role(role: felt252, account: ContractAddress) { + AccessControl::revoke_role(role, account); + } + + #[external] + fn renounce_role(role: felt252, account: ContractAddress) { + AccessControl::renounce_role(role, account); + } +} diff --git a/src/openzeppelin/utils/selectors.cairo b/src/openzeppelin/utils/selectors.cairo index 8f56ff9d5..33844ef8e 100644 --- a/src/openzeppelin/utils/selectors.cairo +++ b/src/openzeppelin/utils/selectors.cairo @@ -1,3 +1,18 @@ +// +// AccessControl +// + +const get_role_admin: felt252 = 0x302e0454f48778e0ca3a2e714a289c4e8d8e03d614b370130abb1a524a47f22; +const getRoleAdmin: felt252 = 0x2034da88f3e3f3382ab0faf97fe5f74fe34d551ddff7fda974d756bf12130a0; +const grant_role: felt252 = 0x18a2f881894a5eb15a2a00f598839abaa75bd7f1fea1a37e42779d7fbcd9cf8; +const grantRole: felt252 = 0x37322ff1aabefe50aec25a14eb84b168b7be4f2d66fbbdb5dd8135e8234c37a; +const has_role: felt252 = 0x30559321b47d576b645ed7bd24089943dd5fd3a359ecdd6fa8f05c1bab67d6b; +const hasRole: felt252 = 0x35ed3407ba17dc741dd3af821fa1548619ebcdc87c95bcea9e3bc510951fae8; +const renounce_role: felt252 = 0xd80093a4ee6a9e649f2ae3c64963d5096948d50cf4ea055500aa03a342fd43; +const renounceRole: felt252 = 0x3c4022816cd5119ac7938fd7a982062e4cacd4777b4eda6e6a8f64d9e6833; +const revoke_role: felt252 = 0x246116ed358bad337e64a4df51cb57a40929189494ad5905a39872c489136ec; +const revokeRole: felt252 = 0xa7ef1739dec1e216a0ba2987650983a3104c707ad0831a30184a3b1382dd7d; + // // Ownable // diff --git a/src/openzeppelin/utils/serde.cairo b/src/openzeppelin/utils/serde.cairo index 68c3720f0..aca966485 100644 --- a/src/openzeppelin/utils/serde.cairo +++ b/src/openzeppelin/utils/serde.cairo @@ -17,3 +17,13 @@ impl SpanSerde< Option::Some(deserialize_array_helper(ref serialized, arr, length)?.span()) } } + +trait SerializedAppend { + fn append_serde(ref self: Array, value: T); +} + +impl SerializedAppendImpl, impl TDrop: Drop> of SerializedAppend { + fn append_serde(ref self: Array, value: T) { + value.serialize(ref self); + } +} From 3a8e3e7234ac68319f75e1d6a7a4c7512c4a26b9 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Wed, 5 Jul 2023 17:41:47 -0400 Subject: [PATCH 057/124] erc20 dual dispatcher (#622) * add camel methods * update erc20 dispatcher path * refactor tests, add tests for camel methods * fix formatting * add try_selector_with_fallback and bool impl * add erc20 selectors * add abi to traits * add dual20 mocks * add panic trait * add dual20 mocks * add dual20 * add dual20 * add dual20 tests * tidy up tests * move tests to token dir * fix formatting * clean up tests * restructure token tests * remove panic trait * reorder imports * remove unused imports * fix comments * update const selector casings * remove comments * Apply suggestions from code review Co-authored-by: Eric Nordelo * change target member to contract_address * fix formatting * fix dispatcher calls * change dispatcher to dual_dispatcher * reorder use clauses * move selectors to selectors mod * fix formatting * reorder selectors * remove duplicate selectors * remove ignore * simplify dispatcher vars * fix comment * Apply suggestions from code review Co-authored-by: Eric Nordelo * fix test constants * add SerializedAppend trait * integrate append_serde * integrate append_serde and utils selector * change u256 fns to constants * change u256 fns to constants * move dual721 test to token/, apply append_serde, change u256 fn to constant * fix formatting * add append_serde * move append_serde to serde * update append_serde path * change dispatcher to IERC20 * remove unnecessary into() * remove bindings * add binding to empty arrays * fix formatting --------- Co-authored-by: Eric Nordelo --- .../access/ownable/dual_ownable.cairo | 8 +- src/openzeppelin/tests.cairo | 4 +- src/openzeppelin/tests/mocks.cairo | 4 + .../tests/mocks/camel20_mock.cairo | 58 ++ .../tests/mocks/erc20_panic.cairo | 96 ++++ .../tests/mocks/non721_mock.cairo | 7 + .../tests/mocks/snake20_mock.cairo | 58 ++ src/openzeppelin/tests/test_account.cairo | 39 +- src/openzeppelin/tests/test_erc20.cairo | 451 --------------- src/openzeppelin/tests/token.cairo | 3 + .../tests/token/test_dual20.cairo | 348 +++++++++++ .../tests/{ => token}/test_dual721.cairo | 102 ++-- src/openzeppelin/tests/token/test_erc20.cairo | 543 ++++++++++++++++++ .../tests/{ => token}/test_erc721.cairo | 155 +++-- src/openzeppelin/tests/utils.cairo | 7 +- src/openzeppelin/token/erc20.cairo | 236 +------- src/openzeppelin/token/erc20/dual20.cairo | 138 +++++ src/openzeppelin/token/erc20/erc20.cairo | 314 ++++++++++ src/openzeppelin/token/erc20/interface.cairo | 45 ++ src/openzeppelin/token/erc721/dual721.cairo | 58 +- src/openzeppelin/token/erc721/erc721.cairo | 8 +- src/openzeppelin/utils/selectors.cairo | 12 + 22 files changed, 1810 insertions(+), 884 deletions(-) create mode 100644 src/openzeppelin/tests/mocks/camel20_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/erc20_panic.cairo create mode 100644 src/openzeppelin/tests/mocks/non721_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/snake20_mock.cairo delete mode 100644 src/openzeppelin/tests/test_erc20.cairo create mode 100644 src/openzeppelin/tests/token.cairo create mode 100644 src/openzeppelin/tests/token/test_dual20.cairo rename src/openzeppelin/tests/{ => token}/test_dual721.cairo (83%) create mode 100644 src/openzeppelin/tests/token/test_erc20.cairo rename src/openzeppelin/tests/{ => token}/test_erc721.cairo (80%) create mode 100644 src/openzeppelin/token/erc20/dual20.cairo create mode 100644 src/openzeppelin/token/erc20/erc20.cairo create mode 100644 src/openzeppelin/token/erc20/interface.cairo diff --git a/src/openzeppelin/access/ownable/dual_ownable.cairo b/src/openzeppelin/access/ownable/dual_ownable.cairo index 840c371f5..fc7381f80 100644 --- a/src/openzeppelin/access/ownable/dual_ownable.cairo +++ b/src/openzeppelin/access/ownable/dual_ownable.cairo @@ -6,12 +6,12 @@ use starknet::ContractAddress; use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResultTrait; use starknet::call_contract_syscall; -use traits::Into; use traits::TryInto; use openzeppelin::utils::try_selector_with_fallback; use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; #[derive(Copy, Drop)] struct DualCaseOwnable { @@ -26,7 +26,9 @@ trait DualCaseOwnableTrait { impl DualCaseOwnableImpl of DualCaseOwnableTrait { fn owner(self: @DualCaseOwnable) -> ContractAddress { - (*call_contract_syscall(*self.contract_address, selectors::owner, ArrayTrait::new().span()) + let args = ArrayTrait::new(); + + (*call_contract_syscall(*self.contract_address, selectors::owner, args.span()) .unwrap_syscall() .at(0)) .try_into() @@ -35,7 +37,7 @@ impl DualCaseOwnableImpl of DualCaseOwnableTrait { fn transfer_ownership(self: @DualCaseOwnable, new_owner: ContractAddress) { let mut args = ArrayTrait::new(); - args.append(new_owner.into()); + args.append_serde(new_owner); try_selector_with_fallback( *self.contract_address, diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index e50d9f319..800541185 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -2,9 +2,7 @@ mod access; mod test_reentrancyguard; mod test_src5; mod test_account; -mod test_erc20; -mod test_erc721; -mod test_dual721; +mod token; mod test_initializable; mod test_pausable; mod mocks; diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index bb101efc0..325546d0c 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -3,6 +3,10 @@ mod reentrancy_mock; mod erc721_receiver; mod erc721_panic_mock; mod mock_pausable; +mod camel20_mock; +mod snake20_mock; +mod erc20_panic; +mod non721_mock; mod accesscontrol_panic_mock; mod camel_accesscontrol_mock; mod snake_accesscontrol_mock; diff --git a/src/openzeppelin/tests/mocks/camel20_mock.cairo b/src/openzeppelin/tests/mocks/camel20_mock.cairo new file mode 100644 index 000000000..3b9bd1048 --- /dev/null +++ b/src/openzeppelin/tests/mocks/camel20_mock.cairo @@ -0,0 +1,58 @@ +#[contract] +mod CamelERC20Mock { + use starknet::ContractAddress; + use openzeppelin::token::erc20::ERC20; + + #[constructor] + fn constructor( + name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress + ) { + ERC20::initializer(name, symbol); + ERC20::_mint(recipient, initial_supply); + } + + #[view] + fn name() -> felt252 { + ERC20::name() + } + + #[view] + fn symbol() -> felt252 { + ERC20::symbol() + } + + #[view] + fn decimals() -> u8 { + ERC20::decimals() + } + + #[view] + fn totalSupply() -> u256 { + ERC20::totalSupply() + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + ERC20::balanceOf(account) + } + + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + ERC20::allowance(owner, spender) + } + + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + ERC20::transfer(recipient, amount) + } + + #[external] + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20::transferFrom(sender, recipient, amount) + } + + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool { + ERC20::approve(spender, amount) + } +} diff --git a/src/openzeppelin/tests/mocks/erc20_panic.cairo b/src/openzeppelin/tests/mocks/erc20_panic.cairo new file mode 100644 index 000000000..89389bc74 --- /dev/null +++ b/src/openzeppelin/tests/mocks/erc20_panic.cairo @@ -0,0 +1,96 @@ +// Although these modules are designed to panic, functions +// still need a valid return value. We chose: +// +// 3 for felt252 and u8 +// zero for ContractAddress +// false for bool +// u256 { 3, 3 } for u256 + +#[contract] +mod SnakeERC20Panic { + use starknet::ContractAddress; + + /// + /// Agnostic + /// + + #[view] + fn name() -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn symbol() -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn decimals() -> u8 { + panic_with_felt252('Some error'); + 3_u8 + } + + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + panic_with_felt252('Some error'); + u256 { low: 3, high: 3 } + } + + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + panic_with_felt252('Some error'); + false + } + + #[external] + fn approve(to: ContractAddress, token_id: u256) -> bool { + panic_with_felt252('Some error'); + false + } + + /// + /// Snake + /// + + #[view] + fn total_supply() -> u256 { + panic_with_felt252('Some error'); + u256 { low: 3, high: 3 } + } + + #[view] + fn balance_of(account: ContractAddress) -> u256 { + panic_with_felt252('Some error'); + u256 { low: 3, high: 3 } + } + + #[external] + fn transfer_from(from: ContractAddress, to: ContractAddress, amount: u256) -> bool { + panic_with_felt252('Some error'); + false + } +} + +#[contract] +mod CamelERC20Panic { + use starknet::ContractAddress; + + #[view] + fn totalSupply() -> u256 { + panic_with_felt252('Some error'); + u256 { low: 3, high: 3 } + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + panic_with_felt252('Some error'); + u256 { low: 3, high: 3 } + } + + #[external] + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) { + panic_with_felt252('Some error'); + } +} diff --git a/src/openzeppelin/tests/mocks/non721_mock.cairo b/src/openzeppelin/tests/mocks/non721_mock.cairo new file mode 100644 index 000000000..05c7d140c --- /dev/null +++ b/src/openzeppelin/tests/mocks/non721_mock.cairo @@ -0,0 +1,7 @@ +#[contract] +mod NonERC721 { + #[view] + fn nope() -> bool { + false + } +} diff --git a/src/openzeppelin/tests/mocks/snake20_mock.cairo b/src/openzeppelin/tests/mocks/snake20_mock.cairo new file mode 100644 index 000000000..dd5a034f7 --- /dev/null +++ b/src/openzeppelin/tests/mocks/snake20_mock.cairo @@ -0,0 +1,58 @@ +#[contract] +mod SnakeERC20Mock { + use starknet::ContractAddress; + use openzeppelin::token::erc20::ERC20; + + #[constructor] + fn constructor( + name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress + ) { + ERC20::initializer(name, symbol); + ERC20::_mint(recipient, initial_supply); + } + + #[view] + fn name() -> felt252 { + ERC20::name() + } + + #[view] + fn symbol() -> felt252 { + ERC20::symbol() + } + + #[view] + fn decimals() -> u8 { + ERC20::decimals() + } + + #[view] + fn total_supply() -> u256 { + ERC20::total_supply() + } + + #[view] + fn balance_of(account: ContractAddress) -> u256 { + ERC20::balance_of(account) + } + + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + ERC20::allowance(owner, spender) + } + + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + ERC20::transfer(recipient, amount) + } + + #[external] + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20::transfer_from(sender, recipient, amount) + } + + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool { + ERC20::approve(spender, amount) + } +} diff --git a/src/openzeppelin/tests/test_account.cairo b/src/openzeppelin/tests/test_account.cairo index 5a833327f..d39fa796c 100644 --- a/src/openzeppelin/tests/test_account.cairo +++ b/src/openzeppelin/tests/test_account.cairo @@ -17,12 +17,13 @@ use openzeppelin::account::TRANSACTION_VERSION; use openzeppelin::introspection::src5::ISRC5_ID; use openzeppelin::tests::utils; use openzeppelin::token::erc20::ERC20; -use openzeppelin::token::erc20::IERC20Dispatcher; -use openzeppelin::token::erc20::IERC20DispatcherTrait; +use openzeppelin::token::erc20::interface::IERC20Dispatcher; +use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; const PUBLIC_KEY: felt252 = 0x333333; const NEW_PUBKEY: felt252 = 0x789789; -const TRANSFER_SELECTOR: felt252 = 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e; const SALT: felt252 = 123; #[derive(Drop)] @@ -81,11 +82,10 @@ fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispa let symbol = 0; let mut calldata = ArrayTrait::new(); - calldata.append(name); - calldata.append(symbol); - calldata.append(initial_supply.low.into()); - calldata.append(initial_supply.high.into()); - calldata.append(recipient.into()); + calldata.append_serde(name); + calldata.append_serde(symbol); + calldata.append_serde(initial_supply); + calldata.append_serde(recipient); let address = utils::deploy(ERC20::TEST_CLASS_HASH, calldata); IERC20Dispatcher { contract_address: address } @@ -241,10 +241,11 @@ fn test_execute_with_version(version: Option) { // Craft call and add to calls array let mut calldata = ArrayTrait::new(); let amount: u256 = 200; - calldata.append(recipient.into()); - calldata.append(amount.low.into()); - calldata.append(amount.high.into()); - let call = Call { to: erc20.contract_address, selector: TRANSFER_SELECTOR, calldata: calldata }; + calldata.append_serde(recipient); + calldata.append_serde(amount); + let call = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata + }; let mut calls = ArrayTrait::new(); calls.append(call); @@ -318,21 +319,19 @@ fn test_multicall() { // Craft call1 let mut calldata1 = ArrayTrait::new(); let amount1: u256 = 300; - calldata1.append(recipient1.into()); - calldata1.append(amount1.low.into()); - calldata1.append(amount1.high.into()); + calldata1.append_serde(recipient1); + calldata1.append_serde(amount1); let call1 = Call { - to: erc20.contract_address, selector: TRANSFER_SELECTOR, calldata: calldata1 + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata1 }; // Craft call2 let mut calldata2 = ArrayTrait::new(); let amount2: u256 = 500; - calldata2.append(recipient2.into()); - calldata2.append(amount2.low.into()); - calldata2.append(amount2.high.into()); + calldata2.append_serde(recipient2); + calldata2.append_serde(amount2); let call2 = Call { - to: erc20.contract_address, selector: TRANSFER_SELECTOR, calldata: calldata2 + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata2 }; // Bundle calls and exeute diff --git a/src/openzeppelin/tests/test_erc20.cairo b/src/openzeppelin/tests/test_erc20.cairo deleted file mode 100644 index 5c5615990..000000000 --- a/src/openzeppelin/tests/test_erc20.cairo +++ /dev/null @@ -1,451 +0,0 @@ -use openzeppelin::token::erc20::ERC20; -use starknet::contract_address_const; -use starknet::ContractAddress; -use starknet::testing::set_caller_address; -use integer::u256; -use integer::u256_from_felt252; -use integer::BoundedInt; -use traits::Into; - -// -// Constants -// - -const NAME: felt252 = 111; -const SYMBOL: felt252 = 222; - -// -// Helper functions -// - -fn setup() -> (ContractAddress, u256) { - let initial_supply: u256 = u256_from_felt252(2000); - let account: ContractAddress = contract_address_const::<1>(); - // Set account as default caller - set_caller_address(account); - - ERC20::constructor(NAME, SYMBOL, initial_supply, account); - (account, initial_supply) -} - -fn set_caller_as_zero() { - set_caller_address(contract_address_const::<0>()); -} - -// -// Tests -// - -#[test] -#[available_gas(2000000)] -fn test_initializer() { - ERC20::initializer(NAME, SYMBOL); - - assert(ERC20::name() == NAME, 'Name should be NAME'); - assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20::decimals() == 18_u8, 'Decimals should be 18'); - assert(ERC20::total_supply() == u256_from_felt252(0), 'Supply should eq 0'); -} - - -#[test] -#[available_gas(2000000)] -fn test_constructor() { - let initial_supply: u256 = u256_from_felt252(2000); - let account: ContractAddress = contract_address_const::<1>(); - let decimals: u8 = 18_u8; - - ERC20::constructor(NAME, SYMBOL, initial_supply, account); - - let owner_balance: u256 = ERC20::balance_of(account); - assert(owner_balance == initial_supply, 'Should eq inital_supply'); - - assert(ERC20::total_supply() == initial_supply, 'Should eq inital_supply'); - assert(ERC20::name() == NAME, 'Name should be NAME'); - assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20::decimals() == decimals, 'Decimals should be 18'); -} - -#[test] -#[available_gas(2000000)] -fn test_approve() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - let success: bool = ERC20::approve(spender, amount); - assert(success, 'Should return true'); - assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve from 0', ))] -fn test_approve_from_zero() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - set_caller_as_zero(); - - ERC20::approve(spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve to 0', ))] -fn test_approve_to_zero() { - let (owner, supply) = setup(); - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::approve(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__approve() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::_approve(owner, spender, amount); - assert(ERC20::allowance(owner, spender) == amount, 'Spender not approved correctly'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve from 0', ))] -fn test__approve_from_zero() { - let owner: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<1>(); - let amount: u256 = u256_from_felt252(100); - ERC20::_approve(owner, spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve to 0', ))] -fn test__approve_to_zero() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt252(100); - ERC20::_approve(owner, spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - let success: bool = ERC20::transfer(recipient, amount); - - assert(success, 'Should return true'); - assert(ERC20::balance_of(recipient) == amount, 'Balance should eq amount'); - assert(ERC20::balance_of(sender) == supply - amount, 'Should eq supply - amount'); - assert(ERC20::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test__transfer() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - ERC20::_transfer(sender, recipient, amount); - - assert(ERC20::balance_of(recipient) == amount, 'Balance should eq amount'); - assert(ERC20::balance_of(sender) == supply - amount, 'Should eq supply - amount'); - assert(ERC20::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] -fn test__transfer_not_enough_balance() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let amount: u256 = supply + u256_from_felt252(1); - ERC20::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: transfer from 0', ))] -fn test__transfer_from_zero() { - let sender: ContractAddress = contract_address_const::<0>(); - let recipient: ContractAddress = contract_address_const::<1>(); - let amount: u256 = u256_from_felt252(100); - ERC20::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: transfer to 0', ))] -fn test__transfer_to_zero() { - let (sender, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt252(100); - ERC20::_transfer(sender, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer_from() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::approve(spender, amount); - - set_caller_address(spender); - - let success: bool = ERC20::transfer_from(owner, recipient, amount); - assert(success, 'Should return true'); - - // Will dangle without setting as a var - let spender_allowance: u256 = ERC20::allowance(owner, spender); - - assert(ERC20::balance_of(recipient) == amount, 'Should eq amount'); - assert(ERC20::balance_of(owner) == supply - amount, 'Should eq suppy - amount'); - assert(spender_allowance == u256_from_felt252(0), 'Should eq 0'); - assert(ERC20::total_supply() == supply, 'Total supply should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test_transfer_from_doesnt_consume_infinite_allowance() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::approve(spender, BoundedInt::max()); - - set_caller_address(spender); - ERC20::transfer_from(owner, recipient, amount); - - let spender_allowance: u256 = ERC20::allowance(owner, spender); - assert(spender_allowance == BoundedInt::max(), 'Allowance should not change'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] -fn test_transfer_from_greater_than_allowance() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt252(100); - let amount_plus_one: u256 = amount + u256_from_felt252(1); - - ERC20::approve(spender, amount); - - set_caller_address(spender); - - ERC20::transfer_from(owner, recipient, amount_plus_one); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: transfer to 0', ))] -fn test_transfer_from_to_zero_address() { - let (owner, supply) = setup(); - - let recipient: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::approve(spender, amount); - - set_caller_address(spender); - - ERC20::transfer_from(owner, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] -fn test_transfer_from_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let recipient: ContractAddress = contract_address_const::<2>(); - let spender: ContractAddress = contract_address_const::<3>(); - let amount: u256 = u256_from_felt252(100); - - set_caller_address(zero_address); - - ERC20::transfer_from(owner, recipient, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_increase_allowance() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::approve(spender, amount); - let success: bool = ERC20::increase_allowance(spender, amount); - assert(success, 'Should return true'); - - let spender_allowance: u256 = ERC20::allowance(owner, spender); - assert(spender_allowance == amount + amount, 'Should be amount * 2'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve to 0', ))] -fn test_increase_allowance_to_zero_address() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::increase_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve from 0', ))] -fn test_increase_allowance_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - set_caller_address(zero_address); - - ERC20::increase_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test_decrease_allowance() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::approve(spender, amount); - let success: bool = ERC20::decrease_allowance(spender, amount); - assert(success, 'Should return true'); - - let spender_allowance: u256 = ERC20::allowance(owner, spender); - assert(spender_allowance == amount - amount, 'Should be 0'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] -fn test_decrease_allowance_to_zero_address() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::decrease_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] -fn test_decrease_allowance_from_zero_address() { - let (owner, supply) = setup(); - - let zero_address: ContractAddress = contract_address_const::<0>(); - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - set_caller_address(zero_address); - - ERC20::decrease_allowance(spender, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__spend_allowance_not_unlimited() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::_approve(owner, spender, supply); - ERC20::_spend_allowance(owner, spender, amount); - assert(ERC20::allowance(owner, spender) == supply - amount, 'Should eq supply - amount'); -} - -#[test] -#[available_gas(2000000)] -fn test__spend_allowance_unlimited() { - let (owner, supply) = setup(); - - let spender: ContractAddress = contract_address_const::<2>(); - let max_minus_one: u256 = BoundedInt::max() - 1.into(); - - ERC20::_approve(owner, spender, BoundedInt::max()); - ERC20::_spend_allowance(owner, spender, max_minus_one); - - assert(ERC20::allowance(owner, spender) == BoundedInt::max(), 'Allowance should not change'); -} - -#[test] -#[available_gas(2000000)] -fn test__mint() { - let minter: ContractAddress = contract_address_const::<2>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::_mint(minter, amount); - - let minter_balance: u256 = ERC20::balance_of(minter); - assert(minter_balance == amount, 'Should eq amount'); - - assert(ERC20::total_supply() == amount, 'Should eq total supply'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: mint to 0', ))] -fn test__mint_to_zero() { - let minter: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::_mint(minter, amount); -} - -#[test] -#[available_gas(2000000)] -fn test__burn() { - let (owner, supply) = setup(); - - let amount: u256 = u256_from_felt252(100); - ERC20::_burn(owner, amount); - - assert(ERC20::total_supply() == supply - amount, 'Should eq supply - amount'); - assert(ERC20::balance_of(owner) == supply - amount, 'Should eq supply - amount'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('ERC20: burn from 0', ))] -fn test__burn_from_zero() { - setup(); - let zero_address: ContractAddress = contract_address_const::<0>(); - let amount: u256 = u256_from_felt252(100); - - ERC20::_burn(zero_address, amount); -} diff --git a/src/openzeppelin/tests/token.cairo b/src/openzeppelin/tests/token.cairo new file mode 100644 index 000000000..a072d4a08 --- /dev/null +++ b/src/openzeppelin/tests/token.cairo @@ -0,0 +1,3 @@ +mod test_dual20; +mod test_erc20; +mod test_erc721; diff --git a/src/openzeppelin/tests/token/test_dual20.cairo b/src/openzeppelin/tests/token/test_dual20.cairo new file mode 100644 index 000000000..0da4ea5c7 --- /dev/null +++ b/src/openzeppelin/tests/token/test_dual20.cairo @@ -0,0 +1,348 @@ +use array::ArrayTrait; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_contract_address; + +use openzeppelin::tests::mocks::camel20_mock::CamelERC20Mock; +use openzeppelin::tests::mocks::erc20_panic::SnakeERC20Panic; +use openzeppelin::tests::mocks::erc20_panic::CamelERC20Panic; +use openzeppelin::tests::mocks::non721_mock::NonERC721; +use openzeppelin::tests::mocks::snake20_mock::SnakeERC20Mock; +use openzeppelin::token::erc20::dual20::DualERC20; +use openzeppelin::token::erc20::dual20::DualERC20Trait; +use openzeppelin::token::erc20::interface::IERC20CamelDispatcher; +use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait; +use openzeppelin::token::erc20::interface::IERC20Dispatcher; +use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; +use openzeppelin::tests::utils; +use openzeppelin::utils::serde::SerializedAppend; + +/// +/// Constants +/// + +const NAME: felt252 = 111; +const SYMBOL: felt252 = 222; +const DECIMALS: u8 = 18_u8; +const SUPPLY: u256 = 2000; +const VALUE: u256 = 300; + +fn OWNER() -> ContractAddress { + contract_address_const::<10>() +} +fn SPENDER() -> ContractAddress { + contract_address_const::<20>() +} +fn RECIPIENT() -> ContractAddress { + contract_address_const::<30>() +} +fn OPERATOR() -> ContractAddress { + contract_address_const::<40>() +} + +/// +/// Setup +/// + +fn setup_snake() -> (DualERC20, IERC20Dispatcher) { + let mut calldata = ArrayTrait::new(); + calldata.append_serde(NAME); + calldata.append_serde(SYMBOL); + calldata.append_serde(SUPPLY); + calldata.append_serde(OWNER()); + let target = utils::deploy(SnakeERC20Mock::TEST_CLASS_HASH, calldata); + (DualERC20 { contract_address: target }, IERC20Dispatcher { contract_address: target }) +} + +fn setup_camel() -> (DualERC20, IERC20CamelDispatcher) { + let mut calldata = ArrayTrait::new(); + calldata.append_serde(NAME); + calldata.append_serde(SYMBOL); + calldata.append_serde(SUPPLY); + calldata.append_serde(OWNER()); + let target = utils::deploy(CamelERC20Mock::TEST_CLASS_HASH, calldata); + (DualERC20 { contract_address: target }, IERC20CamelDispatcher { contract_address: target }) +} + +fn setup_non_erc20() -> DualERC20 { + let calldata = ArrayTrait::new(); + let target = utils::deploy(NonERC721::TEST_CLASS_HASH, calldata); + DualERC20 { contract_address: target } +} + +fn setup_erc20_panic() -> (DualERC20, DualERC20) { + let snake_target = utils::deploy(SnakeERC20Panic::TEST_CLASS_HASH, ArrayTrait::new()); + let camel_target = utils::deploy(CamelERC20Panic::TEST_CLASS_HASH, ArrayTrait::new()); + (DualERC20 { contract_address: snake_target }, DualERC20 { contract_address: camel_target }) +} + +/// +/// Case agnostic methods +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_name() { + let (snake_dispatcher, _) = setup_snake(); + let (camel_dispatcher, _) = setup_camel(); + assert(snake_dispatcher.name() == NAME, 'Should return name'); + assert(camel_dispatcher.name() == NAME, 'Should return name'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_name() { + let dispatcher = setup_non_erc20(); + dispatcher.name(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_name_exists_and_panics() { + let (dispatcher, _) = setup_erc20_panic(); + dispatcher.name(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_symbol() { + let (snake_dispatcher, _) = setup_snake(); + let (camel_dispatcher, _) = setup_camel(); + assert(snake_dispatcher.symbol() == SYMBOL, 'Should return symbol'); + assert(camel_dispatcher.symbol() == SYMBOL, 'Should return symbol'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_symbol() { + let dispatcher = setup_non_erc20(); + dispatcher.symbol(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_symbol_exists_and_panics() { + let (dispatcher, _) = setup_erc20_panic(); + dispatcher.symbol(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_decimals() { + let (snake_dispatcher, _) = setup_snake(); + let (camel_dispatcher, _) = setup_camel(); + assert(snake_dispatcher.decimals() == DECIMALS, 'Should return symbol'); + assert(camel_dispatcher.decimals() == DECIMALS, 'Should return symbol'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_decimals() { + let dispatcher = setup_non_erc20(); + dispatcher.decimals(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_decimals_exists_and_panics() { + let (dispatcher, _) = setup_erc20_panic(); + dispatcher.decimals(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_transfer() { + let (snake_dispatcher, snake_target) = setup_snake(); + set_contract_address(OWNER()); + assert(snake_dispatcher.transfer(RECIPIENT(), VALUE), 'Should return true'); + assert(snake_target.balance_of(RECIPIENT()) == VALUE, 'Should equal VALUE'); + + let (camel_dispatcher, camel_target) = setup_camel(); + set_contract_address(OWNER()); + assert(camel_dispatcher.transfer(RECIPIENT(), VALUE), 'Should return true'); + assert(camel_target.balanceOf(RECIPIENT()) == VALUE, 'Should equal VALUE'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_transfer() { + let dispatcher = setup_non_erc20(); + dispatcher.transfer(RECIPIENT(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_transfer_exists_and_panics() { + let (dispatcher, _) = setup_erc20_panic(); + dispatcher.transfer(RECIPIENT(), VALUE); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_approve() { + let (snake_dispatcher, snake_target) = setup_snake(); + set_contract_address(OWNER()); + assert(snake_dispatcher.approve(SPENDER(), VALUE), 'Should return true'); + assert(snake_target.allowance(OWNER(), SPENDER()) == VALUE, 'Allowance should equal VALUE'); + + let (camel_dispatcher, camel_target) = setup_camel(); + set_contract_address(OWNER()); + assert(camel_dispatcher.approve(SPENDER(), VALUE), 'Should return true'); + assert(camel_target.allowance(OWNER(), SPENDER()) == VALUE, 'Allowance should equal VALUE'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_approve() { + let dispatcher = setup_non_erc20(); + dispatcher.approve(SPENDER(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_approve_exists_and_panics() { + let (dispatcher, _) = setup_erc20_panic(); + dispatcher.approve(SPENDER(), VALUE); +} + +/// +/// snake_case target +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_total_supply() { + let (dispatcher, _) = setup_snake(); + assert(dispatcher.total_supply() == SUPPLY, 'Should return balance'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_total_supply() { + let dispatcher = setup_non_erc20(); + dispatcher.total_supply(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_total_supply_exists_and_panics() { + let (dispatcher, _) = setup_erc20_panic(); + dispatcher.total_supply(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_balance_of() { + let (dispatcher, _) = setup_snake(); + assert(dispatcher.balance_of(OWNER()) == SUPPLY, 'Should return balance'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_balance_of() { + let dispatcher = setup_non_erc20(); + dispatcher.balance_of(OWNER()); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_balance_of_exists_and_panics() { + let (dispatcher, _) = setup_erc20_panic(); + dispatcher.balance_of(OWNER()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_transfer_from() { + let (dispatcher, target) = setup_snake(); + set_contract_address(OWNER()); + target.approve(OPERATOR(), VALUE); + + set_contract_address(OPERATOR()); + dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); + assert(target.balance_of(RECIPIENT()) == VALUE, 'Should transfer VALUE'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_transfer_from() { + let dispatcher = setup_non_erc20(); + dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_transfer_from_exists_and_panics() { + let (dispatcher, _) = setup_erc20_panic(); + dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); +} + +/// +/// camelCase target +/// + +#[test] +#[available_gas(2000000)] +fn test_dual_totalSupply() { + let (dispatcher, _) = setup_camel(); + assert(dispatcher.total_supply() == SUPPLY, 'Should return supply'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_totalSupply_exists_and_panics() { + let (_, dispatcher) = setup_erc20_panic(); + dispatcher.total_supply(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_balanceOf() { + let (dispatcher, _) = setup_camel(); + assert(dispatcher.balance_of(OWNER()) == SUPPLY, 'Should return balance'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_balanceOf_exists_and_panics() { + let (_, dispatcher) = setup_erc20_panic(); + dispatcher.balance_of(OWNER()); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_transferFrom() { + let (dispatcher, target) = setup_camel(); + set_contract_address(OWNER()); + target.approve(OPERATOR(), VALUE); + + set_contract_address(OPERATOR()); + dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); + assert(target.balanceOf(RECIPIENT()) == VALUE, 'Should transfer VALUE'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_transferFrom_exists_and_panics() { + let (_, dispatcher) = setup_erc20_panic(); + dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); +} diff --git a/src/openzeppelin/tests/test_dual721.cairo b/src/openzeppelin/tests/token/test_dual721.cairo similarity index 83% rename from src/openzeppelin/tests/test_dual721.cairo rename to src/openzeppelin/tests/token/test_dual721.cairo index 98d7459f9..0ef8a0521 100644 --- a/src/openzeppelin/tests/test_dual721.cairo +++ b/src/openzeppelin/tests/token/test_dual721.cairo @@ -1,4 +1,3 @@ -use traits::Into; use array::ArrayTrait; use starknet::ContractAddress; use starknet::contract_address_const; @@ -19,6 +18,7 @@ use openzeppelin::tests::mocks::erc721_panic_mock::SnakeERC721PanicMock; use openzeppelin::tests::mocks::erc721_panic_mock::CamelERC721PanicMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils; +use openzeppelin::utils::serde::SerializedAppend; /// /// Constants @@ -27,10 +27,8 @@ use openzeppelin::tests::utils; const NAME: felt252 = 111; const SYMBOL: felt252 = 222; const URI: felt252 = 333; +const TOKEN_ID: u256 = 7; -fn TOKEN_ID() -> u256 { - 7.into() -} fn OWNER() -> ContractAddress { contract_address_const::<10>() } @@ -46,9 +44,9 @@ fn OPERATOR() -> ContractAddress { fn DATA(success: bool) -> Span { let mut data = ArrayTrait::new(); if success { - data.append(SUCCESS); + data.append_serde(SUCCESS); } else { - data.append(FAILURE); + data.append_serde(FAILURE); } data.span() } @@ -59,11 +57,10 @@ fn DATA(success: bool) -> Span { fn setup_snake() -> (DualCaseERC721, IERC721Dispatcher) { let mut calldata = ArrayTrait::new(); - calldata.append(NAME); - calldata.append(SYMBOL); - calldata.append(TOKEN_ID().low.into()); - calldata.append(TOKEN_ID().high.into()); - calldata.append(URI); + calldata.append_serde(NAME); + calldata.append_serde(SYMBOL); + calldata.append_serde(TOKEN_ID); + calldata.append_serde(URI); set_caller_address(OWNER()); let target = utils::deploy(SnakeERC721Mock::TEST_CLASS_HASH, calldata); (DualCaseERC721 { contract_address: target }, IERC721Dispatcher { contract_address: target }) @@ -71,11 +68,10 @@ fn setup_snake() -> (DualCaseERC721, IERC721Dispatcher) { fn setup_camel() -> (DualCaseERC721, IERC721CamelDispatcher) { let mut calldata = ArrayTrait::new(); - calldata.append(NAME); - calldata.append(SYMBOL); - calldata.append(TOKEN_ID().low.into()); - calldata.append(TOKEN_ID().high.into()); - calldata.append(URI); + calldata.append_serde(NAME); + calldata.append_serde(SYMBOL); + calldata.append_serde(TOKEN_ID); + calldata.append_serde(URI); set_caller_address(OWNER()); let target = utils::deploy(CamelERC721Mock::TEST_CLASS_HASH, calldata); ( @@ -168,13 +164,13 @@ fn test_dual_symbol_exists_and_panics() { fn test_dual_approve() { let (snake_dispatcher, snake_target) = setup_snake(); set_contract_address(OWNER()); - snake_dispatcher.approve(SPENDER(), TOKEN_ID()); - assert(snake_target.get_approved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); + snake_dispatcher.approve(SPENDER(), TOKEN_ID); + assert(snake_target.get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); let (camel_dispatcher, camel_target) = setup_camel(); set_contract_address(OWNER()); - camel_dispatcher.approve(SPENDER(), TOKEN_ID()); - assert(camel_target.getApproved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); + camel_dispatcher.approve(SPENDER(), TOKEN_ID); + assert(camel_target.getApproved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); } #[test] @@ -182,7 +178,7 @@ fn test_dual_approve() { #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_dual_no_approve() { let dispatcher = setup_non_erc721(); - dispatcher.approve(SPENDER(), TOKEN_ID()); + dispatcher.approve(SPENDER(), TOKEN_ID); } #[test] @@ -190,7 +186,7 @@ fn test_dual_no_approve() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_approve_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); - dispatcher.approve(SPENDER(), TOKEN_ID()); + dispatcher.approve(SPENDER(), TOKEN_ID); } /// @@ -224,7 +220,7 @@ fn test_dual_balance_of_exists_and_panics() { #[available_gas(2000000)] fn test_dual_owner_of() { let (dispatcher, target) = setup_snake(); - assert(dispatcher.owner_of(TOKEN_ID()) == OWNER(), 'Should return owner'); + assert(dispatcher.owner_of(TOKEN_ID) == OWNER(), 'Should return owner'); } #[test] @@ -232,7 +228,7 @@ fn test_dual_owner_of() { #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_dual_no_owner_of() { let dispatcher = setup_non_erc721(); - dispatcher.owner_of(TOKEN_ID()); + dispatcher.owner_of(TOKEN_ID); } #[test] @@ -240,15 +236,15 @@ fn test_dual_no_owner_of() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_owner_of_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); - dispatcher.owner_of(TOKEN_ID()); + dispatcher.owner_of(TOKEN_ID); } #[test] #[available_gas(2000000)] fn test_dual_transfer_from() { let (dispatcher, target) = setup_snake(); - dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); - assert(target.owner_of(TOKEN_ID()) == RECIPIENT(), 'Should transfer token'); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); + assert(target.owner_of(TOKEN_ID) == RECIPIENT(), 'Should transfer token'); } #[test] @@ -256,7 +252,7 @@ fn test_dual_transfer_from() { #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_dual_no_transfer_from() { let dispatcher = setup_non_erc721(); - dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); } #[test] @@ -264,7 +260,7 @@ fn test_dual_no_transfer_from() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_transfer_from_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); - dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); } #[test] @@ -272,8 +268,8 @@ fn test_dual_transfer_from_exists_and_panics() { fn test_dual_safe_transfer_from() { let (dispatcher, target) = setup_snake(); let receiver = setup_receiver(); - dispatcher.safe_transfer_from(OWNER(), receiver, TOKEN_ID(), DATA(true)); - assert(target.owner_of(TOKEN_ID()) == receiver, 'Should transfer token'); + dispatcher.safe_transfer_from(OWNER(), receiver, TOKEN_ID, DATA(true)); + assert(target.owner_of(TOKEN_ID) == receiver, 'Should transfer token'); } #[test] @@ -281,7 +277,7 @@ fn test_dual_safe_transfer_from() { #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_dual_no_safe_transfer_from() { let dispatcher = setup_non_erc721(); - dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID(), DATA(true)); + dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] @@ -289,7 +285,7 @@ fn test_dual_no_safe_transfer_from() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_safe_transfer_from_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); - dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID(), DATA(true)); + dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] @@ -297,8 +293,8 @@ fn test_dual_safe_transfer_from_exists_and_panics() { fn test_dual_get_approved() { let (dispatcher, target) = setup_snake(); set_contract_address(OWNER()); - target.approve(SPENDER(), TOKEN_ID()); - assert(dispatcher.get_approved(TOKEN_ID()) == SPENDER(), 'Should return approval'); + target.approve(SPENDER(), TOKEN_ID); + assert(dispatcher.get_approved(TOKEN_ID) == SPENDER(), 'Should return approval'); } #[test] @@ -306,7 +302,7 @@ fn test_dual_get_approved() { #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_dual_no_get_approved() { let dispatcher = setup_non_erc721(); - dispatcher.get_approved(TOKEN_ID()); + dispatcher.get_approved(TOKEN_ID); } #[test] @@ -314,7 +310,7 @@ fn test_dual_no_get_approved() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_get_approved_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); - dispatcher.get_approved(TOKEN_ID()); + dispatcher.get_approved(TOKEN_ID); } #[test] @@ -371,7 +367,7 @@ fn test_dual_is_approved_for_all_exists_and_panics() { #[available_gas(2000000)] fn test_dual_token_uri() { let (dispatcher, target) = setup_snake(); - assert(dispatcher.token_uri(TOKEN_ID()) == URI, 'Should return URI'); + assert(dispatcher.token_uri(TOKEN_ID) == URI, 'Should return URI'); } #[test] @@ -379,7 +375,7 @@ fn test_dual_token_uri() { #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_dual_no_token_uri() { let dispatcher = setup_non_erc721(); - dispatcher.token_uri(TOKEN_ID()); + dispatcher.token_uri(TOKEN_ID); } #[test] @@ -387,7 +383,7 @@ fn test_dual_no_token_uri() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_token_uri_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); - dispatcher.token_uri(TOKEN_ID()); + dispatcher.token_uri(TOKEN_ID); } /// @@ -413,7 +409,7 @@ fn test_dual_balanceOf_exists_and_panics() { #[available_gas(2000000)] fn test_dual_ownerOf() { let (dispatcher, target) = setup_camel(); - assert(dispatcher.owner_of(TOKEN_ID()) == OWNER(), 'Should return owner'); + assert(dispatcher.owner_of(TOKEN_ID) == OWNER(), 'Should return owner'); } #[test] @@ -421,7 +417,7 @@ fn test_dual_ownerOf() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_ownerOf_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); - dispatcher.owner_of(TOKEN_ID()); + dispatcher.owner_of(TOKEN_ID); } #[test] @@ -429,8 +425,8 @@ fn test_dual_ownerOf_exists_and_panics() { fn test_dual_transferFrom() { let (dispatcher, target) = setup_camel(); set_contract_address(OWNER()); - dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); - assert(target.ownerOf(TOKEN_ID()) == RECIPIENT(), 'Should transfer token'); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); + assert(target.ownerOf(TOKEN_ID) == RECIPIENT(), 'Should transfer token'); } #[test] @@ -438,7 +434,7 @@ fn test_dual_transferFrom() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_transferFrom_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); - dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); + dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); } #[test] @@ -446,8 +442,8 @@ fn test_dual_transferFrom_exists_and_panics() { fn test_dual_safeTransferFrom() { let (dispatcher, target) = setup_camel(); let receiver = setup_receiver(); - dispatcher.safe_transfer_from(OWNER(), receiver, TOKEN_ID(), DATA(true)); - assert(target.ownerOf(TOKEN_ID()) == receiver, 'Should transfer token'); + dispatcher.safe_transfer_from(OWNER(), receiver, TOKEN_ID, DATA(true)); + assert(target.ownerOf(TOKEN_ID) == receiver, 'Should transfer token'); } #[test] @@ -455,7 +451,7 @@ fn test_dual_safeTransferFrom() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_safeTransferFrom_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); - dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID(), DATA(true)); + dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] @@ -463,8 +459,8 @@ fn test_dual_safeTransferFrom_exists_and_panics() { fn test_dual_getApproved() { let (dispatcher, target) = setup_camel(); set_contract_address(OWNER()); - target.approve(SPENDER(), TOKEN_ID()); - assert(dispatcher.get_approved(TOKEN_ID()) == SPENDER(), 'Should return approval'); + target.approve(SPENDER(), TOKEN_ID); + assert(dispatcher.get_approved(TOKEN_ID) == SPENDER(), 'Should return approval'); } #[test] @@ -472,7 +468,7 @@ fn test_dual_getApproved() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_getApproved_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); - dispatcher.get_approved(TOKEN_ID()); + dispatcher.get_approved(TOKEN_ID); } #[test] @@ -513,7 +509,7 @@ fn test_dual_isApprovedForAll_exists_and_panics() { #[available_gas(2000000)] fn test_dual_tokenUri() { let (dispatcher, target) = setup_camel(); - assert(dispatcher.token_uri(TOKEN_ID()) == URI, 'Should return URI'); + assert(dispatcher.token_uri(TOKEN_ID) == URI, 'Should return URI'); } #[test] @@ -521,5 +517,5 @@ fn test_dual_tokenUri() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_tokenUri_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); - dispatcher.token_uri(TOKEN_ID()); + dispatcher.token_uri(TOKEN_ID); } diff --git a/src/openzeppelin/tests/token/test_erc20.cairo b/src/openzeppelin/tests/token/test_erc20.cairo new file mode 100644 index 000000000..775c974fa --- /dev/null +++ b/src/openzeppelin/tests/token/test_erc20.cairo @@ -0,0 +1,543 @@ +use openzeppelin::token::erc20::ERC20; +use integer::BoundedInt; +use integer::u256; +use integer::u256_from_felt252; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_caller_address; +use traits::Into; +use zeroable::Zeroable; + +// +// Constants +// + +const NAME: felt252 = 111; +const SYMBOL: felt252 = 222; +const DECIMALS: u8 = 18_u8; +const SUPPLY: u256 = 2000; +const VALUE: u256 = 300; + +fn OWNER() -> ContractAddress { + contract_address_const::<1>() +} + +fn SPENDER() -> ContractAddress { + contract_address_const::<2>() +} + +fn RECIPIENT() -> ContractAddress { + contract_address_const::<3>() +} + +// +// Setup +// + +fn setup() { + ERC20::constructor(NAME, SYMBOL, SUPPLY, OWNER()); +} + +// +// initializer & constructor +// + +#[test] +#[available_gas(2000000)] +fn test_initializer() { + ERC20::initializer(NAME, SYMBOL); + + assert(ERC20::name() == NAME, 'Name should be NAME'); + assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20::decimals() == DECIMALS, 'Decimals should be 18'); + assert(ERC20::total_supply() == 0, 'Supply should eq 0'); +} + + +#[test] +#[available_gas(2000000)] +fn test_constructor() { + ERC20::constructor(NAME, SYMBOL, SUPPLY, OWNER()); + + assert(ERC20::balance_of(OWNER()) == SUPPLY, 'Should eq inital_supply'); + assert(ERC20::total_supply() == SUPPLY, 'Should eq inital_supply'); + assert(ERC20::name() == NAME, 'Name should be NAME'); + assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20::decimals() == DECIMALS, 'Decimals should be 18'); +} + +// +// Getters +// + +#[test] +#[available_gas(2000000)] +fn test_total_supply() { + ERC20::_mint(OWNER(), SUPPLY); + assert(ERC20::total_supply() == SUPPLY, 'Should eq SUPPLY'); +} + +#[test] +#[available_gas(2000000)] +fn test_totalSupply() { + ERC20::_mint(OWNER(), SUPPLY); + assert(ERC20::totalSupply() == SUPPLY, 'Should eq SUPPLY'); +} + +#[test] +#[available_gas(2000000)] +fn test_balance_of() { + ERC20::_mint(OWNER(), SUPPLY); + assert(ERC20::balance_of(OWNER()) == SUPPLY, 'Should eq SUPPLY'); +} + +#[test] +#[available_gas(2000000)] +fn test_balanceOf() { + ERC20::_mint(OWNER(), SUPPLY); + assert(ERC20::balanceOf(OWNER()) == SUPPLY, 'Should eq SUPPLY'); +} + +#[test] +#[available_gas(2000000)] +fn test_allowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE, 'Should eq VALUE'); +} + +// +// approve & _approve +// + +#[test] +#[available_gas(2000000)] +fn test_approve() { + setup(); + set_caller_address(OWNER()); + assert(ERC20::approve(SPENDER(), VALUE), 'Should return true'); + + assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: approve from 0', ))] +fn test_approve_from_zero() { + setup(); + ERC20::approve(SPENDER(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: approve to 0', ))] +fn test_approve_to_zero() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(Zeroable::zero(), VALUE); +} + +#[test] +#[available_gas(2000000)] +fn test__approve() { + setup(); + set_caller_address(OWNER()); + ERC20::_approve(OWNER(), SPENDER(), VALUE); + + assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: approve from 0', ))] +fn test__approve_from_zero() { + setup(); + ERC20::_approve(Zeroable::zero(), SPENDER(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: approve to 0', ))] +fn test__approve_to_zero() { + setup(); + set_caller_address(OWNER()); + ERC20::_approve(OWNER(), Zeroable::zero(), VALUE); +} + +// +// transfer & _transfer +// + +#[test] +#[available_gas(2000000)] +fn test_transfer() { + setup(); + set_caller_address(OWNER()); + assert(ERC20::transfer(RECIPIENT(), VALUE), 'Should return true'); + + assert(ERC20::balance_of(RECIPIENT()) == VALUE, 'Balance should eq VALUE'); + assert(ERC20::balance_of(OWNER()) == SUPPLY - VALUE, 'Should eq supply - VALUE'); + assert(ERC20::total_supply() == SUPPLY, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test__transfer() { + setup(); + + ERC20::_transfer(OWNER(), RECIPIENT(), VALUE); + assert(ERC20::balance_of(RECIPIENT()) == VALUE, 'Balance should eq amount'); + assert(ERC20::balance_of(OWNER()) == SUPPLY - VALUE, 'Should eq supply - amount'); + assert(ERC20::total_supply() == SUPPLY, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test__transfer_not_enough_balance() { + setup(); + set_caller_address(OWNER()); + + let balance_plus_one = SUPPLY + 1; + ERC20::_transfer(OWNER(), RECIPIENT(), balance_plus_one); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: transfer from 0', ))] +fn test__transfer_from_zero() { + setup(); + ERC20::_transfer(Zeroable::zero(), RECIPIENT(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: transfer to 0', ))] +fn test__transfer_to_zero() { + setup(); + ERC20::_transfer(OWNER(), Zeroable::zero(), VALUE); +} + +// +// transfer_from & transferFrom +// + +#[test] +#[available_gas(2000000)] +fn test_transfer_from() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + set_caller_address(SPENDER()); + assert(ERC20::transfer_from(OWNER(), RECIPIENT(), VALUE), 'Should return true'); + + assert(ERC20::balance_of(RECIPIENT()) == VALUE, 'Should eq amount'); + assert(ERC20::balance_of(OWNER()) == SUPPLY - VALUE, 'Should eq suppy - amount'); + assert(ERC20::allowance(OWNER(), SPENDER()) == 0, 'Should eq 0'); + assert(ERC20::total_supply() == SUPPLY, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test_transfer_from_doesnt_consume_infinite_allowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), BoundedInt::max()); + + set_caller_address(SPENDER()); + ERC20::transfer_from(OWNER(), RECIPIENT(), VALUE); + + assert( + ERC20::allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change' + ); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test_transfer_from_greater_than_allowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + set_caller_address(SPENDER()); + let allowance_plus_one = VALUE + 1; + ERC20::transfer_from(OWNER(), RECIPIENT(), allowance_plus_one); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: transfer to 0', ))] +fn test_transfer_from_to_zero_address() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + set_caller_address(SPENDER()); + ERC20::transfer_from(OWNER(), Zeroable::zero(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test_transfer_from_from_zero_address() { + setup(); + ERC20::transfer_from(Zeroable::zero(), RECIPIENT(), VALUE); +} + +#[test] +#[available_gas(2000000)] +fn test_transferFrom() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + set_caller_address(SPENDER()); + assert(ERC20::transferFrom(OWNER(), RECIPIENT(), VALUE), 'Should return true'); + + assert(ERC20::balanceOf(RECIPIENT()) == VALUE, 'Should eq amount'); + assert(ERC20::balanceOf(OWNER()) == SUPPLY - VALUE, 'Should eq suppy - amount'); + assert(ERC20::allowance(OWNER(), SPENDER()) == 0, 'Should eq 0'); + assert(ERC20::totalSupply() == SUPPLY, 'Total supply should not change'); +} + +#[test] +#[available_gas(2000000)] +fn test_transferFrom_doesnt_consume_infinite_allowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), BoundedInt::max()); + + set_caller_address(SPENDER()); + ERC20::transferFrom(OWNER(), RECIPIENT(), VALUE); + + assert( + ERC20::allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change' + ); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test_transferFrom_greater_than_allowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + set_caller_address(SPENDER()); + let allowance_plus_one = VALUE + 1; + ERC20::transferFrom(OWNER(), RECIPIENT(), allowance_plus_one); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: transfer to 0', ))] +fn test_transferFrom_to_zero_address() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + set_caller_address(SPENDER()); + ERC20::transferFrom(OWNER(), Zeroable::zero(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test_transferFrom_from_zero_address() { + setup(); + ERC20::transferFrom(Zeroable::zero(), RECIPIENT(), VALUE); +} + +// +// increase_allowance & increaseAllowance +// + +#[test] +#[available_gas(2000000)] +fn test_increase_allowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + assert(ERC20::increase_allowance(SPENDER(), VALUE), 'Should return true'); + assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: approve to 0', ))] +fn test_increase_allowance_to_zero_address() { + setup(); + set_caller_address(OWNER()); + ERC20::increase_allowance(Zeroable::zero(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: approve from 0', ))] +fn test_increase_allowance_from_zero_address() { + setup(); + ERC20::increase_allowance(SPENDER(), VALUE); +} + +#[test] +#[available_gas(2000000)] +fn test_increaseAllowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + assert(ERC20::increaseAllowance(SPENDER(), VALUE), 'Should return true'); + assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: approve to 0', ))] +fn test_increaseAllowance_to_zero_address() { + setup(); + set_caller_address(OWNER()); + ERC20::increaseAllowance(Zeroable::zero(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: approve from 0', ))] +fn test_increaseAllowance_from_zero_address() { + setup(); + ERC20::increaseAllowance(SPENDER(), VALUE); +} + +// +// decrease_allowance & decreaseAllowance +// + +#[test] +#[available_gas(2000000)] +fn test_decrease_allowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + assert(ERC20::decrease_allowance(SPENDER(), VALUE), 'Should return true'); + assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test_decrease_allowance_to_zero_address() { + setup(); + set_caller_address(OWNER()); + ERC20::decrease_allowance(Zeroable::zero(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test_decrease_allowance_from_zero_address() { + setup(); + ERC20::decrease_allowance(SPENDER(), VALUE); +} + +#[test] +#[available_gas(2000000)] +fn test_decreaseAllowance() { + setup(); + set_caller_address(OWNER()); + ERC20::approve(SPENDER(), VALUE); + + assert(ERC20::decreaseAllowance(SPENDER(), VALUE), 'Should return true'); + assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test_decreaseAllowance_to_zero_address() { + setup(); + set_caller_address(OWNER()); + ERC20::decreaseAllowance(Zeroable::zero(), VALUE); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('u256_sub Overflow', ))] +fn test_decreaseAllowance_from_zero_address() { + setup(); + ERC20::decreaseAllowance(SPENDER(), VALUE); +} + +// +// _spend_allowance +// + +#[test] +#[available_gas(2000000)] +fn test__spend_allowance_not_unlimited() { + setup(); + + ERC20::_approve(OWNER(), SPENDER(), SUPPLY); + ERC20::_spend_allowance(OWNER(), SPENDER(), VALUE); + assert(ERC20::allowance(OWNER(), SPENDER()) == SUPPLY - VALUE, 'Should eq supply - amount'); +} + +#[test] +#[available_gas(2000000)] +fn test__spend_allowance_unlimited() { + setup(); + ERC20::_approve(OWNER(), SPENDER(), BoundedInt::max()); + + let max_minus_one: u256 = BoundedInt::max() - 1; + ERC20::_spend_allowance(OWNER(), SPENDER(), max_minus_one); + + assert( + ERC20::allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change' + ); +} + +// +// _mint +// + +#[test] +#[available_gas(2000000)] +fn test__mint() { + ERC20::_mint(OWNER(), VALUE); + + assert(ERC20::balance_of(OWNER()) == VALUE, 'Should eq amount'); + assert(ERC20::total_supply() == VALUE, 'Should eq total supply'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: mint to 0', ))] +fn test__mint_to_zero() { + ERC20::_mint(Zeroable::zero(), VALUE); +} + +// +// _burn +// + +#[test] +#[available_gas(2000000)] +fn test__burn() { + setup(); + ERC20::_burn(OWNER(), VALUE); + + assert(ERC20::total_supply() == SUPPLY - VALUE, 'Should eq supply - amount'); + assert(ERC20::balance_of(OWNER()) == SUPPLY - VALUE, 'Should eq supply - amount'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC20: burn from 0', ))] +fn test__burn_from_zero() { + setup(); + ERC20::_burn(Zeroable::zero(), VALUE); +} diff --git a/src/openzeppelin/tests/test_erc721.cairo b/src/openzeppelin/tests/token/test_erc721.cairo similarity index 80% rename from src/openzeppelin/tests/test_erc721.cairo rename to src/openzeppelin/tests/token/test_erc721.cairo index d37a495a8..4f968c0ee 100644 --- a/src/openzeppelin/tests/test_erc721.cairo +++ b/src/openzeppelin/tests/token/test_erc721.cairo @@ -1,7 +1,7 @@ +use openzeppelin::account::Account; use openzeppelin::introspection::src5; use openzeppelin::token::erc721; use openzeppelin::token::erc721::ERC721; -use openzeppelin::account::Account; use openzeppelin::tests::utils; use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; @@ -21,10 +21,7 @@ use zeroable::Zeroable; const NAME: felt252 = 111; const SYMBOL: felt252 = 222; const URI: felt252 = 333; - -fn TOKEN_ID() -> u256 { - 7.into() -} +const TOKEN_ID: u256 = 7; fn ZERO() -> ContractAddress { Zeroable::zero() @@ -61,7 +58,7 @@ fn DATA(success: bool) -> Span { fn setup() { ERC721::initializer(NAME, SYMBOL); - ERC721::_mint(OWNER(), TOKEN_ID()); + ERC721::_mint(OWNER(), TOKEN_ID); } fn setup_receiver() -> ContractAddress { @@ -86,7 +83,7 @@ fn test_constructor() { assert(ERC721::name() == NAME, 'Name should be NAME'); assert(ERC721::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC721::balance_of(OWNER()) == 0.into(), 'Balance should be zero'); + assert(ERC721::balance_of(OWNER()) == 0, 'Balance should be zero'); assert(ERC721::supports_interface(erc721::interface::IERC721_ID), 'Missing interface ID'); assert( @@ -102,7 +99,7 @@ fn test_initialize() { assert(ERC721::name() == NAME, 'Name should be NAME'); assert(ERC721::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC721::balance_of(OWNER()) == 0.into(), 'Balance should be zero'); + assert(ERC721::balance_of(OWNER()) == 0, 'Balance should be zero'); assert(ERC721::supports_interface(erc721::interface::IERC721_ID), 'Missing interface ID'); assert( @@ -119,7 +116,7 @@ fn test_initialize() { #[available_gas(2000000)] fn test_balance_of() { setup(); - assert(ERC721::balance_of(OWNER()) == 1.into(), 'Should return balance'); + assert(ERC721::balance_of(OWNER()) == 1, 'Should return balance'); } #[test] @@ -133,7 +130,7 @@ fn test_balance_of_zero() { #[available_gas(2000000)] fn test_owner_of() { setup(); - assert(ERC721::owner_of(TOKEN_ID()) == OWNER(), 'Should return owner'); + assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Should return owner'); } #[test] @@ -155,7 +152,7 @@ fn test_token_uri_non_minted() { fn test_get_approved() { setup(); let spender = SPENDER(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; assert(ERC721::get_approved(token_id) == ZERO(), 'Should return non-approval'); ERC721::_approve(spender, token_id); @@ -173,7 +170,7 @@ fn test_get_approved_nonexistent() { #[available_gas(2000000)] fn test__exists() { let zero = ZERO(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; assert(!ERC721::_exists(token_id), 'Token should not exist'); assert(ERC721::_owners::read(token_id) == zero, 'Invalid owner'); @@ -198,8 +195,8 @@ fn test_approve_from_owner() { setup(); set_caller_address(OWNER()); - ERC721::approve(SPENDER(), TOKEN_ID()); - assert(ERC721::get_approved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); + ERC721::approve(SPENDER(), TOKEN_ID); + assert(ERC721::get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); } #[test] @@ -211,8 +208,8 @@ fn test_approve_from_operator() { ERC721::set_approval_for_all(OPERATOR(), true); set_caller_address(OPERATOR()); - ERC721::approve(SPENDER(), TOKEN_ID()); - assert(ERC721::get_approved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); + ERC721::approve(SPENDER(), TOKEN_ID); + assert(ERC721::get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); } #[test] @@ -222,7 +219,7 @@ fn test_approve_from_unauthorized() { setup(); set_caller_address(OTHER()); - ERC721::approve(SPENDER(), TOKEN_ID()); + ERC721::approve(SPENDER(), TOKEN_ID); } #[test] @@ -232,14 +229,14 @@ fn test_approve_to_owner() { setup(); set_caller_address(OWNER()); - ERC721::approve(OWNER(), TOKEN_ID()); + ERC721::approve(OWNER(), TOKEN_ID); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_approve_nonexistent() { - ERC721::approve(SPENDER(), TOKEN_ID()); + ERC721::approve(SPENDER(), TOKEN_ID); } #[test] @@ -247,8 +244,8 @@ fn test_approve_nonexistent() { fn test__approve() { setup(); - ERC721::_approve(SPENDER(), TOKEN_ID()); - assert(ERC721::get_approved(TOKEN_ID()) == SPENDER(), 'Spender not approved correctly'); + ERC721::_approve(SPENDER(), TOKEN_ID); + assert(ERC721::get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); } #[test] @@ -257,14 +254,14 @@ fn test__approve() { fn test__approve_to_owner() { setup(); - ERC721::_approve(OWNER(), TOKEN_ID()); + ERC721::_approve(OWNER(), TOKEN_ID); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test__approve_nonexistent() { - ERC721::_approve(SPENDER(), TOKEN_ID()); + ERC721::_approve(SPENDER(), TOKEN_ID); } /// @@ -334,7 +331,7 @@ fn test__set_approval_for_all_owner_equal_operator_false() { #[available_gas(2000000)] fn test_transfer_from_owner() { setup(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); // set approval to check reset @@ -353,7 +350,7 @@ fn test_transfer_from_owner() { #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_transfer_from_nonexistent() { - ERC721::transfer_from(ZERO(), RECIPIENT(), TOKEN_ID()); + ERC721::transfer_from(ZERO(), RECIPIENT(), TOKEN_ID); } #[test] @@ -363,7 +360,7 @@ fn test_transfer_from_to_zero() { setup(); set_caller_address(OWNER()); - ERC721::transfer_from(OWNER(), ZERO(), TOKEN_ID()); + ERC721::transfer_from(OWNER(), ZERO(), TOKEN_ID); } #[test] @@ -371,21 +368,21 @@ fn test_transfer_from_to_zero() { fn test_transfer_from_to_owner() { setup(); - assert(ERC721::owner_of(TOKEN_ID()) == OWNER(), 'Ownership before'); - assert(ERC721::balance_of(OWNER()) == 1.into(), 'Balance of owner before'); + assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); + assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner before'); set_caller_address(OWNER()); - ERC721::transfer_from(OWNER(), OWNER(), TOKEN_ID()); + ERC721::transfer_from(OWNER(), OWNER(), TOKEN_ID); - assert(ERC721::owner_of(TOKEN_ID()) == OWNER(), 'Ownership after'); - assert(ERC721::balance_of(OWNER()) == 1.into(), 'Balance of owner after'); + assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership after'); + assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner after'); } #[test] #[available_gas(2000000)] fn test_transfer_from_approved() { setup(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); assert_state_before_transfer(token_id, owner, recipient); @@ -403,7 +400,7 @@ fn test_transfer_from_approved() { #[available_gas(2000000)] fn test_transfer_from_approved_for_all() { setup(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); @@ -425,7 +422,7 @@ fn test_transfer_from_unauthorized() { setup(); set_caller_address(OTHER()); - ERC721::transfer_from(OWNER(), RECIPIENT(), TOKEN_ID()); + ERC721::transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); } // @@ -437,7 +434,7 @@ fn test_transfer_from_unauthorized() { fn test_safe_transfer_from_to_account() { setup(); let account = setup_account(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); assert_state_before_transfer(token_id, owner, account); @@ -453,7 +450,7 @@ fn test_safe_transfer_from_to_account() { fn test_safe_transfer_from_to_receiver() { setup(); let receiver = setup_receiver(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); assert_state_before_transfer(token_id, owner, receiver); @@ -470,7 +467,7 @@ fn test_safe_transfer_from_to_receiver() { fn test_safe_transfer_from_to_receiver_failure() { setup(); let receiver = setup_receiver(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); set_caller_address(owner); @@ -483,7 +480,7 @@ fn test_safe_transfer_from_to_receiver_failure() { fn test_safe_transfer_from_to_non_receiver() { setup(); let recipient = utils::deploy(ERC721NonReceiver::TEST_CLASS_HASH, ArrayTrait::new()); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); set_caller_address(owner); @@ -494,7 +491,7 @@ fn test_safe_transfer_from_to_non_receiver() { #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_safe_transfer_from_nonexistent() { - ERC721::safe_transfer_from(ZERO(), RECIPIENT(), TOKEN_ID(), DATA(true)); + ERC721::safe_transfer_from(ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] @@ -504,25 +501,25 @@ fn test_safe_transfer_from_to_zero() { setup(); set_caller_address(OWNER()); - ERC721::safe_transfer_from(OWNER(), ZERO(), TOKEN_ID(), DATA(true)); + ERC721::safe_transfer_from(OWNER(), ZERO(), TOKEN_ID, DATA(true)); } #[test] #[available_gas(2000000)] fn test_safe_transfer_from_to_owner() { - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = setup_receiver(); ERC721::initializer(NAME, SYMBOL); ERC721::_mint(owner, token_id); assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); - assert(ERC721::balance_of(owner) == 1.into(), 'Balance of owner before'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); set_caller_address(owner); ERC721::safe_transfer_from(owner, owner, token_id, DATA(true)); assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); - assert(ERC721::balance_of(owner) == 1.into(), 'Balance of owner after'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); } #[test] @@ -530,7 +527,7 @@ fn test_safe_transfer_from_to_owner() { fn test_safe_transfer_from_approved() { setup(); let receiver = setup_receiver(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); assert_state_before_transfer(token_id, owner, receiver); @@ -549,7 +546,7 @@ fn test_safe_transfer_from_approved() { fn test_safe_transfer_from_approved_for_all() { setup(); let receiver = setup_receiver(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); assert_state_before_transfer(token_id, owner, receiver); @@ -569,7 +566,7 @@ fn test_safe_transfer_from_approved_for_all() { fn test_safe_transfer_from_unauthorized() { setup(); set_caller_address(OTHER()); - ERC721::safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID(), DATA(true)); + ERC721::safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } // @@ -580,7 +577,7 @@ fn test_safe_transfer_from_unauthorized() { #[available_gas(2000000)] fn test__transfer() { setup(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); @@ -593,7 +590,7 @@ fn test__transfer() { #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test__transfer_nonexistent() { - ERC721::_transfer(ZERO(), RECIPIENT(), TOKEN_ID()); + ERC721::_transfer(ZERO(), RECIPIENT(), TOKEN_ID); } #[test] @@ -602,7 +599,7 @@ fn test__transfer_nonexistent() { fn test__transfer_to_zero() { setup(); - ERC721::_transfer(OWNER(), ZERO(), TOKEN_ID()); + ERC721::_transfer(OWNER(), ZERO(), TOKEN_ID); } #[test] @@ -611,7 +608,7 @@ fn test__transfer_to_zero() { fn test__transfer_from_invalid_owner() { setup(); - ERC721::_transfer(RECIPIENT(), OWNER(), TOKEN_ID()); + ERC721::_transfer(RECIPIENT(), OWNER(), TOKEN_ID); } /// @@ -622,9 +619,9 @@ fn test__transfer_from_invalid_owner() { #[available_gas(2000000)] fn test__mint() { let recipient = RECIPIENT(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; assert_state_before_mint(recipient); - ERC721::_mint(RECIPIENT(), TOKEN_ID()); + ERC721::_mint(RECIPIENT(), TOKEN_ID); assert_state_after_mint(token_id, recipient); } @@ -632,7 +629,7 @@ fn test__mint() { #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test__mint_to_zero() { - ERC721::_mint(ZERO(), TOKEN_ID()); + ERC721::_mint(ZERO(), TOKEN_ID); } #[test] @@ -641,7 +638,7 @@ fn test__mint_to_zero() { fn test__mint_already_exist() { setup(); - ERC721::_mint(RECIPIENT(), TOKEN_ID()); + ERC721::_mint(RECIPIENT(), TOKEN_ID); } /// @@ -652,7 +649,7 @@ fn test__mint_already_exist() { #[available_gas(2000000)] fn test__safe_mint_to_receiver() { let recipient = setup_receiver(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; assert_state_before_mint(recipient); ERC721::_safe_mint(recipient, token_id, DATA(true)); @@ -663,7 +660,7 @@ fn test__safe_mint_to_receiver() { #[available_gas(2000000)] fn test__safe_mint_to_account() { let account = setup_account(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; assert_state_before_mint(account); ERC721::_safe_mint(account, token_id, DATA(true)); @@ -675,7 +672,7 @@ fn test__safe_mint_to_account() { #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test__safe_mint_to_non_receiver() { let recipient = utils::deploy(ERC721NonReceiver::TEST_CLASS_HASH, ArrayTrait::new()); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; assert_state_before_mint(recipient); ERC721::_safe_mint(recipient, token_id, DATA(true)); @@ -687,7 +684,7 @@ fn test__safe_mint_to_non_receiver() { #[should_panic(expected: ('ERC721: safe mint failed', ))] fn test__safe_mint_to_receiver_failure() { let recipient = setup_receiver(); - let token_id = TOKEN_ID(); + let token_id = TOKEN_ID; assert_state_before_mint(recipient); ERC721::_safe_mint(recipient, token_id, DATA(false)); @@ -698,7 +695,7 @@ fn test__safe_mint_to_receiver_failure() { #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test__safe_mint_to_zero() { - ERC721::_safe_mint(ZERO(), TOKEN_ID(), DATA(true)); + ERC721::_safe_mint(ZERO(), TOKEN_ID, DATA(true)); } #[test] @@ -706,7 +703,7 @@ fn test__safe_mint_to_zero() { #[should_panic(expected: ('ERC721: token already minted', ))] fn test__safe_mint_already_exist() { setup(); - ERC721::_safe_mint(RECIPIENT(), TOKEN_ID(), DATA(true)); + ERC721::_safe_mint(RECIPIENT(), TOKEN_ID, DATA(true)); } /// @@ -718,24 +715,24 @@ fn test__safe_mint_already_exist() { fn test__burn() { setup(); - ERC721::_approve(OTHER(), TOKEN_ID()); + ERC721::_approve(OTHER(), TOKEN_ID); - assert(ERC721::owner_of(TOKEN_ID()) == OWNER(), 'Ownership before'); - assert(ERC721::balance_of(OWNER()) == 1.into(), 'Balance of owner before'); - assert(ERC721::get_approved(TOKEN_ID()) == OTHER(), 'Approval before'); + assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); + assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner before'); + assert(ERC721::get_approved(TOKEN_ID) == OTHER(), 'Approval before'); - ERC721::_burn(TOKEN_ID()); + ERC721::_burn(TOKEN_ID); - assert(ERC721::_owners::read(TOKEN_ID()) == ZERO(), 'Ownership after'); - assert(ERC721::balance_of(OWNER()) == 0.into(), 'Balance of owner after'); - assert(ERC721::_token_approvals::read(TOKEN_ID()) == ZERO(), 'Approval after'); + assert(ERC721::_owners::read(TOKEN_ID) == ZERO(), 'Ownership after'); + assert(ERC721::balance_of(OWNER()) == 0, 'Balance of owner after'); + assert(ERC721::_token_approvals::read(TOKEN_ID) == ZERO(), 'Approval after'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test__burn_nonexistent() { - ERC721::_burn(TOKEN_ID()); + ERC721::_burn(TOKEN_ID); } /// @@ -747,16 +744,16 @@ fn test__burn_nonexistent() { fn test__set_token_uri() { setup(); - assert(ERC721::token_uri(TOKEN_ID()) == 0, 'URI should be 0'); - ERC721::_set_token_uri(TOKEN_ID(), URI); - assert(ERC721::token_uri(TOKEN_ID()) == URI, 'URI should be set'); + assert(ERC721::token_uri(TOKEN_ID) == 0, 'URI should be 0'); + ERC721::_set_token_uri(TOKEN_ID, URI); + assert(ERC721::token_uri(TOKEN_ID) == URI, 'URI should be set'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test__set_token_uri_nonexistent() { - ERC721::_set_token_uri(TOKEN_ID(), URI); + ERC721::_set_token_uri(TOKEN_ID, URI); } // @@ -767,23 +764,23 @@ fn assert_state_before_transfer( token_id: u256, owner: ContractAddress, recipient: ContractAddress ) { assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); - assert(ERC721::balance_of(owner) == 1.into(), 'Balance of owner before'); - assert(ERC721::balance_of(recipient) == 0.into(), 'Balance of recipient before'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); + assert(ERC721::balance_of(recipient) == 0, 'Balance of recipient before'); } fn assert_state_after_transfer(token_id: u256, owner: ContractAddress, recipient: ContractAddress) { assert(ERC721::owner_of(token_id) == recipient, 'Ownership after'); - assert(ERC721::balance_of(owner) == 0.into(), 'Balance of owner after'); - assert(ERC721::balance_of(recipient) == 1.into(), 'Balance of recipient after'); + assert(ERC721::balance_of(owner) == 0, 'Balance of owner after'); + assert(ERC721::balance_of(recipient) == 1, 'Balance of recipient after'); assert(ERC721::get_approved(token_id) == ZERO(), 'Approval not implicitly reset'); } fn assert_state_before_mint(recipient: ContractAddress) { - assert(ERC721::balance_of(recipient) == 0.into(), 'Balance of recipient before'); + assert(ERC721::balance_of(recipient) == 0, 'Balance of recipient before'); } fn assert_state_after_mint(token_id: u256, recipient: ContractAddress) { assert(ERC721::owner_of(token_id) == recipient, 'Ownership after'); - assert(ERC721::balance_of(recipient) == 1.into(), 'Balance of recipient after'); + assert(ERC721::balance_of(recipient) == 1, 'Balance of recipient after'); assert(ERC721::get_approved(token_id) == ZERO(), 'Approval implicitly set'); } diff --git a/src/openzeppelin/tests/utils.cairo b/src/openzeppelin/tests/utils.cairo index e0eaea264..d3b720cce 100644 --- a/src/openzeppelin/tests/utils.cairo +++ b/src/openzeppelin/tests/utils.cairo @@ -1,12 +1,9 @@ +use array::ArrayTrait; use core::result::ResultTrait; use option::OptionTrait; -use array::ArrayTrait; -use traits::TryInto; -use traits::Into; - -use openzeppelin::utils::BoolIntoFelt252; use starknet::class_hash::Felt252TryIntoClassHash; use starknet::ContractAddress; +use traits::TryInto; fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { let (address, _) = starknet::deploy_syscall( diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo index eca9933d7..1a728ef23 100644 --- a/src/openzeppelin/token/erc20.cairo +++ b/src/openzeppelin/token/erc20.cairo @@ -1,233 +1,5 @@ -use starknet::ContractAddress; +mod erc20; +use erc20::{ERC20, ERC20ABIDispatcher, ERC20ABIDispatcherTrait}; -#[abi] -trait IERC20 { - #[view] - fn name() -> felt252; - #[view] - fn symbol() -> felt252; - #[view] - fn decimals() -> u8; - #[view] - fn total_supply() -> u256; - #[view] - fn balance_of(account: ContractAddress) -> u256; - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; - #[external] - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool; - #[external] - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool; -} - -#[contract] -mod ERC20 { - use super::IERC20; - use integer::BoundedInt; - use starknet::ContractAddress; - use starknet::get_caller_address; - use zeroable::Zeroable; - - struct Storage { - _name: felt252, - _symbol: felt252, - _total_supply: u256, - _balances: LegacyMap, - _allowances: LegacyMap<(ContractAddress, ContractAddress), u256>, - } - - #[event] - fn Transfer(from: ContractAddress, to: ContractAddress, value: u256) {} - - #[event] - fn Approval(owner: ContractAddress, spender: ContractAddress, value: u256) {} - - impl ERC20 of IERC20 { - fn name() -> felt252 { - _name::read() - } - - fn symbol() -> felt252 { - _symbol::read() - } - - fn decimals() -> u8 { - 18_u8 - } - - fn total_supply() -> u256 { - _total_supply::read() - } - - fn balance_of(account: ContractAddress) -> u256 { - _balances::read(account) - } - - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - _allowances::read((owner, spender)) - } - - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - let sender = get_caller_address(); - _transfer(sender, recipient, amount); - true - } - - fn transfer_from( - sender: ContractAddress, recipient: ContractAddress, amount: u256 - ) -> bool { - let caller = get_caller_address(); - _spend_allowance(sender, caller, amount); - _transfer(sender, recipient, amount); - true - } - - fn approve(spender: ContractAddress, amount: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, amount); - true - } - - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - _increase_allowance(spender, added_value) - } - - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - _decrease_allowance(spender, subtracted_value) - } - } - - #[constructor] - fn constructor( - name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress - ) { - initializer(name, symbol); - _mint(recipient, initial_supply); - } - - #[view] - fn name() -> felt252 { - ERC20::name() - } - - #[view] - fn symbol() -> felt252 { - ERC20::symbol() - } - - #[view] - fn decimals() -> u8 { - ERC20::decimals() - } - - #[view] - fn total_supply() -> u256 { - ERC20::total_supply() - } - - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC20::balance_of(account) - } - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20::allowance(owner, spender) - } - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20::transfer(recipient, amount) - } - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20::transfer_from(sender, recipient, amount) - } - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20::approve(spender, amount) - } - - #[external] - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - ERC20::increase_allowance(spender, added_value) - } - - #[external] - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - ERC20::decrease_allowance(spender, subtracted_value) - } - - /// - /// Internals - /// - - #[internal] - fn initializer(name_: felt252, symbol_: felt252) { - _name::write(name_); - _symbol::write(symbol_); - } - - #[internal] - fn _increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, _allowances::read((caller, spender)) + added_value); - true - } - - #[internal] - fn _decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, _allowances::read((caller, spender)) - subtracted_value); - true - } - - #[internal] - fn _mint(recipient: ContractAddress, amount: u256) { - assert(!recipient.is_zero(), 'ERC20: mint to 0'); - _total_supply::write(_total_supply::read() + amount); - _balances::write(recipient, _balances::read(recipient) + amount); - Transfer(Zeroable::zero(), recipient, amount); - } - - #[internal] - fn _burn(account: ContractAddress, amount: u256) { - assert(!account.is_zero(), 'ERC20: burn from 0'); - _total_supply::write(_total_supply::read() - amount); - _balances::write(account, _balances::read(account) - amount); - Transfer(account, Zeroable::zero(), amount); - } - - #[internal] - fn _approve(owner: ContractAddress, spender: ContractAddress, amount: u256) { - assert(!owner.is_zero(), 'ERC20: approve from 0'); - assert(!spender.is_zero(), 'ERC20: approve to 0'); - _allowances::write((owner, spender), amount); - Approval(owner, spender, amount); - } - - #[internal] - fn _transfer(sender: ContractAddress, recipient: ContractAddress, amount: u256) { - assert(!sender.is_zero(), 'ERC20: transfer from 0'); - assert(!recipient.is_zero(), 'ERC20: transfer to 0'); - _balances::write(sender, _balances::read(sender) - amount); - _balances::write(recipient, _balances::read(recipient) + amount); - Transfer(sender, recipient, amount); - } - - #[internal] - fn _spend_allowance(owner: ContractAddress, spender: ContractAddress, amount: u256) { - let current_allowance = _allowances::read((owner, spender)); - if current_allowance != BoundedInt::max() { - _approve(owner, spender, current_allowance - amount); - } - } -} +mod interface; +mod dual20; diff --git a/src/openzeppelin/token/erc20/dual20.cairo b/src/openzeppelin/token/erc20/dual20.cairo new file mode 100644 index 000000000..9e0ece69e --- /dev/null +++ b/src/openzeppelin/token/erc20/dual20.cairo @@ -0,0 +1,138 @@ +use array::ArrayTrait; +use array::SpanTrait; +use core::result::ResultTrait; +use integer::Felt252TryIntoU8; +use option::OptionTrait; +use starknet::call_contract_syscall; +use starknet::ContractAddress; +use starknet::Felt252TryIntoContractAddress; +use starknet::SyscallResultTrait; +use traits::Into; +use traits::TryInto; + +use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::Felt252TryIntoBool; +use openzeppelin::utils::BoolIntoFelt252; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; + +#[derive(Copy, Drop)] +struct DualERC20 { + contract_address: ContractAddress +} + +trait DualERC20Trait { + fn name(self: @DualERC20) -> felt252; + fn symbol(self: @DualERC20) -> felt252; + fn decimals(self: @DualERC20) -> u8; + fn total_supply(self: @DualERC20) -> u256; + fn balance_of(self: @DualERC20, account: ContractAddress) -> u256; + fn allowance(self: @DualERC20, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(self: @DualERC20, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + self: @DualERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(self: @DualERC20, spender: ContractAddress, amount: u256) -> bool; +} + +impl DualERC20Impl of DualERC20Trait { + fn name(self: @DualERC20) -> felt252 { + let args = ArrayTrait::new(); + + *call_contract_syscall(*self.contract_address, selectors::name, args.span()) + .unwrap_syscall() + .at(0) + } + + fn symbol(self: @DualERC20) -> felt252 { + let args = ArrayTrait::new(); + + *call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) + .unwrap_syscall() + .at(0) + } + + fn decimals(self: @DualERC20) -> u8 { + let args = ArrayTrait::new(); + + (*call_contract_syscall(*self.contract_address, selectors::decimals, args.span()) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } + + fn total_supply(self: @DualERC20) -> u256 { + let mut args = ArrayTrait::new(); + let res = try_selector_with_fallback( + *self.contract_address, selectors::total_supply, selectors::totalSupply, args.span() + ) + .unwrap_syscall(); + + u256 { low: (*res.at(0)).try_into().unwrap(), high: (*res.at(1)).try_into().unwrap(), } + } + + fn balance_of(self: @DualERC20, account: ContractAddress) -> u256 { + let mut args = ArrayTrait::new(); + args.append_serde(account); + + let res = try_selector_with_fallback( + *self.contract_address, selectors::balance_of, selectors::balanceOf, args.span() + ) + .unwrap_syscall(); + + u256 { low: (*res.at(0)).try_into().unwrap(), high: (*res.at(1)).try_into().unwrap(), } + } + + fn allowance(self: @DualERC20, owner: ContractAddress, spender: ContractAddress) -> u256 { + let mut args = ArrayTrait::new(); + args.append_serde(owner); + args.append_serde(spender); + + let res = call_contract_syscall(*self.contract_address, selectors::allowance, args.span()) + .unwrap_syscall(); + + u256 { low: (*res.at(0)).try_into().unwrap(), high: (*res.at(1)).try_into().unwrap(), } + } + + fn transfer(self: @DualERC20, recipient: ContractAddress, amount: u256) -> bool { + let mut args = ArrayTrait::new(); + args.append_serde(recipient); + args.append_serde(amount); + + (*call_contract_syscall(*self.contract_address, selectors::transfer, args.span()) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } + + fn transfer_from( + self: @DualERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool { + let mut args = ArrayTrait::new(); + args.append_serde(sender); + args.append_serde(recipient); + args.append_serde(amount); + + (*try_selector_with_fallback( + *self.contract_address, selectors::transfer_from, selectors::transferFrom, args.span() + ) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } + + fn approve(self: @DualERC20, spender: ContractAddress, amount: u256) -> bool { + let mut args = ArrayTrait::new(); + args.append_serde(spender); + args.append_serde(amount); + + (*call_contract_syscall(*self.contract_address, selectors::approve, args.span()) + .unwrap_syscall() + .at(0)) + .try_into() + .unwrap() + } +} diff --git a/src/openzeppelin/token/erc20/erc20.cairo b/src/openzeppelin/token/erc20/erc20.cairo new file mode 100644 index 000000000..3342742ba --- /dev/null +++ b/src/openzeppelin/token/erc20/erc20.cairo @@ -0,0 +1,314 @@ +use starknet::ContractAddress; + +#[abi] +trait ERC20ABI { + #[view] + fn name() -> felt252; + #[view] + fn symbol() -> felt252; + #[view] + fn decimals() -> u8; + #[view] + fn total_supply() -> u256; + #[view] + fn balance_of(account: ContractAddress) -> u256; + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool; + #[external] + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool; + #[external] + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool; + #[external] + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool; +} + +#[abi] +trait ERC20CamelABI { + #[view] + fn name() -> felt252; + #[view] + fn symbol() -> felt252; + #[view] + fn decimals() -> u8; + #[view] + fn totalSupply() -> u256; + #[view] + fn balanceOf(account: ContractAddress) -> u256; + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool; + #[external] + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool; + #[external] + fn increaseAllowance(spender: ContractAddress, addedValue: u256) -> bool; + #[external] + fn decreaseAllowance(spender: ContractAddress, subtractedValue: u256) -> bool; +} + +#[contract] +mod ERC20 { + use openzeppelin::token::erc20::interface::{IERC20, IERC20Camel}; + use integer::BoundedInt; + use starknet::ContractAddress; + use starknet::get_caller_address; + use zeroable::Zeroable; + + struct Storage { + _name: felt252, + _symbol: felt252, + _total_supply: u256, + _balances: LegacyMap, + _allowances: LegacyMap<(ContractAddress, ContractAddress), u256>, + } + + #[event] + fn Transfer(from: ContractAddress, to: ContractAddress, value: u256) {} + + #[event] + fn Approval(owner: ContractAddress, spender: ContractAddress, value: u256) {} + + impl ERC20Impl of IERC20 { + fn name() -> felt252 { + _name::read() + } + + fn symbol() -> felt252 { + _symbol::read() + } + + fn decimals() -> u8 { + 18_u8 + } + + fn total_supply() -> u256 { + _total_supply::read() + } + + fn balance_of(account: ContractAddress) -> u256 { + _balances::read(account) + } + + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + _allowances::read((owner, spender)) + } + + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + let sender = get_caller_address(); + _transfer(sender, recipient, amount); + true + } + + fn transfer_from( + sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool { + let caller = get_caller_address(); + _spend_allowance(sender, caller, amount); + _transfer(sender, recipient, amount); + true + } + + fn approve(spender: ContractAddress, amount: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, amount); + true + } + } + + impl ERC20CamelImpl of IERC20Camel { + fn name() -> felt252 { + ERC20Impl::name() + } + + fn symbol() -> felt252 { + ERC20Impl::symbol() + } + + fn decimals() -> u8 { + ERC20Impl::decimals() + } + + fn totalSupply() -> u256 { + ERC20Impl::total_supply() + } + + fn balanceOf(account: ContractAddress) -> u256 { + ERC20Impl::balance_of(account) + } + + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + ERC20Impl::allowance(owner, spender) + } + + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + ERC20Impl::transfer(recipient, amount) + } + + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20Impl::transfer_from(sender, recipient, amount) + } + + fn approve(spender: ContractAddress, amount: u256) -> bool { + ERC20Impl::approve(spender, amount) + } + } + + #[constructor] + fn constructor( + name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress + ) { + initializer(name, symbol); + _mint(recipient, initial_supply); + } + + #[view] + fn name() -> felt252 { + ERC20Impl::name() + } + + #[view] + fn symbol() -> felt252 { + ERC20Impl::symbol() + } + + #[view] + fn decimals() -> u8 { + ERC20Impl::decimals() + } + + #[view] + fn total_supply() -> u256 { + ERC20Impl::total_supply() + } + + #[view] + fn totalSupply() -> u256 { + ERC20CamelImpl::totalSupply() + } + + #[view] + fn balance_of(account: ContractAddress) -> u256 { + ERC20Impl::balance_of(account) + } + + #[view] + fn balanceOf(account: ContractAddress) -> u256 { + ERC20CamelImpl::balanceOf(account) + } + + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + ERC20Impl::allowance(owner, spender) + } + + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool { + ERC20Impl::transfer(recipient, amount) + } + + #[external] + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20Impl::transfer_from(sender, recipient, amount) + } + + #[external] + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { + ERC20CamelImpl::transferFrom(sender, recipient, amount) + } + + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool { + ERC20Impl::approve(spender, amount) + } + + #[external] + fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { + _increase_allowance(spender, added_value) + } + + #[external] + fn increaseAllowance(spender: ContractAddress, addedValue: u256) -> bool { + increase_allowance(spender, addedValue) + } + + #[external] + fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { + _decrease_allowance(spender, subtracted_value) + } + + #[external] + fn decreaseAllowance(spender: ContractAddress, subtractedValue: u256) -> bool { + decrease_allowance(spender, subtractedValue) + } + + /// + /// Internals + /// + + #[internal] + fn initializer(name_: felt252, symbol_: felt252) { + _name::write(name_); + _symbol::write(symbol_); + } + + #[internal] + fn _increase_allowance(spender: ContractAddress, added_value: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, _allowances::read((caller, spender)) + added_value); + true + } + + #[internal] + fn _decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { + let caller = get_caller_address(); + _approve(caller, spender, _allowances::read((caller, spender)) - subtracted_value); + true + } + + #[internal] + fn _mint(recipient: ContractAddress, amount: u256) { + assert(!recipient.is_zero(), 'ERC20: mint to 0'); + _total_supply::write(_total_supply::read() + amount); + _balances::write(recipient, _balances::read(recipient) + amount); + Transfer(Zeroable::zero(), recipient, amount); + } + + #[internal] + fn _burn(account: ContractAddress, amount: u256) { + assert(!account.is_zero(), 'ERC20: burn from 0'); + _total_supply::write(_total_supply::read() - amount); + _balances::write(account, _balances::read(account) - amount); + Transfer(account, Zeroable::zero(), amount); + } + + #[internal] + fn _approve(owner: ContractAddress, spender: ContractAddress, amount: u256) { + assert(!owner.is_zero(), 'ERC20: approve from 0'); + assert(!spender.is_zero(), 'ERC20: approve to 0'); + _allowances::write((owner, spender), amount); + Approval(owner, spender, amount); + } + + #[internal] + fn _transfer(sender: ContractAddress, recipient: ContractAddress, amount: u256) { + assert(!sender.is_zero(), 'ERC20: transfer from 0'); + assert(!recipient.is_zero(), 'ERC20: transfer to 0'); + _balances::write(sender, _balances::read(sender) - amount); + _balances::write(recipient, _balances::read(recipient) + amount); + Transfer(sender, recipient, amount); + } + + #[internal] + fn _spend_allowance(owner: ContractAddress, spender: ContractAddress, amount: u256) { + let current_allowance = _allowances::read((owner, spender)); + if current_allowance != BoundedInt::max() { + _approve(owner, spender, current_allowance - amount); + } + } +} diff --git a/src/openzeppelin/token/erc20/interface.cairo b/src/openzeppelin/token/erc20/interface.cairo new file mode 100644 index 000000000..26b00e63b --- /dev/null +++ b/src/openzeppelin/token/erc20/interface.cairo @@ -0,0 +1,45 @@ +use starknet::ContractAddress; + +#[abi] +trait IERC20 { + #[view] + fn name() -> felt252; + #[view] + fn symbol() -> felt252; + #[view] + fn decimals() -> u8; + #[view] + fn total_supply() -> u256; + #[view] + fn balance_of(account: ContractAddress) -> u256; + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool; + #[external] + fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool; +} + +#[abi] +trait IERC20Camel { + #[view] + fn name() -> felt252; + #[view] + fn symbol() -> felt252; + #[view] + fn decimals() -> u8; + #[view] + fn totalSupply() -> u256; + #[view] + fn balanceOf(account: ContractAddress) -> u256; + #[view] + fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; + #[external] + fn transfer(recipient: ContractAddress, amount: u256) -> bool; + #[external] + fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; + #[external] + fn approve(spender: ContractAddress, amount: u256) -> bool; +} diff --git a/src/openzeppelin/token/erc721/dual721.cairo b/src/openzeppelin/token/erc721/dual721.cairo index e71b08874..b1d022686 100644 --- a/src/openzeppelin/token/erc721/dual721.cairo +++ b/src/openzeppelin/token/erc721/dual721.cairo @@ -12,6 +12,7 @@ use openzeppelin::utils::try_selector_with_fallback; use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::BoolIntoFelt252; use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; #[derive(Copy, Drop)] struct DualCaseERC721 { @@ -44,21 +45,24 @@ trait DualCaseERC721Trait { impl DualCaseERC721Impl of DualCaseERC721Trait { fn name(self: @DualCaseERC721) -> felt252 { - *call_contract_syscall(*self.contract_address, selectors::name, ArrayTrait::new().span()) + let args = ArrayTrait::new(); + + *call_contract_syscall(*self.contract_address, selectors::name, args.span()) .unwrap_syscall() .at(0) } fn symbol(self: @DualCaseERC721) -> felt252 { - *call_contract_syscall(*self.contract_address, selectors::symbol, ArrayTrait::new().span()) + let args = ArrayTrait::new(); + + *call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) .unwrap_syscall() .at(0) } fn token_uri(self: @DualCaseERC721, token_id: u256) -> felt252 { let mut args = ArrayTrait::new(); - args.append(token_id.low.into()); - args.append(token_id.high.into()); + args.append_serde(token_id); *try_selector_with_fallback( *self.contract_address, selectors::token_uri, selectors::tokenUri, args.span() @@ -69,7 +73,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { fn balance_of(self: @DualCaseERC721, account: ContractAddress) -> u256 { let mut args = ArrayTrait::new(); - args.append(account.into()); + args.append_serde(account); let res = try_selector_with_fallback( *self.contract_address, selectors::balance_of, selectors::balanceOf, args.span() @@ -81,8 +85,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { fn owner_of(self: @DualCaseERC721, token_id: u256) -> ContractAddress { let mut args = ArrayTrait::new(); - args.append(token_id.low.into()); - args.append(token_id.high.into()); + args.append_serde(token_id); (*try_selector_with_fallback( *self.contract_address, selectors::owner_of, selectors::ownerOf, args.span() @@ -95,8 +98,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { fn get_approved(self: @DualCaseERC721, token_id: u256) -> ContractAddress { let mut args = ArrayTrait::new(); - args.append(token_id.low.into()); - args.append(token_id.high.into()); + args.append_serde(token_id); (*try_selector_with_fallback( *self.contract_address, selectors::get_approved, selectors::getApproved, args.span() @@ -111,8 +113,8 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { self: @DualCaseERC721, owner: ContractAddress, operator: ContractAddress ) -> bool { let mut args = ArrayTrait::new(); - args.append(owner.into()); - args.append(operator.into()); + args.append_serde(owner); + args.append_serde(operator); (*try_selector_with_fallback( *self.contract_address, @@ -128,17 +130,16 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { fn approve(self: @DualCaseERC721, to: ContractAddress, token_id: u256) { let mut args = ArrayTrait::new(); - args.append(to.into()); - args.append(token_id.low.into()); - args.append(token_id.high.into()); + args.append_serde(to); + args.append_serde(token_id); call_contract_syscall(*self.contract_address, selectors::approve, args.span()) .unwrap_syscall(); } fn set_approval_for_all(self: @DualCaseERC721, operator: ContractAddress, approved: bool) { let mut args = ArrayTrait::new(); - args.append(operator.into()); - args.append(approved.into()); + args.append_serde(operator); + args.append_serde(approved); try_selector_with_fallback( *self.contract_address, @@ -153,10 +154,9 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { self: @DualCaseERC721, from: ContractAddress, to: ContractAddress, token_id: u256 ) { let mut args = ArrayTrait::new(); - args.append(from.into()); - args.append(to.into()); - args.append(token_id.low.into()); - args.append(token_id.high.into()); + args.append_serde(from); + args.append_serde(to); + args.append_serde(token_id); try_selector_with_fallback( *self.contract_address, selectors::transfer_from, selectors::transferFrom, args.span() @@ -172,20 +172,10 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { mut data: Span ) { let mut args = ArrayTrait::new(); - args.append(from.into()); - args.append(to.into()); - args.append(token_id.low.into()); - args.append(token_id.high.into()); - args.append(data.len().into()); - - loop { - match data.pop_front() { - Option::Some(x) => args.append(*x), - Option::None(_) => { - break (); - } - }; - }; + args.append_serde(from); + args.append_serde(to); + args.append_serde(token_id); + args.append_serde(data); try_selector_with_fallback( *self.contract_address, diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/openzeppelin/token/erc721/erc721.cairo index 7c1345447..6aaf0bc54 100644 --- a/src/openzeppelin/token/erc721/erc721.cairo +++ b/src/openzeppelin/token/erc721/erc721.cairo @@ -370,7 +370,7 @@ mod ERC721 { assert(!_exists(token_id), 'ERC721: token already minted'); // Update balances - _balances::write(to, _balances::read(to) + 1.into()); + _balances::write(to, _balances::read(to) + 1); // Update token_id owner _owners::write(token_id, to); @@ -389,8 +389,8 @@ mod ERC721 { _token_approvals::write(token_id, Zeroable::zero()); // Update balances - _balances::write(from, _balances::read(from) - 1.into()); - _balances::write(to, _balances::read(to) + 1.into()); + _balances::write(from, _balances::read(from) - 1); + _balances::write(to, _balances::read(to) + 1); // Update token_id owner _owners::write(token_id, to); @@ -407,7 +407,7 @@ mod ERC721 { _token_approvals::write(token_id, Zeroable::zero()); // Update balances - _balances::write(owner, _balances::read(owner) - 1.into()); + _balances::write(owner, _balances::read(owner) - 1); // Delete owner _owners::write(token_id, Zeroable::zero()); diff --git a/src/openzeppelin/utils/selectors.cairo b/src/openzeppelin/utils/selectors.cairo index 33844ef8e..8c17091ce 100644 --- a/src/openzeppelin/utils/selectors.cairo +++ b/src/openzeppelin/utils/selectors.cairo @@ -52,3 +52,15 @@ const transferFrom: felt252 = 0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9 const safe_transfer_from: felt252 = 0x16f0218b33b5cf273196787d7cf139a9ad13d58e6674dcdce722b3bf8389863; const safeTransferFrom: felt252 = 0x19d59d013d4aa1a8b1ce4c8299086f070733b453c02d0dc46e735edc04d6444; + +// +// ERC20 +// + +// The following ERC20 selectors are already defined in ERC721 above: +// name, symbol, balance_of, balanceOf, transfer_from, transferFrom, approve +const decimals: felt252 = 0x4c4fb1ab068f6039d5780c68dd0fa2f8742cceb3426d19667778ca7f3518a9; +const total_supply: felt252 = 0x1557182e4359a1f0c6301278e8f5b35a776ab58d39892581e357578fb287836; +const totalSupply: felt252 = 0x80aa9fdbfaf9615e4afc7f5f722e265daca5ccc655360fa5ccacf9c267936d; +const allowance: felt252 = 0x1e888a1026b19c8c0b57c72d63ed1737106aa10034105b980ba117bd0c29fe1; +const transfer: felt252 = 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e; From 6a1f72910ef24d1bde896bd8572596322ed0757f Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 6 Jul 2023 08:46:01 -0400 Subject: [PATCH 058/124] Add `UnwrapAndCast` trait (#644) * add unwrap_and_cast trait and impls * use unwrap_and_cast * tidy up code * add UnwrapAndCastU8 impl * reorder use clauses * use unwrap_and_cast on view fns --- .../accesscontrol/dual_accesscontrol.cairo | 8 ++- .../access/ownable/dual_ownable.cairo | 10 ++-- src/openzeppelin/token/erc20/dual20.cairo | 49 ++++++------------ src/openzeppelin/token/erc721/dual721.cairo | 28 ++++------- src/openzeppelin/utils.cairo | 50 ++++++++++++++++--- 5 files changed, 75 insertions(+), 70 deletions(-) diff --git a/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo b/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo index 3e9c0151a..032c4f452 100644 --- a/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo +++ b/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo @@ -11,6 +11,7 @@ use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::UnwrapAndCast; #[derive(Copy, Drop)] struct DualCaseAccessControl { @@ -31,13 +32,10 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { args.append_serde(role); args.append_serde(account); - (*try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::has_role, selectors::hasRole, args.span() ) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + .unwrap_and_cast() } fn get_role_admin(self: @DualCaseAccessControl, role: felt252) -> felt252 { diff --git a/src/openzeppelin/access/ownable/dual_ownable.cairo b/src/openzeppelin/access/ownable/dual_ownable.cairo index fc7381f80..583d96ffe 100644 --- a/src/openzeppelin/access/ownable/dual_ownable.cairo +++ b/src/openzeppelin/access/ownable/dual_ownable.cairo @@ -8,10 +8,11 @@ use starknet::SyscallResultTrait; use starknet::call_contract_syscall; use traits::TryInto; -use openzeppelin::utils::try_selector_with_fallback; use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::UnwrapAndCast; #[derive(Copy, Drop)] struct DualCaseOwnable { @@ -28,11 +29,8 @@ impl DualCaseOwnableImpl of DualCaseOwnableTrait { fn owner(self: @DualCaseOwnable) -> ContractAddress { let args = ArrayTrait::new(); - (*call_contract_syscall(*self.contract_address, selectors::owner, args.span()) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + call_contract_syscall(*self.contract_address, selectors::owner, args.span()) + .unwrap_and_cast() } fn transfer_ownership(self: @DualCaseOwnable, new_owner: ContractAddress) { diff --git a/src/openzeppelin/token/erc20/dual20.cairo b/src/openzeppelin/token/erc20/dual20.cairo index 9e0ece69e..2d9028f70 100644 --- a/src/openzeppelin/token/erc20/dual20.cairo +++ b/src/openzeppelin/token/erc20/dual20.cairo @@ -7,7 +7,6 @@ use starknet::call_contract_syscall; use starknet::ContractAddress; use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResultTrait; -use traits::Into; use traits::TryInto; use openzeppelin::utils::try_selector_with_fallback; @@ -15,6 +14,7 @@ use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::BoolIntoFelt252; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::UnwrapAndCast; #[derive(Copy, Drop)] struct DualERC20 { @@ -55,33 +55,27 @@ impl DualERC20Impl of DualERC20Trait { fn decimals(self: @DualERC20) -> u8 { let args = ArrayTrait::new(); - (*call_contract_syscall(*self.contract_address, selectors::decimals, args.span()) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + call_contract_syscall(*self.contract_address, selectors::decimals, args.span()) + .unwrap_and_cast() } fn total_supply(self: @DualERC20) -> u256 { let mut args = ArrayTrait::new(); - let res = try_selector_with_fallback( + + try_selector_with_fallback( *self.contract_address, selectors::total_supply, selectors::totalSupply, args.span() ) - .unwrap_syscall(); - - u256 { low: (*res.at(0)).try_into().unwrap(), high: (*res.at(1)).try_into().unwrap(), } + .unwrap_and_cast() } fn balance_of(self: @DualERC20, account: ContractAddress) -> u256 { let mut args = ArrayTrait::new(); args.append_serde(account); - let res = try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::balance_of, selectors::balanceOf, args.span() ) - .unwrap_syscall(); - - u256 { low: (*res.at(0)).try_into().unwrap(), high: (*res.at(1)).try_into().unwrap(), } + .unwrap_and_cast() } fn allowance(self: @DualERC20, owner: ContractAddress, spender: ContractAddress) -> u256 { @@ -89,10 +83,8 @@ impl DualERC20Impl of DualERC20Trait { args.append_serde(owner); args.append_serde(spender); - let res = call_contract_syscall(*self.contract_address, selectors::allowance, args.span()) - .unwrap_syscall(); - - u256 { low: (*res.at(0)).try_into().unwrap(), high: (*res.at(1)).try_into().unwrap(), } + call_contract_syscall(*self.contract_address, selectors::allowance, args.span()) + .unwrap_and_cast() } fn transfer(self: @DualERC20, recipient: ContractAddress, amount: u256) -> bool { @@ -100,11 +92,8 @@ impl DualERC20Impl of DualERC20Trait { args.append_serde(recipient); args.append_serde(amount); - (*call_contract_syscall(*self.contract_address, selectors::transfer, args.span()) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + call_contract_syscall(*self.contract_address, selectors::transfer, args.span()) + .unwrap_and_cast() } fn transfer_from( @@ -115,13 +104,10 @@ impl DualERC20Impl of DualERC20Trait { args.append_serde(recipient); args.append_serde(amount); - (*try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::transfer_from, selectors::transferFrom, args.span() ) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + .unwrap_and_cast() } fn approve(self: @DualERC20, spender: ContractAddress, amount: u256) -> bool { @@ -129,10 +115,7 @@ impl DualERC20Impl of DualERC20Trait { args.append_serde(spender); args.append_serde(amount); - (*call_contract_syscall(*self.contract_address, selectors::approve, args.span()) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + call_contract_syscall(*self.contract_address, selectors::approve, args.span()) + .unwrap_and_cast() } } diff --git a/src/openzeppelin/token/erc721/dual721.cairo b/src/openzeppelin/token/erc721/dual721.cairo index b1d022686..35389f357 100644 --- a/src/openzeppelin/token/erc721/dual721.cairo +++ b/src/openzeppelin/token/erc721/dual721.cairo @@ -12,6 +12,7 @@ use openzeppelin::utils::try_selector_with_fallback; use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::BoolIntoFelt252; use openzeppelin::utils::selectors; +use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::serde::SerializedAppend; #[derive(Copy, Drop)] @@ -75,38 +76,30 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { let mut args = ArrayTrait::new(); args.append_serde(account); - let res = try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::balance_of, selectors::balanceOf, args.span() ) - .unwrap_syscall(); - - u256 { low: (*res.at(0)).try_into().unwrap(), high: (*res.at(1)).try_into().unwrap(), } + .unwrap_and_cast() } fn owner_of(self: @DualCaseERC721, token_id: u256) -> ContractAddress { let mut args = ArrayTrait::new(); args.append_serde(token_id); - (*try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::owner_of, selectors::ownerOf, args.span() ) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + .unwrap_and_cast() } fn get_approved(self: @DualCaseERC721, token_id: u256) -> ContractAddress { let mut args = ArrayTrait::new(); args.append_serde(token_id); - (*try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::get_approved, selectors::getApproved, args.span() ) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + .unwrap_and_cast() } fn is_approved_for_all( @@ -116,16 +109,13 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { args.append_serde(owner); args.append_serde(operator); - (*try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::is_approved_for_all, selectors::isApprovedForAll, args.span() ) - .unwrap_syscall() - .at(0)) - .try_into() - .unwrap() + .unwrap_and_cast() } fn approve(self: @DualCaseERC721, to: ContractAddress, token_id: u256) { diff --git a/src/openzeppelin/utils.cairo b/src/openzeppelin/utils.cairo index 433693466..28e9ac044 100644 --- a/src/openzeppelin/utils.cairo +++ b/src/openzeppelin/utils.cairo @@ -1,14 +1,18 @@ -use starknet::call_contract_syscall; -use starknet::ContractAddress; -use starknet::SyscallResult; -use option::OptionTrait; -use array::ArrayTrait; -use array::SpanTrait; -use box::BoxTrait; mod constants; mod selectors; mod serde; +use array::ArrayTrait; +use array::SpanTrait; +use box::BoxTrait; +use option::OptionTrait; +use starknet::call_contract_syscall; +use starknet::ContractAddress; +use starknet::Felt252TryIntoContractAddress; +use starknet::SyscallResult; +use starknet::SyscallResultTrait; +use traits::TryInto; + fn try_selector_with_fallback( target: ContractAddress, snake_selector: felt252, camel_selector: felt252, args: Span ) -> SyscallResult> { @@ -57,3 +61,35 @@ fn check_gas() { }, } } + +trait UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> T; +} + +impl UnwrapAndCastBool of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> bool { + (*self.unwrap_syscall().at(0)).try_into().unwrap() + } +} + +impl UnwrapAndCastContractAddress of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> ContractAddress { + (*self.unwrap_syscall().at(0)).try_into().unwrap() + } +} + +impl UnwrapAndCastU8 of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> u8 { + (*self.unwrap_syscall().at(0)).try_into().unwrap() + } +} + +impl UnwrapAndCastU256 of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> u256 { + let unwrapped = self.unwrap_syscall(); + u256 { + low: (*unwrapped.at(0)).try_into().unwrap(), + high: (*unwrapped.at(1)).try_into().unwrap(), + } + } +} From bbcb8758b6b5c2a9d66b5c7efbdb43ccc0a40f5b Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Sat, 8 Jul 2023 14:26:09 -0400 Subject: [PATCH 059/124] add test_dual721 mod (#648) --- src/openzeppelin/tests/token.cairo | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openzeppelin/tests/token.cairo b/src/openzeppelin/tests/token.cairo index a072d4a08..1020d4439 100644 --- a/src/openzeppelin/tests/token.cairo +++ b/src/openzeppelin/tests/token.cairo @@ -1,3 +1,4 @@ mod test_dual20; +mod test_dual721; mod test_erc20; mod test_erc721; From 5a27baa9918a4e2e4de3eb3eeee043104958310e Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 10 Jul 2023 14:30:01 +0200 Subject: [PATCH 060/124] Update account interface (#646) * feat: update interface and ids * refactor: format files * feat: update from reviews * Update src/openzeppelin/account/account.cairo Co-authored-by: Andrew Fleming --------- Co-authored-by: Andrew Fleming --- src/openzeppelin/account/account.cairo | 41 ++++++++++++---------- src/openzeppelin/account/interface.cairo | 11 +++--- src/openzeppelin/tests/test_account.cairo | 7 ++-- src/openzeppelin/token/erc721/erc721.cairo | 2 +- src/openzeppelin/utils/constants.cairo | 5 +-- 5 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/openzeppelin/account/account.cairo b/src/openzeppelin/account/account.cairo index 4061052b0..1823dfac7 100644 --- a/src/openzeppelin/account/account.cairo +++ b/src/openzeppelin/account/account.cairo @@ -29,7 +29,7 @@ trait AccountABI { #[view] fn get_public_key() -> felt252; #[view] - fn is_valid_signature(message: felt252, signature: Array) -> u32; + fn is_valid_signature(message: felt252, signature: Array) -> felt252; #[view] fn supports_interface(interface_id: felt252) -> bool; } @@ -47,9 +47,10 @@ mod Account { use starknet::get_contract_address; use zeroable::Zeroable; - use openzeppelin::account::interface::IAccount; - use openzeppelin::account::interface::IACCOUNT_ID; - use openzeppelin::account::interface::ERC1271_VALIDATED; + use openzeppelin::account::interface::IDeclarer; + use openzeppelin::account::interface::ISRC6; + use openzeppelin::account::interface::ISRC6_ID; + use openzeppelin::introspection::src5::ISRC5; use openzeppelin::introspection::src5::SRC5; use super::Call; @@ -66,7 +67,7 @@ mod Account { initializer(_public_key); } - impl AccountImpl of IAccount { + impl SRC6Impl of ISRC6 { fn __execute__(mut calls: Array) -> Array> { // Avoid calls from other contracts // https://github.com/OpenZeppelin/cairo-contracts/issues/344 @@ -87,18 +88,22 @@ mod Account { validate_transaction() } - fn __validate_declare__(class_hash: felt252) -> felt252 { - validate_transaction() - } - - fn is_valid_signature(message: felt252, signature: Array) -> u32 { + fn is_valid_signature(message: felt252, signature: Array) -> felt252 { if _is_valid_signature(message, signature.span()) { - ERC1271_VALIDATED + starknet::VALIDATED } else { 0 } } + } + + impl DeclarerImpl of IDeclarer { + fn __validate_declare__(class_hash: felt252) -> felt252 { + validate_transaction() + } + } + impl SRC5Impl of ISRC5 { fn supports_interface(interface_id: felt252) -> bool { SRC5::supports_interface(interface_id) } @@ -110,17 +115,17 @@ mod Account { #[external] fn __execute__(mut calls: Array) -> Array> { - AccountImpl::__execute__(calls) + SRC6Impl::__execute__(calls) } #[external] fn __validate__(mut calls: Array) -> felt252 { - AccountImpl::__validate__(calls) + SRC6Impl::__validate__(calls) } #[external] fn __validate_declare__(class_hash: felt252) -> felt252 { - AccountImpl::__validate_declare__(class_hash) + DeclarerImpl::__validate_declare__(class_hash) } #[external] @@ -146,13 +151,13 @@ mod Account { } #[view] - fn is_valid_signature(message: felt252, signature: Array) -> u32 { - AccountImpl::is_valid_signature(message, signature) + fn is_valid_signature(message: felt252, signature: Array) -> felt252 { + SRC6Impl::is_valid_signature(message, signature) } #[view] fn supports_interface(interface_id: felt252) -> bool { - AccountImpl::supports_interface(interface_id) + SRC5Impl::supports_interface(interface_id) } // @@ -161,7 +166,7 @@ mod Account { #[internal] fn initializer(_public_key: felt252) { - SRC5::register_interface(IACCOUNT_ID); + SRC5::register_interface(ISRC6_ID); public_key::write(_public_key); } diff --git a/src/openzeppelin/account/interface.cairo b/src/openzeppelin/account/interface.cairo index 6f30f12d7..75ee9f574 100644 --- a/src/openzeppelin/account/interface.cairo +++ b/src/openzeppelin/account/interface.cairo @@ -2,8 +2,7 @@ use array::ArrayTrait; use array::SpanTrait; use starknet::ContractAddress; -const IACCOUNT_ID: felt252 = 0x36c738c1c375b993078fe6b517d477e5a3c9b104e40c04662c4bdd3e2f5fa4a; -const ERC1271_VALIDATED: u32 = 0x1626ba7e_u32; +const ISRC6_ID: felt252 = 0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd; #[derive(Serde, Drop)] struct Call { @@ -12,10 +11,12 @@ struct Call { calldata: Array } -trait IAccount { +trait ISRC6 { fn __execute__(calls: Array) -> Array>; fn __validate__(calls: Array) -> felt252; + fn is_valid_signature(message: felt252, signature: Array) -> felt252; +} + +trait IDeclarer { fn __validate_declare__(class_hash: felt252) -> felt252; - fn is_valid_signature(message: felt252, signature: Array) -> u32; - fn supports_interface(interface_id: felt252) -> bool; } diff --git a/src/openzeppelin/tests/test_account.cairo b/src/openzeppelin/tests/test_account.cairo index d39fa796c..ab076289d 100644 --- a/src/openzeppelin/tests/test_account.cairo +++ b/src/openzeppelin/tests/test_account.cairo @@ -10,8 +10,7 @@ use openzeppelin::account::Account; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; use openzeppelin::account::interface::Call; -use openzeppelin::account::interface::ERC1271_VALIDATED; -use openzeppelin::account::interface::IACCOUNT_ID; +use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::account::QUERY_VERSION; use openzeppelin::account::TRANSACTION_VERSION; use openzeppelin::introspection::src5::ISRC5_ID; @@ -106,7 +105,7 @@ fn test_interfaces() { let supports_default_interface = Account::supports_interface(ISRC5_ID); assert(supports_default_interface, 'Should support base interface'); - let supports_account_interface = Account::supports_interface(IACCOUNT_ID); + let supports_account_interface = Account::supports_interface(ISRC6_ID); assert(supports_account_interface, 'Should support account id'); } @@ -127,7 +126,7 @@ fn test_is_valid_signature() { Account::set_public_key(data.public_key); let is_valid = Account::is_valid_signature(message, good_signature); - assert(is_valid == ERC1271_VALIDATED, 'Should accept valid signature'); + assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); let is_valid = Account::is_valid_signature(message, bad_signature); assert(is_valid == 0, 'Should reject invalid signature'); diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/openzeppelin/token/erc721/erc721.cairo index 6aaf0bc54..d61bc1a6f 100644 --- a/src/openzeppelin/token/erc721/erc721.cairo +++ b/src/openzeppelin/token/erc721/erc721.cairo @@ -456,7 +456,7 @@ mod ERC721 { } else { ISRC5Dispatcher { contract_address: to - }.supports_interface(account::interface::IACCOUNT_ID) + }.supports_interface(account::interface::ISRC6_ID) } } } diff --git a/src/openzeppelin/utils/constants.cairo b/src/openzeppelin/utils/constants.cairo index 7ab63d0da..9d2414bac 100644 --- a/src/openzeppelin/utils/constants.cairo +++ b/src/openzeppelin/utils/constants.cairo @@ -6,8 +6,9 @@ // See: https://github.com/starknet-io/SNIPs/pull/24 const ISRC5_ID: felt252 = 0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055; -// Account -const IACCOUNT_ID: felt252 = 0x36c738c1c375b993078fe6b517d477e5a3c9b104e40c04662c4bdd3e2f5fa4a; +// SRC6 +// See: https://github.com/starknet-io/SNIPs/pull/27 +const ISRC6_ID: felt252 = 0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd; // ERC721 // See: https://eips.ethereum.org/EIPS/eip-721 From ba291339517928fd920d33903e7083bfd5eea631 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 12 Jul 2023 16:02:50 +0200 Subject: [PATCH 061/124] Add camel support for Account (#647) * feat: update interface and ids * refactor: format files * feat: update from reviews * feat: add dual interface to account * fix: tests * feat: add tests * feat: add more tests * feat: apply review suggestions * feat: apply review updates * Update src/openzeppelin/tests/account/test_dual_account.cairo Co-authored-by: Andrew Fleming --------- Co-authored-by: Andrew Fleming --- src/openzeppelin/account.cairo | 4 +- src/openzeppelin/account/account.cairo | 89 ++++-- src/openzeppelin/account/dual_account.cairo | 73 +++++ src/openzeppelin/account/interface.cairo | 8 +- src/openzeppelin/tests.cairo | 2 +- .../access/test_dual_accesscontrol.cairo | 24 +- .../tests/access/test_dual_ownable.cairo | 30 +- .../tests/access/test_ownable.cairo | 18 +- src/openzeppelin/tests/account.cairo | 2 + .../tests/{ => account}/test_account.cairo | 116 +++++++- .../tests/account/test_dual_account.cairo | 276 ++++++++++++++++++ src/openzeppelin/tests/mocks.cairo | 3 + .../tests/mocks/account_panic_mock.cairo | 57 ++++ .../mocks/camel_accesscontrol_mock.cairo | 1 - .../tests/mocks/camel_account_mock.cairo | 31 ++ .../tests/mocks/snake_account_mock.cairo | 53 ++++ src/openzeppelin/utils.cairo | 36 +-- src/openzeppelin/utils/selectors.cairo | 16 + src/openzeppelin/utils/unwrap_and_cast.cairo | 47 +++ 19 files changed, 775 insertions(+), 111 deletions(-) create mode 100644 src/openzeppelin/account/dual_account.cairo create mode 100644 src/openzeppelin/tests/account.cairo rename src/openzeppelin/tests/{ => account}/test_account.cairo (84%) create mode 100644 src/openzeppelin/tests/account/test_dual_account.cairo create mode 100644 src/openzeppelin/tests/mocks/account_panic_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/camel_account_mock.cairo create mode 100644 src/openzeppelin/tests/mocks/snake_account_mock.cairo create mode 100644 src/openzeppelin/utils/unwrap_and_cast.cairo diff --git a/src/openzeppelin/account.cairo b/src/openzeppelin/account.cairo index 75f26fdf1..d995b6329 100644 --- a/src/openzeppelin/account.cairo +++ b/src/openzeppelin/account.cairo @@ -1,6 +1,8 @@ mod account; use account::{ - Account, AccountABIDispatcher, AccountABIDispatcherTrait, TRANSACTION_VERSION, QUERY_VERSION + Account, AccountABIDispatcher, AccountABIDispatcherTrait, AccountABICamelDispatcher, + AccountABICamelDispatcherTrait, TRANSACTION_VERSION, QUERY_VERSION }; +mod dual_account; mod interface; diff --git a/src/openzeppelin/account/account.cairo b/src/openzeppelin/account/account.cairo index 1823dfac7..3c7a860ea 100644 --- a/src/openzeppelin/account/account.cairo +++ b/src/openzeppelin/account/account.cairo @@ -2,11 +2,10 @@ use array::ArrayTrait; use array::SpanTrait; use option::OptionTrait; use serde::Serde; -use serde::deserialize_array_helper; -use serde::serialize_array_helper; use starknet::ContractAddress; use openzeppelin::account::interface::Call; +use openzeppelin::utils::serde::SpanSerde; const TRANSACTION_VERSION: felt252 = 1; // 2**128 + TRANSACTION_VERSION @@ -29,11 +28,34 @@ trait AccountABI { #[view] fn get_public_key() -> felt252; #[view] - fn is_valid_signature(message: felt252, signature: Array) -> felt252; + fn is_valid_signature(hash: felt252, signature: Array) -> felt252; #[view] fn supports_interface(interface_id: felt252) -> bool; } +// Entry points case-convention is enforced by the protocol +#[abi] +trait AccountABICamel { + #[external] + fn __execute__(calls: Array) -> Array>; + #[external] + fn __validate__(calls: Array) -> felt252; + #[external] + fn __validate_declare__(classHash: felt252) -> felt252; + #[external] + fn __validate_deploy__( + classHash: felt252, contractAddressSalt: felt252, _publicKey: felt252 + ) -> felt252; + #[external] + fn setPublicKey(newPublicKey: felt252); + #[view] + fn getPublicKey() -> felt252; + #[view] + fn isValidSignature(hash: felt252, signature: Array) -> felt252; + #[view] + fn supportsInterface(interfaceId: felt252) -> bool; +} + #[account_contract] mod Account { use array::SpanTrait; @@ -49,6 +71,7 @@ mod Account { use openzeppelin::account::interface::IDeclarer; use openzeppelin::account::interface::ISRC6; + use openzeppelin::account::interface::ISRC6Camel; use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::introspection::src5::ISRC5; use openzeppelin::introspection::src5::SRC5; @@ -88,8 +111,8 @@ mod Account { validate_transaction() } - fn is_valid_signature(message: felt252, signature: Array) -> felt252 { - if _is_valid_signature(message, signature.span()) { + fn is_valid_signature(hash: felt252, signature: Array) -> felt252 { + if _is_valid_signature(hash, signature.span()) { starknet::VALIDATED } else { 0 @@ -97,6 +120,20 @@ mod Account { } } + impl SRC6CamelImpl of ISRC6Camel { + fn __execute__(mut calls: Array) -> Array> { + SRC6Impl::__execute__(calls) + } + + fn __validate__(mut calls: Array) -> felt252 { + SRC6Impl::__validate__(calls) + } + + fn isValidSignature(hash: felt252, signature: Array) -> felt252 { + SRC6Impl::is_valid_signature(hash, signature) + } + } + impl DeclarerImpl of IDeclarer { fn __validate_declare__(class_hash: felt252) -> felt252 { validate_transaction() @@ -141,6 +178,11 @@ mod Account { public_key::write(new_public_key); } + #[external] + fn setPublicKey(newPublicKey: felt252) { + set_public_key(newPublicKey); + } + // // View // @@ -151,8 +193,18 @@ mod Account { } #[view] - fn is_valid_signature(message: felt252, signature: Array) -> felt252 { - SRC6Impl::is_valid_signature(message, signature) + fn getPublicKey() -> felt252 { + get_public_key() + } + + #[view] + fn is_valid_signature(hash: felt252, signature: Array) -> felt252 { + SRC6Impl::is_valid_signature(hash, signature) + } + + #[view] + fn isValidSignature(hash: felt252, signature: Array) -> felt252 { + SRC6CamelImpl::isValidSignature(hash, signature) } #[view] @@ -160,6 +212,11 @@ mod Account { SRC5Impl::supports_interface(interface_id) } + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + supports_interface(interfaceId) + } + // // Internals // @@ -187,12 +244,12 @@ mod Account { } #[internal] - fn _is_valid_signature(message: felt252, signature: Span) -> bool { + fn _is_valid_signature(hash: felt252, signature: Span) -> bool { let valid_length = signature.len() == 2_u32; if valid_length { check_ecdsa_signature( - message, public_key::read(), *signature.at(0_u32), *signature.at(1_u32) + hash, public_key::read(), *signature.at(0_u32), *signature.at(1_u32) ) } else { false @@ -222,17 +279,3 @@ mod Account { starknet::call_contract_syscall(to, selector, calldata.span()).unwrap_syscall() } } - -impl SpanSerde< - T, impl TSerde: Serde, impl TCopy: Copy, impl TDrop: Drop -> of Serde> { - fn serialize(self: @Span, ref output: Array) { - (*self).len().serialize(ref output); - serialize_array_helper(*self, ref output); - } - fn deserialize(ref serialized: Span) -> Option> { - let length = *serialized.pop_front()?; - let mut arr = ArrayTrait::new(); - Option::Some(deserialize_array_helper(ref serialized, arr, length)?.span()) - } -} diff --git a/src/openzeppelin/account/dual_account.cairo b/src/openzeppelin/account/dual_account.cairo new file mode 100644 index 000000000..ad6903659 --- /dev/null +++ b/src/openzeppelin/account/dual_account.cairo @@ -0,0 +1,73 @@ +use array::ArrayTrait; +use array::SpanTrait; +use starknet::ContractAddress; +use starknet::SyscallResultTrait; + +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::UnwrapAndCast; + +#[derive(Copy, Drop)] +struct DualCaseAccount { + contract_address: ContractAddress +} + +trait DualCaseAccountTrait { + fn set_public_key(self: @DualCaseAccount, new_public_key: felt252); + fn get_public_key(self: @DualCaseAccount) -> felt252; + fn is_valid_signature( + self: @DualCaseAccount, hash: felt252, signature: Array + ) -> felt252; + fn supports_interface(self: @DualCaseAccount, interface_id: felt252) -> bool; +} + +impl DualCaseAccountImpl of DualCaseAccountTrait { + fn set_public_key(self: @DualCaseAccount, new_public_key: felt252) { + let mut args = ArrayTrait::new(); + args.append_serde(new_public_key); + + try_selector_with_fallback( + *self.contract_address, selectors::set_public_key, selectors::setPublicKey, args.span() + ) + .unwrap_syscall(); + } + + fn get_public_key(self: @DualCaseAccount) -> felt252 { + let mut args = ArrayTrait::new(); + + try_selector_with_fallback( + *self.contract_address, selectors::get_public_key, selectors::getPublicKey, args.span() + ) + .unwrap_and_cast() + } + + fn is_valid_signature( + self: @DualCaseAccount, hash: felt252, signature: Array + ) -> felt252 { + let mut args = ArrayTrait::new(); + args.append_serde(hash); + args.append_serde(signature); + + try_selector_with_fallback( + *self.contract_address, + selectors::is_valid_signature, + selectors::isValidSignature, + args.span() + ) + .unwrap_and_cast() + } + + fn supports_interface(self: @DualCaseAccount, interface_id: felt252) -> bool { + let mut args = ArrayTrait::new(); + args.append_serde(interface_id); + + try_selector_with_fallback( + *self.contract_address, + selectors::supports_interface, + selectors::supportsInterface, + args.span() + ) + .unwrap_and_cast() + } +} diff --git a/src/openzeppelin/account/interface.cairo b/src/openzeppelin/account/interface.cairo index 75ee9f574..af454163c 100644 --- a/src/openzeppelin/account/interface.cairo +++ b/src/openzeppelin/account/interface.cairo @@ -14,7 +14,13 @@ struct Call { trait ISRC6 { fn __execute__(calls: Array) -> Array>; fn __validate__(calls: Array) -> felt252; - fn is_valid_signature(message: felt252, signature: Array) -> felt252; + fn is_valid_signature(hash: felt252, signature: Array) -> felt252; +} + +trait ISRC6Camel { + fn __execute__(calls: Array) -> Array>; + fn __validate__(calls: Array) -> felt252; + fn isValidSignature(hash: felt252, signature: Array) -> felt252; } trait IDeclarer { diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 800541185..1aab31950 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,7 +1,7 @@ mod access; mod test_reentrancyguard; mod test_src5; -mod test_account; +mod account; mod token; mod test_initializable; mod test_pausable; diff --git a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo index 19ae46a4f..4ddf7e8bc 100644 --- a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo +++ b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo @@ -18,9 +18,9 @@ use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; -/// -/// Constants -/// +// +// Constants +// const ROLE: felt252 = 41; @@ -32,9 +32,9 @@ fn AUTHORIZED() -> ContractAddress { contract_address_const::<20>() } -/// -/// Setup -/// +// +// Setup +// fn setup_snake() -> (DualCaseAccessControl, IAccessControlDispatcher) { let mut calldata = ArrayTrait::new(); @@ -84,9 +84,9 @@ fn setup_accesscontrol_panic() -> (DualCaseAccessControl, DualCaseAccessControl) ) } -/// -/// snake_case target -/// +// +// snake_case target +// #[test] #[available_gas(2000000)] @@ -209,9 +209,9 @@ fn test_dual_renounce_role_exists_and_panics() { dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); } -/// -/// camelCase target -/// +// +// camelCase target +// #[test] #[available_gas(2000000)] diff --git a/src/openzeppelin/tests/access/test_dual_ownable.cairo b/src/openzeppelin/tests/access/test_dual_ownable.cairo index dca5595f7..c093838fc 100644 --- a/src/openzeppelin/tests/access/test_dual_ownable.cairo +++ b/src/openzeppelin/tests/access/test_dual_ownable.cairo @@ -18,9 +18,9 @@ use openzeppelin::tests::mocks::dual_ownable_mocks::CamelOwnablePanicMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils; -/// -/// Constants -/// +// +// Constants +// fn OWNER() -> ContractAddress { contract_address_const::<10>() @@ -30,9 +30,9 @@ fn NEW_OWNER() -> ContractAddress { contract_address_const::<20>() } -/// -/// Setup -/// +// +// Setup +// fn setup_snake() -> (DualCaseOwnable, IOwnableDispatcher) { let mut calldata = ArrayTrait::new(); @@ -74,9 +74,9 @@ fn setup_ownable_panic() -> (DualCaseOwnable, DualCaseOwnable) { ) } -/// -/// Case agnostic methods -/// +// +// Case agnostic methods +// #[test] #[available_gas(2000000)] @@ -103,9 +103,9 @@ fn test_dual_owner_exists_and_panics() { dispatcher.owner(); } -/// -/// snake_case target -/// +// +// snake_case target +// #[test] #[available_gas(2000000)] @@ -158,9 +158,9 @@ fn test_dual_renounce_ownership_exists_and_panics() { dispatcher.renounce_ownership(); } -/// -/// camelCase target -/// +// +// camelCase target +// #[test] #[available_gas(2000000)] diff --git a/src/openzeppelin/tests/access/test_ownable.cairo b/src/openzeppelin/tests/access/test_ownable.cairo index 99a717ff6..7f3980699 100644 --- a/src/openzeppelin/tests/access/test_ownable.cairo +++ b/src/openzeppelin/tests/access/test_ownable.cairo @@ -22,9 +22,9 @@ fn setup() { Ownable::initializer(); } -/// -/// initializer -/// +// +// initializer +// #[test] #[available_gas(2000000)] @@ -34,9 +34,9 @@ fn test_initializer() { assert(Ownable::owner() == OWNER(), 'Owner should be set'); } -/// -/// transfer_ownership & transferOwnership -/// +// +// transfer_ownership & transferOwnership +// #[test] #[available_gas(2000000)] @@ -102,9 +102,9 @@ fn test_transferOwnership_from_nonowner() { Ownable::transferOwnership(OTHER()); } -/// -/// renounce_ownership & renounceOwnership -/// +// +// renounce_ownership & renounceOwnership +// #[test] #[available_gas(2000000)] diff --git a/src/openzeppelin/tests/account.cairo b/src/openzeppelin/tests/account.cairo new file mode 100644 index 000000000..1708ec912 --- /dev/null +++ b/src/openzeppelin/tests/account.cairo @@ -0,0 +1,2 @@ +mod test_account; +mod test_dual_account; diff --git a/src/openzeppelin/tests/test_account.cairo b/src/openzeppelin/tests/account/test_account.cairo similarity index 84% rename from src/openzeppelin/tests/test_account.cairo rename to src/openzeppelin/tests/account/test_account.cairo index ab076289d..6ece0c5e9 100644 --- a/src/openzeppelin/tests/test_account.cairo +++ b/src/openzeppelin/tests/account/test_account.cairo @@ -2,8 +2,8 @@ use array::ArrayTrait; use core::traits::Into; use option::OptionTrait; use serde::Serde; -use starknet::ContractAddress; use starknet::contract_address_const; +use starknet::ContractAddress; use starknet::testing; use openzeppelin::account::Account; @@ -21,6 +21,10 @@ use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; +// +// Constants +// + const PUBLIC_KEY: felt252 = 0x333333; const NEW_PUBKEY: felt252 = 0x789789; const SALT: felt252 = 123; @@ -50,6 +54,10 @@ fn SIGNED_TX_DATA() -> SignedTransactionData { } } +// +// Setup +// + fn setup_dispatcher(data: Option<@SignedTransactionData>) -> AccountABIDispatcher { // Set the transaction version testing::set_version(TRANSACTION_VERSION); @@ -72,7 +80,7 @@ fn setup_dispatcher(data: Option<@SignedTransactionData>) -> AccountABIDispatche calldata.append(PUBLIC_KEY); } - let address = utils::deploy(Account::TEST_CLASS_HASH, calldata); + let address = utils::deploy(CLASS_HASH(), calldata); AccountABIDispatcher { contract_address: address } } @@ -90,6 +98,10 @@ fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispa IERC20Dispatcher { contract_address: address } } +// +// constructor +// + #[test] #[available_gas(2000000)] fn test_constructor() { @@ -97,9 +109,13 @@ fn test_constructor() { assert(Account::get_public_key() == PUBLIC_KEY, 'Should return public key'); } +// +// supports_interface & supportsInterface +// + #[test] #[available_gas(2000000)] -fn test_interfaces() { +fn test_supports_interface() { Account::constructor(PUBLIC_KEY); let supports_default_interface = Account::supports_interface(ISRC5_ID); @@ -109,11 +125,50 @@ fn test_interfaces() { assert(supports_account_interface, 'Should support account id'); } +#[test] +#[available_gas(2000000)] +fn test_supportsInterface() { + Account::constructor(PUBLIC_KEY); + + let supports_default_interface = Account::supportsInterface(ISRC5_ID); + assert(supports_default_interface, 'Should support base interface'); + + let supports_account_interface = Account::supportsInterface(ISRC6_ID); + assert(supports_account_interface, 'Should support account id'); +} + +// +// is_valid_signature & isValidSignature +// + #[test] #[available_gas(2000000)] fn test_is_valid_signature() { let data = SIGNED_TX_DATA(); - let message = data.transaction_hash; + let hash = data.transaction_hash; + + let mut good_signature = ArrayTrait::new(); + good_signature.append(data.r); + good_signature.append(data.s); + + let mut bad_signature = ArrayTrait::new(); + bad_signature.append(0x987); + bad_signature.append(0x564); + + Account::set_public_key(data.public_key); + + let is_valid = Account::is_valid_signature(hash, good_signature); + assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); + + let is_valid = Account::is_valid_signature(hash, bad_signature); + assert(is_valid == 0, 'Should reject invalid signature'); +} + +#[test] +#[available_gas(2000000)] +fn test_isValidSignature() { + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; let mut good_signature = ArrayTrait::new(); good_signature.append(data.r); @@ -125,13 +180,17 @@ fn test_is_valid_signature() { Account::set_public_key(data.public_key); - let is_valid = Account::is_valid_signature(message, good_signature); + let is_valid = Account::is_valid_signature(hash, good_signature); assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); - let is_valid = Account::is_valid_signature(message, bad_signature); + let is_valid = Account::is_valid_signature(hash, bad_signature); assert(is_valid == 0, 'Should reject invalid signature'); } +// +// Entry points +// + #[test] #[available_gas(2000000)] fn test_validate_deploy() { @@ -364,6 +423,21 @@ fn test_multicall_zero_calls() { assert(ret.len() == 0, 'Should have an empty response'); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid caller', ))] +fn test_account_called_from_contract() { + let calls = ArrayTrait::new(); + let caller = contract_address_const::<0x123>(); + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(caller); + Account::__execute__(calls); +} + +// +// set_public_key & get_public_key +// + #[test] #[available_gas(2000000)] fn test_public_key_setter_and_getter() { @@ -385,15 +459,29 @@ fn test_public_key_setter_different_account() { Account::set_public_key(NEW_PUBKEY); } +// +// setPublicKey & getPublicKey +// + #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Account: invalid caller', ))] -fn test_account_called_from_contract() { - let calls = ArrayTrait::new(); +fn test_public_key_setter_and_getter_camel() { + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(ACCOUNT_ADDRESS()); + Account::setPublicKey(NEW_PUBKEY); + + let public_key = Account::getPublicKey(); + assert(public_key == NEW_PUBKEY, 'Should update key'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: unauthorized', ))] +fn test_public_key_setter_different_account_camel() { let caller = contract_address_const::<0x123>(); testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(caller); - Account::__execute__(calls); + Account::setPublicKey(NEW_PUBKEY); } // @@ -429,7 +517,7 @@ fn test_assert_only_self_false() { #[available_gas(2000000)] fn test__is_valid_signature() { let data = SIGNED_TX_DATA(); - let message = data.transaction_hash; + let hash = data.transaction_hash; let mut good_signature = ArrayTrait::new(); good_signature.append(data.r); @@ -444,12 +532,12 @@ fn test__is_valid_signature() { Account::set_public_key(data.public_key); - let is_valid = Account::_is_valid_signature(message, good_signature.span()); + let is_valid = Account::_is_valid_signature(hash, good_signature.span()); assert(is_valid, 'Should accept valid signature'); - let is_valid = Account::_is_valid_signature(message, bad_signature.span()); + let is_valid = Account::_is_valid_signature(hash, bad_signature.span()); assert(!is_valid, 'Should reject invalid signature'); - let is_valid = Account::_is_valid_signature(message, invalid_length_signature.span()); + let is_valid = Account::_is_valid_signature(hash, invalid_length_signature.span()); assert(!is_valid, 'Should reject invalid length'); } diff --git a/src/openzeppelin/tests/account/test_dual_account.cairo b/src/openzeppelin/tests/account/test_dual_account.cairo new file mode 100644 index 000000000..946119a6c --- /dev/null +++ b/src/openzeppelin/tests/account/test_dual_account.cairo @@ -0,0 +1,276 @@ +use array::ArrayTrait; +use starknet::testing; + +use openzeppelin::account::dual_account::DualCaseAccount; +use openzeppelin::account::dual_account::DualCaseAccountTrait; +use openzeppelin::account::AccountABICamelDispatcher; +use openzeppelin::account::AccountABICamelDispatcherTrait; +use openzeppelin::account::AccountABIDispatcher; +use openzeppelin::account::AccountABIDispatcherTrait; +use openzeppelin::introspection::src5::ISRC5_ID; +use openzeppelin::tests::account::test_account::SIGNED_TX_DATA; +use openzeppelin::tests::mocks::account_panic_mock::CamelAccountPanicMock; +use openzeppelin::tests::mocks::account_panic_mock::SnakeAccountPanicMock; +use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::mocks::snake_account_mock::SnakeAccountMock; +use openzeppelin::tests::utils; +use openzeppelin::utils::serde::SerializedAppend; + +// +// Constants +// + +const PUBLIC_KEY: felt252 = 0x333333; +const NEW_PUBLIC_KEY: felt252 = 0x444444; + +// +// Setup +// + +fn setup_snake() -> (DualCaseAccount, AccountABIDispatcher) { + let mut calldata = ArrayTrait::new(); + calldata.append_serde(PUBLIC_KEY); + let target = utils::deploy(SnakeAccountMock::TEST_CLASS_HASH, calldata); + ( + DualCaseAccount { + contract_address: target + }, AccountABIDispatcher { + contract_address: target + } + ) +} + +fn setup_camel() -> (DualCaseAccount, AccountABICamelDispatcher) { + let mut calldata = ArrayTrait::new(); + calldata.append_serde(PUBLIC_KEY); + let target = utils::deploy(CamelAccountMock::TEST_CLASS_HASH, calldata); + ( + DualCaseAccount { + contract_address: target + }, AccountABICamelDispatcher { + contract_address: target + } + ) +} + +fn setup_non_account() -> DualCaseAccount { + let calldata = ArrayTrait::new(); + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); + DualCaseAccount { contract_address: target } +} + +fn setup_account_panic() -> (DualCaseAccount, DualCaseAccount) { + let snake_target = utils::deploy(SnakeAccountPanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + let camel_target = utils::deploy(CamelAccountPanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + ( + DualCaseAccount { + contract_address: snake_target + }, DualCaseAccount { + contract_address: camel_target + } + ) +} + +// +// snake_case target +// + +#[test] +#[available_gas(2000000)] +fn test_dual_set_public_key() { + let (snake_dispatcher, target) = setup_snake(); + + testing::set_contract_address(snake_dispatcher.contract_address); + + snake_dispatcher.set_public_key(NEW_PUBLIC_KEY); + assert(target.get_public_key() == NEW_PUBLIC_KEY, 'Should return NEW_PUBLIC_KEY'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_set_public_key() { + let dispatcher = setup_non_account(); + dispatcher.set_public_key(NEW_PUBLIC_KEY); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_set_public_key_exists_and_panics() { + let (dispatcher, _) = setup_account_panic(); + dispatcher.set_public_key(NEW_PUBLIC_KEY); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_get_public_key() { + let (snake_dispatcher, _) = setup_snake(); + assert(snake_dispatcher.get_public_key() == PUBLIC_KEY, 'Should return PUBLIC_KEY'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_get_public_key() { + let dispatcher = setup_non_account(); + dispatcher.get_public_key(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_get_public_key_exists_and_panics() { + let (dispatcher, _) = setup_account_panic(); + dispatcher.get_public_key(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_is_valid_signature() { + let (snake_dispatcher, target) = setup_snake(); + + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; + + let mut signature = ArrayTrait::new(); + signature.append(data.r); + signature.append(data.s); + + testing::set_contract_address(snake_dispatcher.contract_address); + target.set_public_key(data.public_key); + + let is_valid = snake_dispatcher.is_valid_signature(hash, signature); + assert(is_valid == 'VALID', 'Should accept valid signature'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_is_valid_signature() { + let hash = 0x0; + let signature = ArrayTrait::::new(); + + let dispatcher = setup_non_account(); + dispatcher.is_valid_signature(hash, signature); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_is_valid_signature_exists_and_panics() { + let hash = 0x0; + let signature = ArrayTrait::::new(); + + let (dispatcher, _) = setup_account_panic(); + dispatcher.is_valid_signature(hash, signature); +} + + +#[test] +#[available_gas(2000000)] +fn test_dual_supports_interface() { + let (snake_dispatcher, target) = setup_snake(); + assert(snake_dispatcher.supports_interface(ISRC5_ID), 'Should implement ISRC5'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_supports_interface() { + let dispatcher = setup_non_account(); + dispatcher.supports_interface(ISRC5_ID); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_supports_interface_exists_and_panics() { + let (dispatcher, _) = setup_account_panic(); + dispatcher.supports_interface(ISRC5_ID); +} + +// +// camelCase target +// + +#[test] +#[available_gas(2000000)] +fn test_dual_setPublicKey() { + let (camel_dispatcher, target) = setup_camel(); + + testing::set_contract_address(camel_dispatcher.contract_address); + + camel_dispatcher.set_public_key(NEW_PUBLIC_KEY); + assert(target.getPublicKey() == NEW_PUBLIC_KEY, 'Should return NEW_PUBLIC_KEY'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_setPublicKey_exists_and_panics() { + let (_, dispatcher) = setup_account_panic(); + dispatcher.set_public_key(NEW_PUBLIC_KEY); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_getPublicKey() { + let (camel_dispatcher, _) = setup_camel(); + assert(camel_dispatcher.get_public_key() == PUBLIC_KEY, 'Should return PUBLIC_KEY'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_getPublicKey_exists_and_panics() { + let (_, dispatcher) = setup_account_panic(); + dispatcher.get_public_key(); +} + +#[test] +#[available_gas(2000000)] +fn test_dual_isValidSignature() { + let (camel_dispatcher, target) = setup_camel(); + + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; + + let mut signature = ArrayTrait::new(); + signature.append(data.r); + signature.append(data.s); + + testing::set_contract_address(camel_dispatcher.contract_address); + target.setPublicKey(data.public_key); + + let is_valid = camel_dispatcher.is_valid_signature(hash, signature); + assert(is_valid == 'VALID', 'Should accept valid signature'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_isValidSignature_exists_and_panics() { + let hash = 0x0; + let signature = ArrayTrait::::new(); + + let (_, dispatcher) = setup_account_panic(); + dispatcher.is_valid_signature(hash, signature); +} + + +#[test] +#[available_gas(2000000)] +fn test_dual_supportsInterface() { + let (camel_dispatcher, _) = setup_camel(); + assert(camel_dispatcher.supports_interface(ISRC5_ID), 'Should implement ISRC5'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_supportsInterface_exists_and_panics() { + let (_, dispatcher) = setup_account_panic(); + dispatcher.supports_interface(ISRC5_ID); +} diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 325546d0c..86bd7ce90 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -8,8 +8,11 @@ mod snake20_mock; mod erc20_panic; mod non721_mock; mod accesscontrol_panic_mock; +mod account_panic_mock; mod camel_accesscontrol_mock; +mod camel_account_mock; mod snake_accesscontrol_mock; +mod snake_account_mock; mod dual_ownable_mocks; mod snake721_mock; mod camel721_mock; diff --git a/src/openzeppelin/tests/mocks/account_panic_mock.cairo b/src/openzeppelin/tests/mocks/account_panic_mock.cairo new file mode 100644 index 000000000..f3809b807 --- /dev/null +++ b/src/openzeppelin/tests/mocks/account_panic_mock.cairo @@ -0,0 +1,57 @@ +// Although these modules are designed to panic, functions +// still need a valid return value. We chose: +// +// 3 for felt252 +// false for bool + +#[account_contract] +mod SnakeAccountPanicMock { + #[external] + fn set_public_key(new_public_key: felt252) { + panic_with_felt252('Some error'); + } + + #[view] + fn get_public_key() -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn is_valid_signature(hash: felt252, signature: Array) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn supports_interface(interface_id: felt252) -> bool { + panic_with_felt252('Some error'); + false + } +} + +#[account_contract] +mod CamelAccountPanicMock { + #[external] + fn setPublicKey(newPublicKey: felt252) { + panic_with_felt252('Some error'); + } + + #[view] + fn getPublicKey() -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn isValidSignature(hash: felt252, signature: Array) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + panic_with_felt252('Some error'); + false + } +} diff --git a/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo b/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo index 4d6cc6f7e..b1f898855 100644 --- a/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo +++ b/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo @@ -4,7 +4,6 @@ mod CamelAccessControlMock { use starknet::get_caller_address; use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; - use openzeppelin::utils::serde::SpanSerde; #[constructor] fn constructor(admin: ContractAddress) { diff --git a/src/openzeppelin/tests/mocks/camel_account_mock.cairo b/src/openzeppelin/tests/mocks/camel_account_mock.cairo new file mode 100644 index 000000000..01ee5b53e --- /dev/null +++ b/src/openzeppelin/tests/mocks/camel_account_mock.cairo @@ -0,0 +1,31 @@ +#[account_contract] +mod CamelAccountMock { + use openzeppelin::account::interface::Call; + use openzeppelin::account::Account; + use openzeppelin::utils::serde::SpanSerde; + + #[constructor] + fn constructor(_publicKey: felt252) { + Account::initializer(_publicKey); + } + + #[external] + fn setPublicKey(newPublicKey: felt252) { + Account::setPublicKey(newPublicKey); + } + + #[view] + fn getPublicKey() -> felt252 { + Account::getPublicKey() + } + + #[view] + fn isValidSignature(hash: felt252, signature: Array) -> felt252 { + Account::isValidSignature(hash, signature) + } + + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + Account::supportsInterface(interfaceId) + } +} diff --git a/src/openzeppelin/tests/mocks/snake_account_mock.cairo b/src/openzeppelin/tests/mocks/snake_account_mock.cairo new file mode 100644 index 000000000..03b9cd05d --- /dev/null +++ b/src/openzeppelin/tests/mocks/snake_account_mock.cairo @@ -0,0 +1,53 @@ +#[account_contract] +mod SnakeAccountMock { + use openzeppelin::account::interface::Call; + use openzeppelin::account::Account; + use openzeppelin::utils::serde::SpanSerde; + + #[constructor] + fn constructor(_public_key: felt252) { + Account::initializer(_public_key); + } + + #[external] + fn __execute__(mut calls: Array) -> Array> { + Account::__execute__(calls) + } + + #[external] + fn __validate__(mut calls: Array) -> felt252 { + Account::__validate__(calls) + } + + #[external] + fn __validate_declare__(class_hash: felt252) -> felt252 { + Account::__validate_declare__(class_hash) + } + + #[external] + fn __validate_deploy__( + class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + ) -> felt252 { + Account::__validate_deploy__(class_hash, contract_address_salt, _public_key) + } + + #[external] + fn set_public_key(new_public_key: felt252) { + Account::set_public_key(new_public_key); + } + + #[view] + fn get_public_key() -> felt252 { + Account::get_public_key() + } + + #[view] + fn is_valid_signature(hash: felt252, signature: Array) -> felt252 { + Account::is_valid_signature(hash, signature) + } + + #[view] + fn supports_interface(interface_id: felt252) -> bool { + Account::supports_interface(interface_id) + } +} diff --git a/src/openzeppelin/utils.cairo b/src/openzeppelin/utils.cairo index 28e9ac044..e8d356c77 100644 --- a/src/openzeppelin/utils.cairo +++ b/src/openzeppelin/utils.cairo @@ -1,6 +1,7 @@ mod constants; mod selectors; mod serde; +mod unwrap_and_cast; use array::ArrayTrait; use array::SpanTrait; @@ -8,10 +9,9 @@ use box::BoxTrait; use option::OptionTrait; use starknet::call_contract_syscall; use starknet::ContractAddress; -use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResult; use starknet::SyscallResultTrait; -use traits::TryInto; +use unwrap_and_cast::UnwrapAndCast; fn try_selector_with_fallback( target: ContractAddress, snake_selector: felt252, camel_selector: felt252, args: Span @@ -61,35 +61,3 @@ fn check_gas() { }, } } - -trait UnwrapAndCast { - fn unwrap_and_cast(self: SyscallResult>) -> T; -} - -impl UnwrapAndCastBool of UnwrapAndCast { - fn unwrap_and_cast(self: SyscallResult>) -> bool { - (*self.unwrap_syscall().at(0)).try_into().unwrap() - } -} - -impl UnwrapAndCastContractAddress of UnwrapAndCast { - fn unwrap_and_cast(self: SyscallResult>) -> ContractAddress { - (*self.unwrap_syscall().at(0)).try_into().unwrap() - } -} - -impl UnwrapAndCastU8 of UnwrapAndCast { - fn unwrap_and_cast(self: SyscallResult>) -> u8 { - (*self.unwrap_syscall().at(0)).try_into().unwrap() - } -} - -impl UnwrapAndCastU256 of UnwrapAndCast { - fn unwrap_and_cast(self: SyscallResult>) -> u256 { - let unwrapped = self.unwrap_syscall(); - u256 { - low: (*unwrapped.at(0)).try_into().unwrap(), - high: (*unwrapped.at(1)).try_into().unwrap(), - } - } -} diff --git a/src/openzeppelin/utils/selectors.cairo b/src/openzeppelin/utils/selectors.cairo index 8c17091ce..6541e28ab 100644 --- a/src/openzeppelin/utils/selectors.cairo +++ b/src/openzeppelin/utils/selectors.cairo @@ -64,3 +64,19 @@ const total_supply: felt252 = 0x1557182e4359a1f0c6301278e8f5b35a776ab58d39892581 const totalSupply: felt252 = 0x80aa9fdbfaf9615e4afc7f5f722e265daca5ccc655360fa5ccacf9c267936d; const allowance: felt252 = 0x1e888a1026b19c8c0b57c72d63ed1737106aa10034105b980ba117bd0c29fe1; const transfer: felt252 = 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e; + +// +// Account +// + +const set_public_key: felt252 = 0x2e3e21ff5952b2531241e37999d9c4c8b3034cccc89a202a6bf019bdf5294f9; +const setPublicKey: felt252 = 0xbc0eb87884ab91e330445c3584a50d7ddf4b568f02fbeb456a6242cce3f5d9; +const get_public_key: felt252 = 0x1a35984e05126dbecb7c3bb9929e7dd9106d460c59b1633739a5c733a5fb13b; +const getPublicKey: felt252 = 0x1a6c6a0bdec86cc645c91997d8eea83e87148659e3e61122f72361fd5e94079; +const is_valid_signature: felt252 = + 0x28420862938116cb3bbdbedee07451ccc54d4e9412dbef71142ad1980a30941; +const isValidSignature: felt252 = 0x213dfe25e2ca309c4d615a09cfc95fdb2fc7dc73fbcad12c450fe93b1f2ff9e; +const supports_interface: felt252 = + 0xfe80f537b66d12a00b6d3c072b44afbb716e78dde5c3f0ef116ee93d3e3283; +const supportsInterface: felt252 = + 0x29e211664c0b63c79638fbea474206ca74016b3e9a3dc4f9ac300ffd8bdf2cd; diff --git a/src/openzeppelin/utils/unwrap_and_cast.cairo b/src/openzeppelin/utils/unwrap_and_cast.cairo new file mode 100644 index 000000000..0e3959664 --- /dev/null +++ b/src/openzeppelin/utils/unwrap_and_cast.cairo @@ -0,0 +1,47 @@ +use array::SpanTrait; +use option::OptionTrait; +use starknet::ContractAddress; +use starknet::Felt252TryIntoContractAddress; +use starknet::SyscallResult; +use starknet::SyscallResultTrait; +use traits::TryInto; + +use openzeppelin::utils::Felt252TryIntoBool; + +trait UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> T; +} + +impl UnwrapAndCastBool of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> bool { + (*self.unwrap_syscall().at(0)).try_into().unwrap() + } +} + +impl UnwrapAndCastContractAddress of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> ContractAddress { + (*self.unwrap_syscall().at(0)).try_into().unwrap() + } +} + +impl UnwrapFelt of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> felt252 { + *self.unwrap_syscall().at(0) + } +} + +impl UnwrapAndCastU8 of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> u8 { + (*self.unwrap_syscall().at(0)).try_into().unwrap() + } +} + +impl UnwrapAndCastU256 of UnwrapAndCast { + fn unwrap_and_cast(self: SyscallResult>) -> u256 { + let unwrapped = self.unwrap_syscall(); + u256 { + low: (*unwrapped.at(0)).try_into().unwrap(), + high: (*unwrapped.at(1)).try_into().unwrap(), + } + } +} From b44f7dc53cb42594b12dfa65adc63ba0f8d6cc9a Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Wed, 12 Jul 2023 10:23:10 -0400 Subject: [PATCH 062/124] Add src5 dual dispatcher (#659) * add dual src5 * add dual src5 tests and mocks * add felt impl * remove unused imports, integrate unwrap_and_cast for felts * add supports_interface to interface * add supports_interface to erc721 interface * add camelCase supportsInterface test * add dual supports_interface to mocks * add dual supports_interface tests * add dual supports_interface to tests * add comment * fix formatting * clean up test * add comments * remove unused imports * fix interface * fix src5 impl * apply review suggestion --- .../access/accesscontrol/accesscontrol.cairo | 23 ++++- .../accesscontrol/dual_accesscontrol.cairo | 24 +++-- src/openzeppelin/introspection.cairo | 1 + .../introspection/dual_src5.cairo | 31 ++++++ src/openzeppelin/introspection/src5.cairo | 16 ++++ src/openzeppelin/tests.cairo | 2 +- .../tests/access/test_accesscontrol.cairo | 9 +- .../access/test_dual_accesscontrol.cairo | 39 ++++++++ src/openzeppelin/tests/introspection.cairo | 2 + .../tests/introspection/test_dual_src5.cairo | 94 +++++++++++++++++++ .../tests/{ => introspection}/test_src5.cairo | 0 src/openzeppelin/tests/mocks.cairo | 1 + .../mocks/accesscontrol_panic_mock.cairo | 12 +++ .../tests/mocks/camel721_mock.cairo | 2 +- .../mocks/camel_accesscontrol_mock.cairo | 5 + .../tests/mocks/erc721_panic_mock.cairo | 12 +++ .../mocks/snake_accesscontrol_mock.cairo | 5 + src/openzeppelin/tests/mocks/src5_mocks.cairo | 35 +++++++ .../tests/token/test_dual721.cairo | 39 ++++++++ src/openzeppelin/token/erc20/dual20.cairo | 18 +--- src/openzeppelin/token/erc721/dual721.cairo | 37 ++++---- src/openzeppelin/token/erc721/erc721.cairo | 30 ++++-- 22 files changed, 384 insertions(+), 53 deletions(-) create mode 100644 src/openzeppelin/introspection/dual_src5.cairo create mode 100644 src/openzeppelin/tests/introspection.cairo create mode 100644 src/openzeppelin/tests/introspection/test_dual_src5.cairo rename src/openzeppelin/tests/{ => introspection}/test_src5.cairo (100%) create mode 100644 src/openzeppelin/tests/mocks/src5_mocks.cairo diff --git a/src/openzeppelin/access/accesscontrol/accesscontrol.cairo b/src/openzeppelin/access/accesscontrol/accesscontrol.cairo index af4e9ce04..fd7dbf36c 100644 --- a/src/openzeppelin/access/accesscontrol/accesscontrol.cairo +++ b/src/openzeppelin/access/accesscontrol/accesscontrol.cairo @@ -1,7 +1,7 @@ #[contract] mod AccessControl { use openzeppelin::access::accesscontrol::interface; - use openzeppelin::introspection::src5::SRC5; + use openzeppelin::introspection::src5; use starknet::ContractAddress; use starknet::get_caller_address; @@ -32,6 +32,18 @@ mod AccessControl { #[event] fn RoleAdminChanged(role: felt252, previous_admin_role: felt252, new_admin_role: felt252) {} + impl ISRC5Impl of src5::ISRC5 { + fn supports_interface(interface_id: felt252) -> bool { + src5::SRC5::supports_interface(interface_id) + } + } + + impl ISRC5CamelImpl of src5::ISRC5Camel { + fn supportsInterface(interfaceId: felt252) -> bool { + src5::SRC5::supportsInterface(interfaceId) + } + } + impl AccessControlImpl of interface::IAccessControl { fn has_role(role: felt252, account: ContractAddress) -> bool { role_members::read((role, account)) @@ -88,7 +100,12 @@ mod AccessControl { #[view] fn supports_interface(interface_id: felt252) -> bool { - SRC5::supports_interface(interface_id) + ISRC5Impl::supports_interface(interface_id) + } + + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + ISRC5CamelImpl::supportsInterface(interfaceId) } #[view] @@ -151,7 +168,7 @@ mod AccessControl { #[internal] fn initializer() { - SRC5::register_interface(interface::IACCESSCONTROL_ID); + src5::SRC5::register_interface(interface::IACCESSCONTROL_ID); } #[internal] diff --git a/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo b/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo index 032c4f452..e4955afd3 100644 --- a/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo +++ b/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo @@ -1,11 +1,6 @@ use array::ArrayTrait; -use array::SpanTrait; -use core::result::ResultTrait; -use option::OptionTrait; use starknet::ContractAddress; -use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResultTrait; -use traits::TryInto; use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::selectors; @@ -24,6 +19,7 @@ trait DualCaseAccessControlTrait { fn grant_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress); fn revoke_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress); fn renounce_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress); + fn supports_interface(self: @DualCaseAccessControl, interface_id: felt252) -> bool; } impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { @@ -42,11 +38,10 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { let mut args = ArrayTrait::new(); args.append_serde(role); - *try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::get_role_admin, selectors::getRoleAdmin, args.span() ) - .unwrap_syscall() - .at(0) + .unwrap_and_cast() } fn grant_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) { @@ -81,4 +76,17 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { ) .unwrap_syscall(); } + + fn supports_interface(self: @DualCaseAccessControl, interface_id: felt252) -> bool { + let mut args = ArrayTrait::new(); + args.append_serde(interface_id); + + try_selector_with_fallback( + *self.contract_address, + selectors::supports_interface, + selectors::supportsInterface, + args.span() + ) + .unwrap_and_cast() + } } diff --git a/src/openzeppelin/introspection.cairo b/src/openzeppelin/introspection.cairo index 2d1a93a9f..0819e4257 100644 --- a/src/openzeppelin/introspection.cairo +++ b/src/openzeppelin/introspection.cairo @@ -1 +1,2 @@ mod src5; +mod dual_src5; diff --git a/src/openzeppelin/introspection/dual_src5.cairo b/src/openzeppelin/introspection/dual_src5.cairo new file mode 100644 index 000000000..f693aac45 --- /dev/null +++ b/src/openzeppelin/introspection/dual_src5.cairo @@ -0,0 +1,31 @@ +use array::ArrayTrait; +use starknet::ContractAddress; + +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::UnwrapAndCast; + +#[derive(Copy, Drop)] +struct DualCaseSRC5 { + contract_address: ContractAddress +} + +trait DualCaseSRC5Trait { + fn supports_interface(self: @DualCaseSRC5, interface_id: felt252) -> bool; +} + +impl DualCaseSRC5Impl of DualCaseSRC5Trait { + fn supports_interface(self: @DualCaseSRC5, interface_id: felt252) -> bool { + let mut args = ArrayTrait::new(); + args.append_serde(interface_id); + + try_selector_with_fallback( + *self.contract_address, + selectors::supports_interface, + selectors::supportsInterface, + args.span() + ) + .unwrap_and_cast() + } +} diff --git a/src/openzeppelin/introspection/src5.cairo b/src/openzeppelin/introspection/src5.cairo index 424a6faf1..2b0384098 100644 --- a/src/openzeppelin/introspection/src5.cairo +++ b/src/openzeppelin/introspection/src5.cairo @@ -5,6 +5,11 @@ trait ISRC5 { fn supports_interface(interface_id: felt252) -> bool; } +#[abi] +trait ISRC5Camel { + fn supportsInterface(interfaceId: felt252) -> bool; +} + #[contract] mod SRC5 { use openzeppelin::introspection::src5; @@ -22,11 +27,22 @@ mod SRC5 { } } + impl SRC5CamelImpl of src5::ISRC5Camel { + fn supportsInterface(interfaceId: felt252) -> bool { + SRC5Impl::supports_interface(interfaceId) + } + } + #[view] fn supports_interface(interface_id: felt252) -> bool { SRC5Impl::supports_interface(interface_id) } + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + SRC5CamelImpl::supportsInterface(interfaceId) + } + #[internal] fn register_interface(interface_id: felt252) { supported_interfaces::write(interface_id, true); diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 1aab31950..0110b5abc 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,6 +1,6 @@ mod access; mod test_reentrancyguard; -mod test_src5; +mod introspection; mod account; mod token; mod test_initializable; diff --git a/src/openzeppelin/tests/access/test_accesscontrol.cairo b/src/openzeppelin/tests/access/test_accesscontrol.cairo index 241f01553..5e6c71489 100644 --- a/src/openzeppelin/tests/access/test_accesscontrol.cairo +++ b/src/openzeppelin/tests/access/test_accesscontrol.cairo @@ -41,7 +41,7 @@ fn test_initializer() { } // -// supports_interface +// supports_interface & supportsInterface // #[test] @@ -51,6 +51,13 @@ fn test_supports_interface() { assert(AccessControl::supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); } +#[test] +#[available_gas(2000000)] +fn test_supportsInterface() { + AccessControl::initializer(); + assert(AccessControl::supportsInterface(IACCESSCONTROL_ID), 'Should support own interface'); +} + // // has_role & hasRole // diff --git a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo index 4ddf7e8bc..83908f95d 100644 --- a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo +++ b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo @@ -4,6 +4,7 @@ use starknet::contract_address_const; use starknet::testing::set_contract_address; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; +use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; @@ -88,6 +89,29 @@ fn setup_accesscontrol_panic() -> (DualCaseAccessControl, DualCaseAccessControl) // snake_case target // +#[test] +#[available_gas(2000000)] +fn test_dual_supports_interface() { + let (dispatcher, _) = setup_snake(); + assert(dispatcher.supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_supports_interface() { + let dispatcher = setup_non_accesscontrol(); + dispatcher.supports_interface(IACCESSCONTROL_ID); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_supports_interface_exists_and_panics() { + let (dispatcher, _) = setup_accesscontrol_panic(); + dispatcher.supports_interface(IACCESSCONTROL_ID); +} + #[test] #[available_gas(2000000)] fn test_dual_has_role() { @@ -213,6 +237,21 @@ fn test_dual_renounce_role_exists_and_panics() { // camelCase target // +#[test] +#[available_gas(2000000)] +fn test_dual_supportsInterface() { + let (dispatcher, _) = setup_camel(); + assert(dispatcher.supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_supportsInterface_exists_and_panics() { + let (_, dispatcher) = setup_accesscontrol_panic(); + dispatcher.supports_interface(IACCESSCONTROL_ID); +} + #[test] #[available_gas(2000000)] fn test_dual_hasRole() { diff --git a/src/openzeppelin/tests/introspection.cairo b/src/openzeppelin/tests/introspection.cairo new file mode 100644 index 000000000..d46bcfe7d --- /dev/null +++ b/src/openzeppelin/tests/introspection.cairo @@ -0,0 +1,2 @@ +mod test_src5; +mod test_dual_src5; diff --git a/src/openzeppelin/tests/introspection/test_dual_src5.cairo b/src/openzeppelin/tests/introspection/test_dual_src5.cairo new file mode 100644 index 000000000..5693b941c --- /dev/null +++ b/src/openzeppelin/tests/introspection/test_dual_src5.cairo @@ -0,0 +1,94 @@ +use array::ArrayTrait; +use openzeppelin::introspection::src5::ISRC5_ID; +use openzeppelin::introspection::src5::ISRC5Dispatcher; +use openzeppelin::introspection::src5::ISRC5DispatcherTrait; +use openzeppelin::introspection::src5::ISRC5CamelDispatcher; +use openzeppelin::introspection::src5::ISRC5CamelDispatcherTrait; +use openzeppelin::introspection::dual_src5::DualCaseSRC5; +use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; +use openzeppelin::tests::mocks::src5_mocks::SnakeSRC5Mock; +use openzeppelin::tests::mocks::src5_mocks::CamelSRC5Mock; +use openzeppelin::tests::mocks::src5_mocks::SnakeSRC5PanicMock; +use openzeppelin::tests::mocks::src5_mocks::CamelSRC5PanicMock; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils; + +// +// Setup +// + +fn setup_snake() -> DualCaseSRC5 { + let mut calldata = ArrayTrait::new(); + let target = utils::deploy(SnakeSRC5Mock::TEST_CLASS_HASH, calldata); + DualCaseSRC5 { contract_address: target } +} + +fn setup_camel() -> DualCaseSRC5 { + let mut calldata = ArrayTrait::new(); + let target = utils::deploy(CamelSRC5Mock::TEST_CLASS_HASH, calldata); + DualCaseSRC5 { contract_address: target } +} + +fn setup_non_src5() -> DualCaseSRC5 { + let calldata = ArrayTrait::new(); + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); + DualCaseSRC5 { contract_address: target } +} + +fn setup_src5_panic() -> (DualCaseSRC5, DualCaseSRC5) { + let snake_target = utils::deploy(SnakeSRC5PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + let camel_target = utils::deploy(CamelSRC5PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + ( + DualCaseSRC5 { + contract_address: snake_target + }, DualCaseSRC5 { + contract_address: camel_target + } + ) +} + +// +// snake_case target +// + +#[test] +#[available_gas(2000000)] +fn test_dual_supports_interface() { + let dispatcher = setup_snake(); + assert(dispatcher.supports_interface(ISRC5_ID), 'Should support base interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_supports_interface() { + let dispatcher = setup_non_src5(); + dispatcher.supports_interface(ISRC5_ID); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_supports_interface_exists_and_panics() { + let (dispatcher, _) = setup_src5_panic(); + dispatcher.supports_interface(ISRC5_ID); +} + +// +// camelCase target +// + +#[test] +#[available_gas(2000000)] +fn test_dual_supportsInterface() { + let dispatcher = setup_camel(); + assert(dispatcher.supports_interface(ISRC5_ID), 'Should support base interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_supportsInterface_exists_and_panics() { + let (_, dispatcher) = setup_src5_panic(); + dispatcher.supports_interface(ISRC5_ID); +} diff --git a/src/openzeppelin/tests/test_src5.cairo b/src/openzeppelin/tests/introspection/test_src5.cairo similarity index 100% rename from src/openzeppelin/tests/test_src5.cairo rename to src/openzeppelin/tests/introspection/test_src5.cairo diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 86bd7ce90..27ad2d535 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -17,3 +17,4 @@ mod dual_ownable_mocks; mod snake721_mock; mod camel721_mock; mod non_implementing_mock; +mod src5_mocks; diff --git a/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo b/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo index a1c13cf66..10601ca78 100644 --- a/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo +++ b/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo @@ -8,6 +8,12 @@ mod SnakeAccessControlPanicMock { use starknet::ContractAddress; + #[view] + fn supports_interface(interface_id: felt252) -> bool { + panic_with_felt252('Some error'); + false + } + #[view] fn has_role(role: felt252, account: ContractAddress) -> bool { panic_with_felt252('Some error'); @@ -40,6 +46,12 @@ mod SnakeAccessControlPanicMock { mod CamelAccessControlPanicMock { use starknet::ContractAddress; + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + panic_with_felt252('Some error'); + false + } + #[view] fn hasRole(role: felt252, account: ContractAddress) -> bool { panic_with_felt252('Some error'); diff --git a/src/openzeppelin/tests/mocks/camel721_mock.cairo b/src/openzeppelin/tests/mocks/camel721_mock.cairo index ef0d95ed2..b2e02793b 100644 --- a/src/openzeppelin/tests/mocks/camel721_mock.cairo +++ b/src/openzeppelin/tests/mocks/camel721_mock.cairo @@ -16,7 +16,7 @@ mod CamelERC721Mock { #[view] fn supportsInterface(interfaceId: felt252) -> bool { - ERC721::supports_interface(interfaceId) + ERC721::supportsInterface(interfaceId) } #[view] diff --git a/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo b/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo index b1f898855..dff5ab1b6 100644 --- a/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo +++ b/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo @@ -11,6 +11,11 @@ mod CamelAccessControlMock { AccessControl::_grant_role(DEFAULT_ADMIN_ROLE, admin); } + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + AccessControl::supportsInterface(interfaceId) + } + #[view] fn hasRole(role: felt252, account: ContractAddress) -> bool { AccessControl::hasRole(role, account) diff --git a/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo b/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo index d7f1702dd..b824bf125 100644 --- a/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo +++ b/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo @@ -36,6 +36,12 @@ mod SnakeERC721PanicMock { // snake // + #[view] + fn supports_interface(interface_id: felt252) -> bool { + panic_with_felt252('Some error'); + false + } + #[view] fn token_uri(token_id: u256) -> felt252 { panic_with_felt252('Some error'); @@ -90,6 +96,12 @@ mod CamelERC721PanicMock { use starknet::ContractAddress; use zeroable::Zeroable; + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + panic_with_felt252('Some error'); + false + } + #[view] fn tokenUri(tokenId: u256) -> felt252 { panic_with_felt252('Some error'); diff --git a/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo b/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo index 76c2d9f26..ea3122a67 100644 --- a/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo +++ b/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo @@ -12,6 +12,11 @@ mod SnakeAccessControlMock { AccessControl::_grant_role(DEFAULT_ADMIN_ROLE, admin); } + #[view] + fn supports_interface(interface_id: felt252) -> bool { + AccessControl::supports_interface(interface_id) + } + #[view] fn has_role(role: felt252, account: ContractAddress) -> bool { AccessControl::has_role(role, account) diff --git a/src/openzeppelin/tests/mocks/src5_mocks.cairo b/src/openzeppelin/tests/mocks/src5_mocks.cairo new file mode 100644 index 000000000..28ccf2b6b --- /dev/null +++ b/src/openzeppelin/tests/mocks/src5_mocks.cairo @@ -0,0 +1,35 @@ +use openzeppelin::introspection::src5::SRC5; + +#[contract] +mod SnakeSRC5Mock { + #[view] + fn supports_interface(interface_id: felt252) -> bool { + super::SRC5::supports_interface(interface_id) + } +} + +#[contract] +mod CamelSRC5Mock { + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + super::SRC5::supportsInterface(interfaceId) + } +} + +#[contract] +mod SnakeSRC5PanicMock { + #[view] + fn supports_interface(interface_id: felt252) -> bool { + panic_with_felt252('Some error'); + false + } +} + +#[contract] +mod CamelSRC5PanicMock { + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + panic_with_felt252('Some error'); + false + } +} diff --git a/src/openzeppelin/tests/token/test_dual721.cairo b/src/openzeppelin/tests/token/test_dual721.cairo index 0ef8a0521..ca821a4be 100644 --- a/src/openzeppelin/tests/token/test_dual721.cairo +++ b/src/openzeppelin/tests/token/test_dual721.cairo @@ -3,6 +3,7 @@ use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing::set_caller_address; use starknet::testing::set_contract_address; +use openzeppelin::token::erc721::interface::IERC721_ID; use openzeppelin::token::erc721::interface::IERC721Dispatcher; use openzeppelin::token::erc721::interface::IERC721CamelDispatcher; use openzeppelin::token::erc721::interface::IERC721DispatcherTrait; @@ -386,6 +387,29 @@ fn test_dual_token_uri_exists_and_panics() { dispatcher.token_uri(TOKEN_ID); } +#[test] +#[available_gas(2000000)] +fn test_dual_supports_interface() { + let (dispatcher, _) = setup_snake(); + assert(dispatcher.supports_interface(IERC721_ID), 'Should support own interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_supports_interface() { + let dispatcher = setup_non_erc721(); + dispatcher.supports_interface(IERC721_ID); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_supports_interface_exists_and_panics() { + let (dispatcher, _) = setup_erc721_panic(); + dispatcher.supports_interface(IERC721_ID); +} + /// /// camelCase target /// @@ -519,3 +543,18 @@ fn test_dual_tokenUri_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.token_uri(TOKEN_ID); } + +#[test] +#[available_gas(2000000)] +fn test_dual_supportsInterface() { + let (dispatcher, _) = setup_camel(); + assert(dispatcher.supports_interface(IERC721_ID), 'Should support own interface'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_supportsInterface_exists_and_panics() { + let (_, dispatcher) = setup_erc721_panic(); + dispatcher.supports_interface(IERC721_ID); +} diff --git a/src/openzeppelin/token/erc20/dual20.cairo b/src/openzeppelin/token/erc20/dual20.cairo index 2d9028f70..99a5045a4 100644 --- a/src/openzeppelin/token/erc20/dual20.cairo +++ b/src/openzeppelin/token/erc20/dual20.cairo @@ -1,17 +1,9 @@ use array::ArrayTrait; -use array::SpanTrait; -use core::result::ResultTrait; -use integer::Felt252TryIntoU8; -use option::OptionTrait; use starknet::call_contract_syscall; use starknet::ContractAddress; -use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResultTrait; -use traits::TryInto; use openzeppelin::utils::try_selector_with_fallback; -use openzeppelin::utils::Felt252TryIntoBool; -use openzeppelin::utils::BoolIntoFelt252; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::UnwrapAndCast; @@ -39,17 +31,15 @@ impl DualERC20Impl of DualERC20Trait { fn name(self: @DualERC20) -> felt252 { let args = ArrayTrait::new(); - *call_contract_syscall(*self.contract_address, selectors::name, args.span()) - .unwrap_syscall() - .at(0) + call_contract_syscall(*self.contract_address, selectors::name, args.span()) + .unwrap_and_cast() } fn symbol(self: @DualERC20) -> felt252 { let args = ArrayTrait::new(); - *call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) - .unwrap_syscall() - .at(0) + call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) + .unwrap_and_cast() } fn decimals(self: @DualERC20) -> u8 { diff --git a/src/openzeppelin/token/erc721/dual721.cairo b/src/openzeppelin/token/erc721/dual721.cairo index 35389f357..bdd49fd03 100644 --- a/src/openzeppelin/token/erc721/dual721.cairo +++ b/src/openzeppelin/token/erc721/dual721.cairo @@ -1,16 +1,8 @@ -use core::result::ResultTrait; -use traits::Into; -use traits::TryInto; -use array::SpanTrait; use array::ArrayTrait; -use option::OptionTrait; use starknet::ContractAddress; use starknet::SyscallResultTrait; use starknet::call_contract_syscall; -use starknet::Felt252TryIntoContractAddress; use openzeppelin::utils::try_selector_with_fallback; -use openzeppelin::utils::Felt252TryIntoBool; -use openzeppelin::utils::BoolIntoFelt252; use openzeppelin::utils::selectors; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::serde::SerializedAppend; @@ -42,34 +34,32 @@ trait DualCaseERC721Trait { token_id: u256, data: Span ); + fn supports_interface(self: @DualCaseERC721, interface_id: felt252) -> bool; } impl DualCaseERC721Impl of DualCaseERC721Trait { fn name(self: @DualCaseERC721) -> felt252 { let args = ArrayTrait::new(); - *call_contract_syscall(*self.contract_address, selectors::name, args.span()) - .unwrap_syscall() - .at(0) + call_contract_syscall(*self.contract_address, selectors::name, args.span()) + .unwrap_and_cast() } fn symbol(self: @DualCaseERC721) -> felt252 { let args = ArrayTrait::new(); - *call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) - .unwrap_syscall() - .at(0) + call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) + .unwrap_and_cast() } fn token_uri(self: @DualCaseERC721, token_id: u256) -> felt252 { let mut args = ArrayTrait::new(); args.append_serde(token_id); - *try_selector_with_fallback( + try_selector_with_fallback( *self.contract_address, selectors::token_uri, selectors::tokenUri, args.span() ) - .unwrap_syscall() - .at(0) + .unwrap_and_cast() } fn balance_of(self: @DualCaseERC721, account: ContractAddress) -> u256 { @@ -175,4 +165,17 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { ) .unwrap_syscall(); } + + fn supports_interface(self: @DualCaseERC721, interface_id: felt252) -> bool { + let mut args = ArrayTrait::new(); + args.append_serde(interface_id); + + try_selector_with_fallback( + *self.contract_address, + selectors::supports_interface, + selectors::supportsInterface, + args.span() + ) + .unwrap_and_cast() + } } diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/openzeppelin/token/erc721/erc721.cairo index d61bc1a6f..8f5f5088a 100644 --- a/src/openzeppelin/token/erc721/erc721.cairo +++ b/src/openzeppelin/token/erc721/erc721.cairo @@ -11,6 +11,8 @@ trait ERC721ABI { fn approve(to: ContractAddress, token_id: u256); // snake_case #[view] + fn supports_interface(interface_id: felt252) -> bool; + #[view] fn balance_of(account: ContractAddress) -> u256; #[view] fn owner_of(token_id: u256) -> ContractAddress; @@ -30,6 +32,8 @@ trait ERC721ABI { fn token_uri(token_id: u256) -> felt252; // camelCase #[view] + fn supportsInterface(interfaceId: felt252) -> bool; + #[view] fn balanceOf(account: ContractAddress) -> u256; #[view] fn ownerOf(tokenId: u256) -> ContractAddress; @@ -57,8 +61,8 @@ mod ERC721 { use openzeppelin::token::erc721; // Dispatchers - use openzeppelin::introspection::src5::ISRC5Dispatcher; - use openzeppelin::introspection::src5::ISRC5DispatcherTrait; + use openzeppelin::introspection::dual_src5::DualCaseSRC5; + use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; use super::super::interface::ERC721ReceiverABIDispatcher; use super::super::interface::ERC721ReceiverABIDispatcherTrait; @@ -95,6 +99,18 @@ mod ERC721 { initializer(name, symbol); } + impl ISRC5Impl of src5::ISRC5 { + fn supports_interface(interface_id: felt252) -> bool { + src5::SRC5::supports_interface(interface_id) + } + } + + impl ISRC5CamelImpl of src5::ISRC5Camel { + fn supportsInterface(interfaceId: felt252) -> bool { + src5::SRC5::supportsInterface(interfaceId) + } + } + impl ERC721Impl of erc721::interface::IERC721 { fn name() -> felt252 { _name::read() @@ -210,12 +226,12 @@ mod ERC721 { #[view] fn supports_interface(interface_id: felt252) -> bool { - src5::SRC5::supports_interface(interface_id) + ISRC5Impl::supports_interface(interface_id) } #[view] fn supportsInterface(interfaceId: felt252) -> bool { - src5::SRC5::supports_interface(interfaceId) + ISRC5CamelImpl::supportsInterface(interfaceId) } #[view] @@ -443,7 +459,7 @@ mod ERC721 { fn _check_on_erc721_received( from: ContractAddress, to: ContractAddress, token_id: u256, data: Span ) -> bool { - if (ISRC5Dispatcher { + if (DualCaseSRC5 { contract_address: to }.supports_interface(erc721::interface::IERC721_RECEIVER_ID)) { // todo add casing fallback mechanism @@ -454,9 +470,7 @@ mod ERC721 { get_caller_address(), from, token_id, data ) == erc721::interface::IERC721_RECEIVER_ID } else { - ISRC5Dispatcher { - contract_address: to - }.supports_interface(account::interface::ISRC6_ID) + DualCaseSRC5 { contract_address: to }.supports_interface(account::interface::ISRC6_ID) } } } From 33dbd5685d2e2415aa597c3378de4e516527383a Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 13 Jul 2023 12:39:34 -0400 Subject: [PATCH 063/124] Add dual case erc721 receiver (#649) * add 721 holder * add 721 receiver selectors * add abis * add dual receiver * add dual receiver mocks * add dual 721 receiver and holder mods * add dual 721 receiver tests * integrate dual case receiver * remove camel supportsInterface * add isrc5 impl * add isrc5 impl * fix formatting * change receiver import * remove unused mod * add isrc5 impl * remove mod * fix formatting * remove conflict * add felt impl to UnwrapAndCast * clean up mocks * add camelCase ISRC5 impl * add camelCase tests for safe methods * fix test * remove unused imports * remove unused imports * remove unused imports * Apply suggestions from code review Co-authored-by: Eric Nordelo * add transferFrom and safeTransferFrom tests * fix comments * fix comments --------- Co-authored-by: Eric Nordelo --- src/openzeppelin/tests/mocks.cairo | 1 + .../tests/mocks/dual721_receiver_mocks.cairo | 83 +++ .../tests/mocks/erc721_receiver.cairo | 31 +- src/openzeppelin/tests/token.cairo | 1 + .../tests/token/test_dual20.cairo | 30 +- .../tests/token/test_dual721.cairo | 30 +- .../tests/token/test_dual721_receiver.cairo | 146 +++++ .../tests/token/test_erc721.cairo | 554 ++++++++++++++++-- src/openzeppelin/token/erc20/erc20.cairo | 6 +- src/openzeppelin/token/erc721.cairo | 1 + .../token/erc721/dual721_receiver.cairo | 46 ++ src/openzeppelin/token/erc721/erc721.cairo | 22 +- src/openzeppelin/token/erc721/interface.cairo | 2 + src/openzeppelin/utils/selectors.cairo | 8 + 14 files changed, 873 insertions(+), 88 deletions(-) create mode 100644 src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo create mode 100644 src/openzeppelin/tests/token/test_dual721_receiver.cairo create mode 100644 src/openzeppelin/token/erc721/dual721_receiver.cairo diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 27ad2d535..7ed138560 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -17,4 +17,5 @@ mod dual_ownable_mocks; mod snake721_mock; mod camel721_mock; mod non_implementing_mock; +mod dual721_receiver_mocks; mod src5_mocks; diff --git a/src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo b/src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo new file mode 100644 index 000000000..3ffb3df74 --- /dev/null +++ b/src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo @@ -0,0 +1,83 @@ +use openzeppelin::introspection::src5::SRC5; +use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; +use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver::IERC721_RECEIVER_ID; + +#[contract] +mod SnakeERC721ReceiverMock { + use openzeppelin::utils::serde::SpanSerde; + use starknet::ContractAddress; + use super::ERC721Receiver; + use super::IERC721_RECEIVER_ID; + use super::SRC5; + + #[constructor] + fn constructor() { + SRC5::register_interface(IERC721_RECEIVER_ID); + } + + #[view] + fn on_erc721_received( + operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + ) -> felt252 { + ERC721Receiver::on_erc721_received(operator, from, token_id, data) + } + + #[view] + fn supports_interface(interface_id: felt252) -> bool { + ERC721Receiver::supports_interface(interface_id) + } +} + +#[contract] +mod CamelERC721ReceiverMock { + use openzeppelin::utils::serde::SpanSerde; + use starknet::ContractAddress; + use super::ERC721Receiver; + use super::IERC721_RECEIVER_ID; + use super::SRC5; + + #[constructor] + fn constructor() { + SRC5::register_interface(IERC721_RECEIVER_ID); + } + + #[view] + fn onERC721Received( + operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + ) -> felt252 { + ERC721Receiver::on_erc721_received(operator, from, tokenId, data) + } + + #[view] + fn supportsInterface(interfaceId: felt252) -> bool { + ERC721Receiver::supportsInterface(interfaceId) + } +} + +#[contract] +mod SnakeERC721ReceiverPanicMock { + use openzeppelin::utils::serde::SpanSerde; + use starknet::ContractAddress; + + #[view] + fn on_erc721_received( + operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + ) -> felt252 { + panic_with_felt252('Some error'); + 3 + } +} + +#[contract] +mod CamelERC721ReceiverPanicMock { + use openzeppelin::utils::serde::SpanSerde; + use starknet::ContractAddress; + + #[view] + fn onERC721Received( + operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + ) -> felt252 { + panic_with_felt252('Some error'); + 3 + } +} diff --git a/src/openzeppelin/tests/mocks/erc721_receiver.cairo b/src/openzeppelin/tests/mocks/erc721_receiver.cairo index 4bb3556bf..aff07e7aa 100644 --- a/src/openzeppelin/tests/mocks/erc721_receiver.cairo +++ b/src/openzeppelin/tests/mocks/erc721_receiver.cairo @@ -6,11 +6,28 @@ mod ERC721Receiver { use openzeppelin::token::erc721::interface::IERC721Receiver; use openzeppelin::token::erc721::interface::IERC721ReceiverCamel; use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; - use openzeppelin::introspection::src5::SRC5; + use openzeppelin::introspection::src5; + use array::SpanTrait; use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; - use array::SpanTrait; + + #[constructor] + fn constructor() { + src5::SRC5::register_interface(IERC721_RECEIVER_ID); + } + + impl ISRC5Impl of src5::ISRC5 { + fn supports_interface(interface_id: felt252) -> bool { + src5::SRC5::supports_interface(interface_id) + } + } + + impl ISRC5CamelImpl of src5::ISRC5Camel { + fn supportsInterface(interfaceId: felt252) -> bool { + src5::SRC5::supportsInterface(interfaceId) + } + } impl ERC721ReceiverImpl of IERC721Receiver { fn on_erc721_received( @@ -32,14 +49,14 @@ mod ERC721Receiver { } } - #[constructor] - fn constructor() { - SRC5::register_interface(IERC721_RECEIVER_ID); + #[view] + fn supports_interface(interface_id: felt252) -> bool { + ISRC5Impl::supports_interface(interface_id) } #[view] - fn supports_interface(interface_id: felt252) -> bool { - SRC5::supports_interface(interface_id) + fn supportsInterface(interfaceId: felt252) -> bool { + ISRC5CamelImpl::supportsInterface(interfaceId) } #[external] diff --git a/src/openzeppelin/tests/token.cairo b/src/openzeppelin/tests/token.cairo index 1020d4439..ebb5dc5c4 100644 --- a/src/openzeppelin/tests/token.cairo +++ b/src/openzeppelin/tests/token.cairo @@ -2,3 +2,4 @@ mod test_dual20; mod test_dual721; mod test_erc20; mod test_erc721; +mod test_dual721_receiver; diff --git a/src/openzeppelin/tests/token/test_dual20.cairo b/src/openzeppelin/tests/token/test_dual20.cairo index 0da4ea5c7..1afa77c31 100644 --- a/src/openzeppelin/tests/token/test_dual20.cairo +++ b/src/openzeppelin/tests/token/test_dual20.cairo @@ -17,9 +17,9 @@ use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; -/// -/// Constants -/// +// +// Constants +// const NAME: felt252 = 111; const SYMBOL: felt252 = 222; @@ -40,9 +40,9 @@ fn OPERATOR() -> ContractAddress { contract_address_const::<40>() } -/// -/// Setup -/// +// +// Setup +// fn setup_snake() -> (DualERC20, IERC20Dispatcher) { let mut calldata = ArrayTrait::new(); @@ -76,9 +76,9 @@ fn setup_erc20_panic() -> (DualERC20, DualERC20) { (DualERC20 { contract_address: snake_target }, DualERC20 { contract_address: camel_target }) } -/// -/// Case agnostic methods -/// +// +// Case agnostic methods +// #[test] #[available_gas(2000000)] @@ -215,9 +215,9 @@ fn test_dual_approve_exists_and_panics() { dispatcher.approve(SPENDER(), VALUE); } -/// -/// snake_case target -/// +// +// snake_case target +// #[test] #[available_gas(2000000)] @@ -293,9 +293,9 @@ fn test_dual_transfer_from_exists_and_panics() { dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); } -/// -/// camelCase target -/// +// +// camelCase target +// #[test] #[available_gas(2000000)] diff --git a/src/openzeppelin/tests/token/test_dual721.cairo b/src/openzeppelin/tests/token/test_dual721.cairo index ca821a4be..4adab5d29 100644 --- a/src/openzeppelin/tests/token/test_dual721.cairo +++ b/src/openzeppelin/tests/token/test_dual721.cairo @@ -21,9 +21,9 @@ use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; -/// -/// Constants -/// +// +// Constants +// const NAME: felt252 = 111; const SYMBOL: felt252 = 222; @@ -52,9 +52,9 @@ fn DATA(success: bool) -> Span { data.span() } -/// -/// Setup -/// +// +// Setup +// fn setup_snake() -> (DualCaseERC721, IERC721Dispatcher) { let mut calldata = ArrayTrait::new(); @@ -106,9 +106,9 @@ fn setup_receiver() -> ContractAddress { utils::deploy(ERC721Receiver::TEST_CLASS_HASH, ArrayTrait::new()) } -/// -/// Case agnostic methods -/// +// +// Case agnostic methods +// #[test] #[available_gas(2000000)] @@ -190,9 +190,9 @@ fn test_dual_approve_exists_and_panics() { dispatcher.approve(SPENDER(), TOKEN_ID); } -/// -/// snake_case target -/// +// +// snake_case target +// #[test] #[available_gas(2000000)] @@ -410,9 +410,9 @@ fn test_dual_supports_interface_exists_and_panics() { dispatcher.supports_interface(IERC721_ID); } -/// -/// camelCase target -/// +// +// camelCase target +// #[test] #[available_gas(2000000)] diff --git a/src/openzeppelin/tests/token/test_dual721_receiver.cairo b/src/openzeppelin/tests/token/test_dual721_receiver.cairo new file mode 100644 index 000000000..ef02380a9 --- /dev/null +++ b/src/openzeppelin/tests/token/test_dual721_receiver.cairo @@ -0,0 +1,146 @@ +use array::ArrayTrait; +use starknet::ContractAddress; +use starknet::contract_address_const; +use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; +use openzeppelin::tests::mocks::erc721_receiver::FAILURE; +use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; +use openzeppelin::token::erc721::interface::IERC721ReceiverDispatcher; +use openzeppelin::token::erc721::interface::IERC721ReceiverCamelDispatcher; +use openzeppelin::token::erc721::interface::IERC721ReceiverDispatcherTrait; +use openzeppelin::token::erc721::interface::IERC721ReceiverCamelDispatcherTrait; +use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; +use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; +use openzeppelin::tests::mocks::dual721_receiver_mocks::SnakeERC721ReceiverMock; +use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; +use openzeppelin::tests::mocks::dual721_receiver_mocks::SnakeERC721ReceiverPanicMock; +use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverPanicMock; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils; + +// +// Constants +// + +const TOKEN_ID: u256 = 7; + +fn DATA(success: bool) -> Span { + let mut data = ArrayTrait::new(); + if success { + data.append(SUCCESS); + } else { + data.append(FAILURE); + } + data.span() +} + +fn OWNER() -> ContractAddress { + contract_address_const::<10>() +} + +fn OPERATOR() -> ContractAddress { + contract_address_const::<20>() +} + +// +// Setup +// + +fn setup_snake() -> (DualCaseERC721Receiver, IERC721ReceiverDispatcher) { + let mut calldata = ArrayTrait::new(); + let target = utils::deploy(SnakeERC721ReceiverMock::TEST_CLASS_HASH, calldata); + ( + DualCaseERC721Receiver { + contract_address: target + }, IERC721ReceiverDispatcher { + contract_address: target + } + ) +} + +fn setup_camel() -> (DualCaseERC721Receiver, IERC721ReceiverCamelDispatcher) { + let mut calldata = ArrayTrait::new(); + let target = utils::deploy(CamelERC721ReceiverMock::TEST_CLASS_HASH, calldata); + ( + DualCaseERC721Receiver { + contract_address: target + }, IERC721ReceiverCamelDispatcher { + contract_address: target + } + ) +} + +fn setup_non_erc721_receiver() -> DualCaseERC721Receiver { + let calldata = ArrayTrait::new(); + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); + DualCaseERC721Receiver { contract_address: target } +} + +fn setup_erc721_receiver_panic() -> (DualCaseERC721Receiver, DualCaseERC721Receiver) { + let snake_target = utils::deploy( + SnakeERC721ReceiverPanicMock::TEST_CLASS_HASH, ArrayTrait::new() + ); + let camel_target = utils::deploy( + CamelERC721ReceiverPanicMock::TEST_CLASS_HASH, ArrayTrait::new() + ); + ( + DualCaseERC721Receiver { + contract_address: snake_target + }, DualCaseERC721Receiver { + contract_address: camel_target + } + ) +} + +// +// snake_case target +// + +#[test] +#[available_gas(2000000)] +fn test_dual_on_erc721_received() { + let (dispatcher, _) = setup_snake(); + assert( + dispatcher + .on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)) == IERC721_RECEIVER_ID, + 'Should return interface id' + ); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_dual_no_on_erc721_received() { + let dispatcher = setup_non_erc721_receiver(); + dispatcher.on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_on_erc721_received_exists_and_panics() { + let (dispatcher, _) = setup_erc721_receiver_panic(); + dispatcher.on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); +} + +// +// camelCase target +// + +#[test] +#[available_gas(2000000)] +fn test_dual_onERC721Received() { + let (dispatcher, _) = setup_camel(); + assert( + dispatcher + .on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)) == IERC721_RECEIVER_ID, + 'Should return interface id' + ); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +fn test_dual_onERC721Received_exists_and_panics() { + let (_, dispatcher) = setup_erc721_receiver_panic(); + dispatcher.on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); +} diff --git a/src/openzeppelin/tests/token/test_erc721.cairo b/src/openzeppelin/tests/token/test_erc721.cairo index 4f968c0ee..5037ae251 100644 --- a/src/openzeppelin/tests/token/test_erc721.cairo +++ b/src/openzeppelin/tests/token/test_erc721.cairo @@ -8,6 +8,8 @@ use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; use openzeppelin::tests::mocks::erc721_receiver::ERC721NonReceiver; use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; use openzeppelin::tests::mocks::erc721_receiver::FAILURE; +use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; +use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; use starknet::contract_address_const; use starknet::ContractAddress; @@ -22,6 +24,7 @@ const NAME: felt252 = 111; const SYMBOL: felt252 = 222; const URI: felt252 = 333; const TOKEN_ID: u256 = 7; +const PUBKEY: felt252 = 444; fn ZERO() -> ContractAddress { Zeroable::zero() @@ -52,9 +55,9 @@ fn DATA(success: bool) -> Span { data.span() } -/// -/// Setup -/// +// +// Setup +// fn setup() { ERC721::initializer(NAME, SYMBOL); @@ -65,16 +68,25 @@ fn setup_receiver() -> ContractAddress { utils::deploy(ERC721Receiver::TEST_CLASS_HASH, ArrayTrait::new()) } +fn setup_camel_receiver() -> ContractAddress { + utils::deploy(CamelERC721ReceiverMock::TEST_CLASS_HASH, ArrayTrait::new()) +} + fn setup_account() -> ContractAddress { let mut calldata = ArrayTrait::new(); - let public_key: felt252 = 1234678; - calldata.append(public_key); + calldata.append(PUBKEY); utils::deploy(Account::TEST_CLASS_HASH, calldata) } -/// -/// Initializers -/// +fn setup_camel_account() -> ContractAddress { + let mut calldata = ArrayTrait::new(); + calldata.append(PUBKEY); + utils::deploy(CamelAccountMock::TEST_CLASS_HASH, calldata) +} + +// +// Initializers +// #[test] #[available_gas(2000000)] @@ -108,9 +120,9 @@ fn test_initialize() { assert(ERC721::supports_interface(src5::ISRC5_ID), 'missing interface ID'); } -/// -/// Getters -/// +// +// Getters +// #[test] #[available_gas(2000000)] @@ -185,9 +197,9 @@ fn test__exists() { assert(ERC721::_owners::read(token_id) == zero, 'Invalid owner'); } -/// -/// approve & _approve -/// +// +// approve & _approve +// #[test] #[available_gas(2000000)] @@ -264,9 +276,9 @@ fn test__approve_nonexistent() { ERC721::_approve(SPENDER(), TOKEN_ID); } -/// -/// set_approval_for_all & _set_approval_for_all -/// +// +// set_approval_for_all & _set_approval_for_all +// #[test] #[available_gas(2000000)] @@ -323,9 +335,9 @@ fn test__set_approval_for_all_owner_equal_operator_false() { ERC721::_set_approval_for_all(OWNER(), OWNER(), false); } -/// -/// transfer_from -/// +// +// transfer_from & transferFrom +// #[test] #[available_gas(2000000)] @@ -346,6 +358,25 @@ fn test_transfer_from_owner() { assert_state_after_transfer(token_id, owner, recipient); } +#[test] +#[available_gas(2000000)] +fn test_transferFrom_owner() { + setup(); + let token_id = TOKEN_ID; + let owner = OWNER(); + let recipient = RECIPIENT(); + // set approval to check reset + ERC721::_approve(OTHER(), token_id); + + assert_state_before_transfer(token_id, owner, recipient); + assert(ERC721::get_approved(token_id) == OTHER(), 'Approval not implicitly reset'); + + set_caller_address(owner); + ERC721::transferFrom(owner, recipient, token_id); + + assert_state_after_transfer(token_id, owner, recipient); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] @@ -353,6 +384,13 @@ fn test_transfer_from_nonexistent() { ERC721::transfer_from(ZERO(), RECIPIENT(), TOKEN_ID); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test_transferFrom_nonexistent() { + ERC721::transferFrom(ZERO(), RECIPIENT(), TOKEN_ID); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] @@ -363,6 +401,16 @@ fn test_transfer_from_to_zero() { ERC721::transfer_from(OWNER(), ZERO(), TOKEN_ID); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid receiver', ))] +fn test_transferFrom_to_zero() { + setup(); + + set_caller_address(OWNER()); + ERC721::transferFrom(OWNER(), ZERO(), TOKEN_ID); +} + #[test] #[available_gas(2000000)] fn test_transfer_from_to_owner() { @@ -378,6 +426,21 @@ fn test_transfer_from_to_owner() { assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner after'); } +#[test] +#[available_gas(2000000)] +fn test_transferFrom_to_owner() { + setup(); + + assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); + assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner before'); + + set_caller_address(OWNER()); + ERC721::transferFrom(OWNER(), OWNER(), TOKEN_ID); + + assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership after'); + assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner after'); +} + #[test] #[available_gas(2000000)] fn test_transfer_from_approved() { @@ -396,6 +459,24 @@ fn test_transfer_from_approved() { assert_state_after_transfer(token_id, owner, recipient); } +#[test] +#[available_gas(2000000)] +fn test_transferFrom_approved() { + setup(); + let token_id = TOKEN_ID; + let owner = OWNER(); + let recipient = RECIPIENT(); + assert_state_before_transfer(token_id, owner, recipient); + + set_caller_address(owner); + ERC721::approve(OPERATOR(), token_id); + + set_caller_address(OPERATOR()); + ERC721::transferFrom(owner, recipient, token_id); + + assert_state_after_transfer(token_id, owner, recipient); +} + #[test] #[available_gas(2000000)] fn test_transfer_from_approved_for_all() { @@ -415,6 +496,25 @@ fn test_transfer_from_approved_for_all() { assert_state_after_transfer(token_id, owner, recipient); } +#[test] +#[available_gas(2000000)] +fn test_transferFrom_approved_for_all() { + setup(); + let token_id = TOKEN_ID; + let owner = OWNER(); + let recipient = RECIPIENT(); + + assert_state_before_transfer(token_id, owner, recipient); + + set_caller_address(owner); + ERC721::set_approval_for_all(OPERATOR(), true); + + set_caller_address(OPERATOR()); + ERC721::transferFrom(owner, recipient, token_id); + + assert_state_after_transfer(token_id, owner, recipient); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: unauthorized caller', ))] @@ -425,8 +525,18 @@ fn test_transfer_from_unauthorized() { ERC721::transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: unauthorized caller', ))] +fn test_transferFrom_unauthorized() { + setup(); + + set_caller_address(OTHER()); + ERC721::transferFrom(OWNER(), RECIPIENT(), TOKEN_ID); +} + // -// safe_transfer_from +// safe_transfer_from & safeTransferFrom // #[test] @@ -445,6 +555,54 @@ fn test_safe_transfer_from_to_account() { assert_state_after_transfer(token_id, owner, account); } +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_to_account() { + setup(); + let account = setup_account(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, account); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, account, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, account); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_to_account_camel() { + setup(); + let account = setup_camel_account(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, account); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, account, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, account); +} + +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_to_account_camel() { + setup(); + let account = setup_camel_account(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, account); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, account, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, account); +} + #[test] #[available_gas(2000000)] fn test_safe_transfer_from_to_receiver() { @@ -461,6 +619,54 @@ fn test_safe_transfer_from_to_receiver() { assert_state_after_transfer(token_id, owner, receiver); } +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_to_receiver() { + setup(); + let receiver = setup_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_to_receiver_camel() { + setup(); + let receiver = setup_camel_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_to_receiver_camel() { + setup(); + let receiver = setup_camel_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: safe transfer failed', ))] @@ -474,6 +680,45 @@ fn test_safe_transfer_from_to_receiver_failure() { ERC721::safe_transfer_from(owner, receiver, token_id, DATA(false)); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: safe transfer failed', ))] +fn test_safeTransferFrom_to_receiver_failure() { + setup(); + let receiver = setup_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, receiver, token_id, DATA(false)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: safe transfer failed', ))] +fn test_safe_transfer_from_to_receiver_failure_camel() { + setup(); + let receiver = setup_camel_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, receiver, token_id, DATA(false)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: safe transfer failed', ))] +fn test_safeTransferFrom_to_receiver_failure_camel() { + setup(); + let receiver = setup_camel_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, receiver, token_id, DATA(false)); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] @@ -487,6 +732,19 @@ fn test_safe_transfer_from_to_non_receiver() { ERC721::safe_transfer_from(owner, recipient, token_id, DATA(true)); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_safeTransferFrom_to_non_receiver() { + setup(); + let recipient = utils::deploy(ERC721NonReceiver::TEST_CLASS_HASH, ArrayTrait::new()); + let token_id = TOKEN_ID; + let owner = OWNER(); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, recipient, token_id, DATA(true)); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] @@ -494,6 +752,13 @@ fn test_safe_transfer_from_nonexistent() { ERC721::safe_transfer_from(ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid token ID', ))] +fn test_safeTransferFrom_nonexistent() { + ERC721::safeTransferFrom(ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] @@ -504,6 +769,16 @@ fn test_safe_transfer_from_to_zero() { ERC721::safe_transfer_from(OWNER(), ZERO(), TOKEN_ID, DATA(true)); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: invalid receiver', ))] +fn test_safeTransferFrom_to_zero() { + setup(); + + set_caller_address(OWNER()); + ERC721::safeTransferFrom(OWNER(), ZERO(), TOKEN_ID, DATA(true)); +} + #[test] #[available_gas(2000000)] fn test_safe_transfer_from_to_owner() { @@ -522,6 +797,60 @@ fn test_safe_transfer_from_to_owner() { assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); } +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_to_owner() { + let token_id = TOKEN_ID; + let owner = setup_receiver(); + ERC721::initializer(NAME, SYMBOL); + ERC721::_mint(owner, token_id); + + assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, owner, token_id, DATA(true)); + + assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_to_owner_camel() { + let token_id = TOKEN_ID; + let owner = setup_camel_receiver(); + ERC721::initializer(NAME, SYMBOL); + ERC721::_mint(owner, token_id); + + assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); + + set_caller_address(owner); + ERC721::safe_transfer_from(owner, owner, token_id, DATA(true)); + + assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); +} + +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_to_owner_camel() { + let token_id = TOKEN_ID; + let owner = setup_camel_receiver(); + ERC721::initializer(NAME, SYMBOL); + ERC721::_mint(owner, token_id); + + assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); + + set_caller_address(owner); + ERC721::safeTransferFrom(owner, owner, token_id, DATA(true)); + + assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); + assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); +} + #[test] #[available_gas(2000000)] fn test_safe_transfer_from_approved() { @@ -541,6 +870,63 @@ fn test_safe_transfer_from_approved() { assert_state_after_transfer(token_id, owner, receiver); } +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_approved() { + setup(); + let receiver = setup_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::approve(OPERATOR(), token_id); + + set_caller_address(OPERATOR()); + ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_approved_camel() { + setup(); + let receiver = setup_camel_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::approve(OPERATOR(), token_id); + + set_caller_address(OPERATOR()); + ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_approved_camel() { + setup(); + let receiver = setup_camel_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::approve(OPERATOR(), token_id); + + set_caller_address(OPERATOR()); + ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + #[test] #[available_gas(2000000)] fn test_safe_transfer_from_approved_for_all() { @@ -560,6 +946,63 @@ fn test_safe_transfer_from_approved_for_all() { assert_state_after_transfer(token_id, owner, receiver); } +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_approved_for_all() { + setup(); + let receiver = setup_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::set_approval_for_all(OPERATOR(), true); + + set_caller_address(OPERATOR()); + ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +fn test_safe_transfer_from_approved_for_all_camel() { + setup(); + let receiver = setup_camel_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::set_approval_for_all(OPERATOR(), true); + + set_caller_address(OPERATOR()); + ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + +#[test] +#[available_gas(2000000)] +fn test_safeTransferFrom_approved_for_all_camel() { + setup(); + let receiver = setup_camel_receiver(); + let token_id = TOKEN_ID; + let owner = OWNER(); + + assert_state_before_transfer(token_id, owner, receiver); + + set_caller_address(owner); + ERC721::set_approval_for_all(OPERATOR(), true); + + set_caller_address(OPERATOR()); + ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + + assert_state_after_transfer(token_id, owner, receiver); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: unauthorized caller', ))] @@ -569,8 +1012,17 @@ fn test_safe_transfer_from_unauthorized() { ERC721::safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: unauthorized caller', ))] +fn test_safeTransferFrom_unauthorized() { + setup(); + set_caller_address(OTHER()); + ERC721::safeTransferFrom(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); +} + // -// __transfer +// _transfer // #[test] @@ -611,9 +1063,9 @@ fn test__transfer_from_invalid_owner() { ERC721::_transfer(RECIPIENT(), OWNER(), TOKEN_ID); } -/// -/// Mint -/// +// +// _mint +// #[test] #[available_gas(2000000)] @@ -641,9 +1093,9 @@ fn test__mint_already_exist() { ERC721::_mint(RECIPIENT(), TOKEN_ID); } -/// -/// _safe_mint -/// +// +// _safe_mint +// #[test] #[available_gas(2000000)] @@ -656,6 +1108,17 @@ fn test__safe_mint_to_receiver() { assert_state_after_mint(token_id, recipient); } +#[test] +#[available_gas(2000000)] +fn test__safe_mint_to_receiver_camel() { + let recipient = setup_camel_receiver(); + let token_id = TOKEN_ID; + + assert_state_before_mint(recipient); + ERC721::_safe_mint(recipient, token_id, DATA(true)); + assert_state_after_mint(token_id, recipient); +} + #[test] #[available_gas(2000000)] fn test__safe_mint_to_account() { @@ -667,6 +1130,17 @@ fn test__safe_mint_to_account() { assert_state_after_mint(token_id, account); } +#[test] +#[available_gas(2000000)] +fn test__safe_mint_to_account_camel() { + let account = setup_camel_account(); + let token_id = TOKEN_ID; + + assert_state_before_mint(account); + ERC721::_safe_mint(account, token_id, DATA(true)); + assert_state_after_mint(token_id, account); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] @@ -691,6 +1165,18 @@ fn test__safe_mint_to_receiver_failure() { assert_state_after_mint(token_id, recipient); } +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ERC721: safe mint failed', ))] +fn test__safe_mint_to_receiver_failure_camel() { + let recipient = setup_camel_receiver(); + let token_id = TOKEN_ID; + + assert_state_before_mint(recipient); + ERC721::_safe_mint(recipient, token_id, DATA(false)); + assert_state_after_mint(token_id, recipient); +} + #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] @@ -706,9 +1192,9 @@ fn test__safe_mint_already_exist() { ERC721::_safe_mint(RECIPIENT(), TOKEN_ID, DATA(true)); } -/// -/// Burn -/// +// +// _burn +// #[test] #[available_gas(2000000)] @@ -735,9 +1221,9 @@ fn test__burn_nonexistent() { ERC721::_burn(TOKEN_ID); } -/// -/// _set_token_uri -/// +// +// _set_token_uri +// #[test] #[available_gas(2000000)] diff --git a/src/openzeppelin/token/erc20/erc20.cairo b/src/openzeppelin/token/erc20/erc20.cairo index 3342742ba..f778a0d47 100644 --- a/src/openzeppelin/token/erc20/erc20.cairo +++ b/src/openzeppelin/token/erc20/erc20.cairo @@ -247,9 +247,9 @@ mod ERC20 { decrease_allowance(spender, subtractedValue) } - /// - /// Internals - /// + // + // Internals + // #[internal] fn initializer(name_: felt252, symbol_: felt252) { diff --git a/src/openzeppelin/token/erc721.cairo b/src/openzeppelin/token/erc721.cairo index 9b6c34399..0fab567a8 100644 --- a/src/openzeppelin/token/erc721.cairo +++ b/src/openzeppelin/token/erc721.cairo @@ -2,3 +2,4 @@ mod erc721; use erc721::ERC721; mod interface; mod dual721; +mod dual721_receiver; diff --git a/src/openzeppelin/token/erc721/dual721_receiver.cairo b/src/openzeppelin/token/erc721/dual721_receiver.cairo new file mode 100644 index 000000000..3dc682b87 --- /dev/null +++ b/src/openzeppelin/token/erc721/dual721_receiver.cairo @@ -0,0 +1,46 @@ +use array::ArrayTrait; +use starknet::ContractAddress; +use starknet::SyscallResultTrait; +use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::UnwrapAndCast; + +#[derive(Copy, Drop)] +struct DualCaseERC721Receiver { + contract_address: ContractAddress +} + +trait DualCaseERC721ReceiverTrait { + fn on_erc721_received( + self: @DualCaseERC721Receiver, + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + data: Span + ) -> felt252; +} + +impl DualCaseERC721ReceiverImpl of DualCaseERC721ReceiverTrait { + fn on_erc721_received( + self: @DualCaseERC721Receiver, + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + data: Span + ) -> felt252 { + let mut args = ArrayTrait::new(); + args.append_serde(operator); + args.append_serde(from); + args.append_serde(token_id); + args.append_serde(data); + + try_selector_with_fallback( + *self.contract_address, + selectors::on_erc721_received, + selectors::onERC721Received, + args.span() + ) + .unwrap_and_cast() + } +} diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/openzeppelin/token/erc721/erc721.cairo index 8f5f5088a..3cda6ff3f 100644 --- a/src/openzeppelin/token/erc721/erc721.cairo +++ b/src/openzeppelin/token/erc721/erc721.cairo @@ -55,25 +55,20 @@ trait ERC721ABI { #[contract] mod ERC721 { - // OZ modules use openzeppelin::account; - use openzeppelin::introspection::src5; - use openzeppelin::token::erc721; - - // Dispatchers use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; - use super::super::interface::ERC721ReceiverABIDispatcher; - use super::super::interface::ERC721ReceiverABIDispatcherTrait; + use openzeppelin::introspection::src5; + use openzeppelin::token::erc721; + use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; + use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; + use openzeppelin::utils::serde::SpanSerde; - // Other + use array::SpanTrait; + use option::OptionTrait; use starknet::ContractAddress; use starknet::get_caller_address; use zeroable::Zeroable; - use option::OptionTrait; - use array::SpanTrait; - use traits::Into; - use openzeppelin::utils::serde::SpanSerde; struct Storage { _name: felt252, @@ -462,8 +457,7 @@ mod ERC721 { if (DualCaseSRC5 { contract_address: to }.supports_interface(erc721::interface::IERC721_RECEIVER_ID)) { - // todo add casing fallback mechanism - ERC721ReceiverABIDispatcher { + DualCaseERC721Receiver { contract_address: to } .on_erc721_received( diff --git a/src/openzeppelin/token/erc721/interface.cairo b/src/openzeppelin/token/erc721/interface.cairo index 53292dd94..aa0acc454 100644 --- a/src/openzeppelin/token/erc721/interface.cairo +++ b/src/openzeppelin/token/erc721/interface.cairo @@ -58,12 +58,14 @@ trait ERC721ReceiverABI { ) -> felt252; } +#[abi] trait IERC721Receiver { fn on_erc721_received( operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span ) -> felt252; } +#[abi] trait IERC721ReceiverCamel { fn onERC721Received( operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span diff --git a/src/openzeppelin/utils/selectors.cairo b/src/openzeppelin/utils/selectors.cairo index 6541e28ab..ee89772f9 100644 --- a/src/openzeppelin/utils/selectors.cairo +++ b/src/openzeppelin/utils/selectors.cairo @@ -53,6 +53,14 @@ const safe_transfer_from: felt252 = 0x16f0218b33b5cf273196787d7cf139a9ad13d58e6674dcdce722b3bf8389863; const safeTransferFrom: felt252 = 0x19d59d013d4aa1a8b1ce4c8299086f070733b453c02d0dc46e735edc04d6444; +// +// ERC721Receiver +// + +const on_erc721_received: felt252 = + 0x38c7ee9f0855dfe219aea022b141d9b2ec0f6b68395d221c3f331c7ca4fb608; +const onERC721Received: felt252 = 0xfa119a8fafc6f1a02deb36fe5efbcc4929ef2021e50cf1cb6d1a780ccd009b; + // // ERC20 // From 65d03ae58c4aba9d1a9e9dc892ab132a2d1d9e1f Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 13 Jul 2023 20:41:41 +0200 Subject: [PATCH 064/124] Add owner param to ownable initializer (#660) * feat: add owner param to ownable initializer * feat: apply review updates * fix: remove unnecessary mut * Update src/openzeppelin/tests/access/test_dual_ownable.cairo Co-authored-by: Andrew Fleming --------- Co-authored-by: Andrew Fleming --- src/openzeppelin/access/ownable/ownable.cairo | 5 ++--- src/openzeppelin/tests/access/test_dual_ownable.cairo | 7 +++---- src/openzeppelin/tests/access/test_ownable.cairo | 2 +- src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo | 8 ++++---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/openzeppelin/access/ownable/ownable.cairo b/src/openzeppelin/access/ownable/ownable.cairo index 1027d4ca7..29e21dde0 100644 --- a/src/openzeppelin/access/ownable/ownable.cairo +++ b/src/openzeppelin/access/ownable/ownable.cairo @@ -71,9 +71,8 @@ mod Ownable { // Internals #[internal] - fn initializer() { - let caller: ContractAddress = get_caller_address(); - _transfer_ownership(caller); + fn initializer(owner: ContractAddress) { + _transfer_ownership(owner); } #[internal] diff --git a/src/openzeppelin/tests/access/test_dual_ownable.cairo b/src/openzeppelin/tests/access/test_dual_ownable.cairo index c093838fc..87841fe8d 100644 --- a/src/openzeppelin/tests/access/test_dual_ownable.cairo +++ b/src/openzeppelin/tests/access/test_dual_ownable.cairo @@ -17,6 +17,7 @@ use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnablePanicMock; use openzeppelin::tests::mocks::dual_ownable_mocks::CamelOwnablePanicMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils; +use openzeppelin::utils::serde::SerializedAppend; // // Constants @@ -36,14 +37,14 @@ fn NEW_OWNER() -> ContractAddress { fn setup_snake() -> (DualCaseOwnable, IOwnableDispatcher) { let mut calldata = ArrayTrait::new(); - set_caller_address(OWNER()); + calldata.append_serde(OWNER()); let target = utils::deploy(SnakeOwnableMock::TEST_CLASS_HASH, calldata); (DualCaseOwnable { contract_address: target }, IOwnableDispatcher { contract_address: target }) } fn setup_camel() -> (DualCaseOwnable, IOwnableCamelDispatcher) { let mut calldata = ArrayTrait::new(); - set_caller_address(OWNER()); + calldata.append_serde(OWNER()); let target = utils::deploy(CamelOwnableMock::TEST_CLASS_HASH, calldata); ( DualCaseOwnable { @@ -56,13 +57,11 @@ fn setup_camel() -> (DualCaseOwnable, IOwnableCamelDispatcher) { fn setup_non_ownable() -> DualCaseOwnable { let calldata = ArrayTrait::new(); - set_caller_address(OWNER()); let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); DualCaseOwnable { contract_address: target } } fn setup_ownable_panic() -> (DualCaseOwnable, DualCaseOwnable) { - set_caller_address(OWNER()); let snake_target = utils::deploy(SnakeOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); let camel_target = utils::deploy(CamelOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); ( diff --git a/src/openzeppelin/tests/access/test_ownable.cairo b/src/openzeppelin/tests/access/test_ownable.cairo index 7f3980699..a3a4f0af9 100644 --- a/src/openzeppelin/tests/access/test_ownable.cairo +++ b/src/openzeppelin/tests/access/test_ownable.cairo @@ -19,7 +19,7 @@ fn OTHER() -> ContractAddress { fn setup() { testing::set_caller_address(OWNER()); - Ownable::initializer(); + Ownable::initializer(OWNER()); } // diff --git a/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo b/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo index f84bc195e..407d63e3b 100644 --- a/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo +++ b/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo @@ -4,8 +4,8 @@ mod SnakeOwnableMock { use openzeppelin::access::ownable::Ownable; #[constructor] - fn constructor() { - Ownable::initializer(); + fn constructor(owner: ContractAddress) { + Ownable::initializer(owner); } #[view] @@ -30,8 +30,8 @@ mod CamelOwnableMock { use openzeppelin::access::ownable::Ownable; #[constructor] - fn constructor() { - Ownable::initializer(); + fn constructor(owner: ContractAddress) { + Ownable::initializer(owner); } #[view] From a863859f585bd5a7554c21b4ad2ea1ee36a2ceac Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Tue, 18 Jul 2023 21:56:06 +0200 Subject: [PATCH 065/124] Migrate SRC5 to Cairo 2 (#664) * feat: migrate files * feat: add interface.cairo * feat: apply review updates * refactor: improve readability --- Cargo.lock | 1020 +++++++++++------ Cargo.toml | 57 +- cairo | 2 +- src/openzeppelin/introspection.cairo | 1 + .../introspection/dual_src5.cairo | 4 +- .../introspection/interface.cairo | 11 + src/openzeppelin/introspection/src5.cairo | 60 +- src/openzeppelin/lib.cairo | 8 +- src/openzeppelin/tests.cairo | 12 +- .../access/test_dual_accesscontrol.cairo | 21 +- .../tests/access/test_dual_ownable.cairo | 14 +- .../tests/account/test_dual_account.cairo | 21 +- .../tests/introspection/test_dual_src5.cairo | 27 +- .../tests/introspection/test_src5.cairo | 27 +- src/openzeppelin/tests/mocks.cairo | 38 +- .../tests/mocks/non_implementing_mock.cairo | 9 +- src/openzeppelin/tests/mocks/src5_mocks.cairo | 42 +- .../tests/token/test_dual721.cairo | 14 +- .../tests/token/test_dual721_receiver.cairo | 21 +- src/openzeppelin/token/erc721/erc721.cairo | 9 +- src/openzeppelin/utils/serde.cairo | 16 - 21 files changed, 850 insertions(+), 584 deletions(-) create mode 100644 src/openzeppelin/introspection/interface.cairo diff --git a/Cargo.lock b/Cargo.lock index a5ca15c63..278c09912 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.3" @@ -22,6 +33,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "anyhow" version = "1.0.70" @@ -29,129 +55,139 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] -name = "ark-ff" -version = "0.3.0" +name = "ark-ec" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ - "ark-ff-asm 0.3.0", - "ark-ff-macros 0.3.0", - "ark-serialize 0.3.0", - "ark-std 0.3.0", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", "derivative", - "num-bigint", + "hashbrown 0.13.2", + "itertools 0.10.5", "num-traits 0.2.15", - "paste", - "rustc_version 0.3.3", "zeroize", ] [[package]] name = "ark-ff" -version = "0.4.0-alpha.7" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cf4b42c978bd9b967f6a2ba54a4cc57f34780f9d0cf86916f8f7e922b4f80fe" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" dependencies = [ - "ark-ff-asm 0.4.0-alpha.7", - "ark-ff-macros 0.4.0-alpha.7", - "ark-serialize 0.4.0-alpha.7", - "ark-std 0.4.0-alpha", + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", "derivative", - "digest 0.10.6", - "itertools", + "digest", + "itertools 0.10.5", "num-bigint", "num-traits 0.2.15", "paste", - "rustc_version 0.4.0", + "rustc_version", "zeroize", ] [[package]] name = "ark-ff-asm" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ "quote", "syn 1.0.103", ] [[package]] -name = "ark-ff-asm" -version = "0.4.0-alpha.7" +name = "ark-ff-macros" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ba0a3cf584a8ede533a1749b86040e9018cf752265fc39a71c69fe1fafaba5" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ + "num-bigint", + "num-traits 0.2.15", + "proc-macro2", "quote", "syn 1.0.103", ] [[package]] -name = "ark-ff-macros" -version = "0.3.0" +name = "ark-poly" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" dependencies = [ - "num-bigint", - "num-traits 0.2.15", - "quote", - "syn 1.0.103", + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", ] [[package]] -name = "ark-ff-macros" -version = "0.4.0-alpha.7" +name = "ark-secp256k1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9989a01ec42d2f31232796831077ef730d4cd0d0931f5ef6962a43ebddd215fa" +checksum = "4c02e954eaeb4ddb29613fee20840c2bbc85ca4396d53e33837e11905363c5f2" dependencies = [ - "num-bigint", - "num-traits 0.2.15", - "proc-macro2", - "quote", - "syn 1.0.103", + "ark-ec", + "ark-ff", + "ark-std", ] [[package]] -name = "ark-serialize" -version = "0.3.0" +name = "ark-secp256r1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" dependencies = [ - "ark-std 0.3.0", - "digest 0.9.0", + "ark-ec", + "ark-ff", + "ark-std", ] [[package]] name = "ark-serialize" -version = "0.4.0-alpha.7" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84aeb60f7c6792ae71e9e2225412ecd59d7c85cfec4183a8c497f2a3a4cdb36e" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-std 0.4.0-alpha", - "digest 0.10.6", + "ark-serialize-derive", + "ark-std", + "digest", "num-bigint", ] [[package]] -name = "ark-std" -version = "0.3.0" +name = "ark-serialize-derive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "num-traits 0.2.15", - "rand", + "proc-macro2", + "quote", + "syn 1.0.103", ] [[package]] name = "ark-std" -version = "0.4.0-alpha" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5b16d734e9b2e43886ff586755219df7fb9639cc04ab00c7e636708a5ba06a" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits 0.2.15", "rand", ] +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "ascii-canvas" version = "3.0.0" @@ -191,9 +227,9 @@ dependencies = [ [[package]] name = "auto_impl" -version = "0.5.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", "proc-macro2", @@ -215,9 +251,9 @@ checksum = "bc0455254eb5c6964c4545d8bac815e1a1be4f3afe0ae695ea539c12d728d44b" [[package]] name = "bincode" -version = "2.0.0-rc.2" +version = "2.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb50c5a2ef4b9b1e7ae73e3a73b52ea24b20312d629f9c4df28260b7ad2c3c4" +checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" dependencies = [ "serde", ] @@ -280,17 +316,34 @@ version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "bytes" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +[[package]] +name = "cairo-compile" +version = "2.0.2" +dependencies = [ + "anyhow", + "cairo-lang-compiler", + "cairo-lang-utils", + "clap", + "log", +] + [[package]] name = "cairo-felt" -version = "0.3.0-rc1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93dedd19b8edf685798f1f12e4e0ac21ac196ea5262c300783f69f3fa0cb28b" +checksum = "0f8de851723a7d13ed8b0b588a78ffa6b38d8e1f3eb4b6e71a96376510e5504a" dependencies = [ "lazy_static", "num-bigint", @@ -299,17 +352,33 @@ dependencies = [ "serde", ] +[[package]] +name = "cairo-format" +version = "2.0.2" +dependencies = [ + "anyhow", + "cairo-lang-formatter", + "cairo-lang-utils", + "clap", + "colored", + "ignore", + "log", +] + [[package]] name = "cairo-lang-casm" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-utils", "env_logger", "indoc", - "itertools", + "itertools 0.11.0", "num-bigint", "num-traits 0.2.15", + "parity-scale-codec", + "parity-scale-codec-derive", "pretty_assertions", + "schemars", "serde", "test-case", "test-log", @@ -318,7 +387,7 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "1.1.1" +version = "2.0.2" dependencies = [ "anyhow", "cairo-lang-defs", @@ -333,7 +402,6 @@ dependencies = [ "cairo-lang-sierra-generator", "cairo-lang-syntax", "cairo-lang-utils", - "clap", "log", "salsa", "smol_str", @@ -343,7 +411,7 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-proc-macros", "cairo-lang-utils", @@ -354,7 +422,7 @@ dependencies = [ [[package]] name = "cairo-lang-defs" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -364,9 +432,9 @@ dependencies = [ "cairo-lang-test-utils", "cairo-lang-utils", "env_logger", - "indexmap", + "indexmap 2.0.0", "indoc", - "itertools", + "itertools 0.11.0", "pretty_assertions", "salsa", "smol_str", @@ -375,14 +443,15 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "1.1.1" +version = "2.0.2" dependencies = [ + "cairo-lang-debug", "cairo-lang-filesystem", "cairo-lang-proc-macros", "cairo-lang-utils", "env_logger", "indoc", - "itertools", + "itertools 0.11.0", "pretty_assertions", "salsa", "test-log", @@ -390,21 +459,21 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-utils", "env_logger", "good_lp", - "indexmap", + "indexmap 2.0.0", "indoc", - "itertools", + "itertools 0.11.0", "test-case", "test-log", ] [[package]] name = "cairo-lang-filesystem" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -419,7 +488,7 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" -version = "1.1.1" +version = "2.0.2" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -427,11 +496,10 @@ dependencies = [ "cairo-lang-parser", "cairo-lang-syntax", "cairo-lang-utils", - "clap", "colored", "diffy", "ignore", - "itertools", + "itertools 0.11.0", "log", "pretty_assertions", "salsa", @@ -442,7 +510,7 @@ dependencies = [ [[package]] name = "cairo-lang-language-server" -version = "1.1.1" +version = "2.0.2" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -474,7 +542,7 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -489,9 +557,9 @@ dependencies = [ "cairo-lang-utils", "env_logger", "id-arena", - "indexmap", + "indexmap 2.0.0", "indoc", - "itertools", + "itertools 0.11.0", "log", "num-bigint", "num-traits 0.2.15", @@ -503,7 +571,7 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -513,7 +581,7 @@ dependencies = [ "cairo-lang-utils", "colored", "env_logger", - "itertools", + "itertools 0.11.0", "log", "num-bigint", "num-traits 0.2.15", @@ -527,7 +595,7 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -540,7 +608,8 @@ dependencies = [ "cairo-lang-utils", "env_logger", "indoc", - "itertools", + "itertools 0.11.0", + "num-bigint", "salsa", "serde_json", "smol_str", @@ -550,18 +619,19 @@ dependencies = [ [[package]] name = "cairo-lang-proc-macros" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-debug", "quote", - "syn 1.0.103", + "syn 2.0.26", ] [[package]] name = "cairo-lang-project" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-filesystem", + "cairo-lang-utils", "indoc", "serde", "smol_str", @@ -572,11 +642,13 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "1.1.1" +version = "2.0.2" dependencies = [ "anyhow", - "ark-ff 0.4.0-alpha.7", - "ark-std 0.3.0", + "ark-ff", + "ark-secp256k1", + "ark-secp256r1", + "ark-std", "cairo-felt", "cairo-lang-casm", "cairo-lang-compiler", @@ -590,11 +662,11 @@ dependencies = [ "cairo-lang-sierra-gas", "cairo-lang-sierra-generator", "cairo-lang-sierra-to-casm", + "cairo-lang-sierra-type-size", "cairo-lang-starknet", "cairo-lang-utils", "cairo-vm", - "clap", - "itertools", + "itertools 0.11.0", "keccak", "num-bigint", "num-integer", @@ -607,7 +679,7 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "1.1.1" +version = "2.0.2" dependencies = [ "assert_matches", "cairo-lang-debug", @@ -623,7 +695,7 @@ dependencies = [ "env_logger", "id-arena", "indoc", - "itertools", + "itertools 0.11.0", "log", "num-bigint", "num-traits 0.2.15", @@ -636,7 +708,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "1.1.1" +version = "2.0.2" dependencies = [ "assert_matches", "bimap", @@ -646,7 +718,7 @@ dependencies = [ "derivative", "env_logger", "indoc", - "itertools", + "itertools 0.11.0", "lalrpop", "lalrpop-util", "num-bigint", @@ -664,14 +736,15 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", + "cairo-lang-sierra-type-size", "cairo-lang-utils", "env_logger", "indoc", - "itertools", + "itertools 0.11.0", "test-case", "test-log", "thiserror", @@ -679,15 +752,16 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", + "cairo-lang-sierra-type-size", "cairo-lang-test-utils", "cairo-lang-utils", "env_logger", "indoc", - "itertools", + "itertools 0.11.0", "pretty_assertions", "test-case", "test-log", @@ -696,7 +770,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -713,9 +787,9 @@ dependencies = [ "cairo-lang-utils", "env_logger", "id-arena", - "indexmap", + "indexmap 2.0.0", "indoc", - "itertools", + "itertools 0.11.0", "log", "num-bigint", "pretty_assertions", @@ -727,20 +801,19 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "1.1.1" +version = "2.0.2" dependencies = [ - "anyhow", "assert_matches", "cairo-felt", "cairo-lang-casm", "cairo-lang-sierra", "cairo-lang-sierra-ap-change", "cairo-lang-sierra-gas", + "cairo-lang-sierra-type-size", "cairo-lang-utils", - "clap", "env_logger", "indoc", - "itertools", + "itertools 0.11.0", "log", "num-bigint", "num-traits 0.2.15", @@ -750,9 +823,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cairo-lang-sierra-type-size" +version = "2.0.2" +dependencies = [ + "cairo-lang-sierra", + "cairo-lang-utils", +] + [[package]] name = "cairo-lang-starknet" -version = "1.1.1" +version = "2.0.2" dependencies = [ "anyhow", "cairo-felt", @@ -773,12 +854,12 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-test-utils", "cairo-lang-utils", - "clap", "convert_case", "env_logger", "genco", + "indent", "indoc", - "itertools", + "itertools 0.11.0", "log", "num-bigint", "num-integer", @@ -796,7 +877,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -814,19 +895,17 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "1.1.1" +version = "2.0.2" dependencies = [ - "cairo-lang-utils", "env_logger", "genco", - "log", "test-log", "xshell", ] [[package]] name = "cairo-lang-test-runner" -version = "1.1.1" +version = "2.0.2" dependencies = [ "anyhow", "cairo-felt", @@ -848,9 +927,8 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-utils", "cairo-vm", - "clap", "colored", - "itertools", + "itertools 0.11.0", "num-bigint", "num-traits 0.2.15", "rayon", @@ -860,7 +938,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-utils" -version = "1.1.1" +version = "2.0.2" dependencies = [ "cairo-lang-utils", "env_logger", @@ -871,15 +949,17 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "1.1.1" +version = "2.0.2" dependencies = [ "env_logger", - "indexmap", - "itertools", + "indexmap 2.0.0", + "itertools 0.11.0", "log", "num-bigint", "num-integer", "num-traits 0.2.15", + "parity-scale-codec", + "schemars", "serde", "serde_json", "test-case", @@ -888,27 +968,52 @@ dependencies = [ ] [[package]] -name = "cairo-take_until_unbalanced" -version = "0.24.2-rc1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e174056df7cfe9b579376f32de405722e1090c74deb2540bb0cd9e7931772d" +name = "cairo-language-server" +version = "2.0.2" dependencies = [ - "nom", + "cairo-lang-language-server", + "cairo-lang-utils", + "log", + "tokio", +] + +[[package]] +name = "cairo-run" +version = "2.0.2" +dependencies = [ + "anyhow", + "cairo-lang-compiler", + "cairo-lang-diagnostics", + "cairo-lang-runner", + "cairo-lang-sierra", + "cairo-lang-sierra-generator", + "cairo-lang-starknet", + "cairo-lang-utils", + "clap", +] + +[[package]] +name = "cairo-test" +version = "2.0.2" +dependencies = [ + "anyhow", + "cairo-lang-compiler", + "cairo-lang-test-runner", + "clap", ] [[package]] name = "cairo-vm" -version = "0.3.0-rc1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f4af8c3e7be5ac46b7da4a3ab551ee4c8c8e2fdb501a4dda4dceef4c66dbcde" +checksum = "656c25c13b6ffcc75e081292f3c23f27e429b3d4b8d69ecdc327a441798e91f4" dependencies = [ "anyhow", "bincode", "bitvec", "cairo-felt", - "cairo-take_until_unbalanced", "generic-array", - "hashbrown 0.13.2", + "hashbrown 0.14.0", "hex", "keccak", "lazy_static", @@ -916,15 +1021,14 @@ dependencies = [ "nom", "num-bigint", "num-integer", + "num-prime", "num-traits 0.2.15", - "rand_core", + "rand", "serde", - "serde_bytes", "serde_json", "sha2", "sha3", "starknet-crypto", - "thiserror", "thiserror-no-std", ] @@ -1072,9 +1176,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.4.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array", "subtle", @@ -1101,41 +1205,6 @@ dependencies = [ "syn 1.0.103", ] -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.103", -] - -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.103", -] - [[package]] name = "dashmap" version = "5.4.0" @@ -1160,37 +1229,6 @@ dependencies = [ "syn 1.0.103", ] -[[package]] -name = "derive_builder" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "derive_builder_macro" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" -dependencies = [ - "derive_builder_core", - "syn 1.0.103", -] - [[package]] name = "diff" version = "0.1.13" @@ -1208,18 +1246,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -1247,6 +1276,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dyn-clone" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" + [[package]] name = "either" version = "1.8.0" @@ -1264,17 +1299,23 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "atty", "humantime", + "is-terminal", "log", "regex", "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.2.8" @@ -1440,11 +1481,20 @@ dependencies = [ "syn 1.0.103", ] +[[package]] +name = "generate-syntax" +version = "2.0.2" +dependencies = [ + "cairo-lang-syntax-codegen", + "cairo-lang-utils", + "log", +] + [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1452,9 +1502,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -1463,13 +1513,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "globset" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bstr", "fnv", "log", @@ -1491,6 +1547,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] [[package]] name = "hashbrown" @@ -1498,7 +1557,17 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash", + "ahash 0.8.3", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash 0.8.3", + "allocator-api2", "serde", ] @@ -1544,7 +1613,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest", ] [[package]] @@ -1565,12 +1634,6 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "0.3.0" @@ -1598,6 +1661,23 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + +[[package]] +name = "indent" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f1a0777d972970f204fdf8ef319f1f4f8459131636d7e3c96c5d59570d0fa6" + [[package]] name = "indexmap" version = "1.9.2" @@ -1609,6 +1689,17 @@ dependencies = [ "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", + "serde", +] + [[package]] name = "indoc" version = "2.0.1" @@ -1656,6 +1747,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.4" @@ -1673,25 +1773,25 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" dependencies = [ "cpufeatures", ] [[package]] name = "lalrpop" -version = "0.19.9" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" dependencies = [ "ascii-canvas", "bit-set", "diff", "ena", "is-terminal", - "itertools", + "itertools 0.10.5", "lalrpop-util", "petgraph", "pico-args", @@ -1705,9 +1805,9 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.19.9" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c1f7869c94d214466c5fd432dfed12c379fd87786768d36455892d46b18edd" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" dependencies = [ "regex", ] @@ -1723,15 +1823,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.137" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libmimalloc-sys" -version = "0.1.28" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d1c67deb83e6b75fa4fe3309e09cfeade12e7721d95322af500d3814ea60c9" +checksum = "f4ac0e912c8ef1b735e92369695618dc5b1819f5a7bf3f167301a3ba1cea515e" dependencies = [ "cc", "libc", @@ -1762,11 +1862,20 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lru" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +dependencies = [ + "hashbrown 0.12.3", +] + [[package]] name = "lsp-types" -version = "0.93.2" +version = "0.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51" +checksum = "0b63735a13a1f9cd4f4835223d828ed9c2e35c8c5e61837774399f558b6a1237" dependencies = [ "bitflags", "serde", @@ -1801,9 +1910,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.32" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2374e2999959a7b583e1811a1ddbf1d3a4b9496eceb9746f1192a59d871eca" +checksum = "4e2894987a3459f3ffb755608bd82188f8ed00d0ae077f1edea29c068d639d98" dependencies = [ "libmimalloc-sys", ] @@ -1884,6 +1993,7 @@ dependencies = [ "autocfg", "num-integer", "num-traits 0.2.15", + "rand", "serde", ] @@ -1907,6 +2017,33 @@ dependencies = [ "num-traits 0.2.15", ] +[[package]] +name = "num-modular" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits 0.2.15", +] + +[[package]] +name = "num-prime" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4e3bc495f6e95bc15a6c0c55ac00421504a5a43d09e3cc455d1fea7015581d" +dependencies = [ + "bitvec", + "either", + "lru", + "num-bigint", + "num-integer", + "num-modular", + "num-traits 0.2.15", + "rand", +] + [[package]] name = "num-traits" version = "0.1.43" @@ -1977,6 +2114,31 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parity-scale-codec" +version = "3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756d439303e94fae44f288ba881ad29670c65b0c4b0e05674ca81061bb65f2c5" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d884d78fcf214d70b1e239fcd1c6e5e95aa3be1881918da2e488cc946c7a476" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.103", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -2033,9 +2195,9 @@ checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[package]] name = "path-clean" -version = "0.1.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" [[package]] name = "percent-encoding" @@ -2043,16 +2205,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" -[[package]] -name = "pest" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" -dependencies = [ - "thiserror", - "ucd-trie", -] - [[package]] name = "petgraph" version = "0.6.2" @@ -2060,7 +2212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.2", ] [[package]] @@ -2074,9 +2226,9 @@ dependencies = [ [[package]] name = "pico-args" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" @@ -2134,6 +2286,16 @@ dependencies = [ "yansi", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2160,18 +2322,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -2188,6 +2350,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", "rand_chacha", "rand_core", ] @@ -2207,6 +2370,9 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] name = "rawpointer" @@ -2258,61 +2424,75 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick 1.0.2", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.2", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "relative-path" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df32d82cedd1499386877b062ebe8721f806de80b08d183c70184ef17dd1d42" +checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" [[package]] name = "rfc6979" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "crypto-bigint", "hmac", - "zeroize", + "subtle", ] [[package]] name = "rstest" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07f2d176c472198ec1e6551dc7da28f1c089652f66a7b722676c2238ebc0edf" +checksum = "2b96577ca10cb3eade7b337eb46520108a67ca2818a24d0b63f41fd62bc9651c" dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version 0.4.0", + "rustc_version", ] [[package]] name = "rstest_macros" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7" +checksum = "225e674cf31712b8bb15fdbca3ec0c1b9d825c5a24407ff2b7e005fb6a29ba03" dependencies = [ "cfg-if", + "glob", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 1.0.103", + "regex", + "relative-path", + "rustc_version", + "syn 2.0.26", "unicode-ident", ] @@ -2322,22 +2502,13 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.17", + "semver", ] [[package]] @@ -2373,7 +2544,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b84d9f96071f3f3be0dc818eae3327625d8ebc95b58da37d6850724f31d3403" dependencies = [ "crossbeam-utils", - "indexmap", + "indexmap 1.9.2", "lock_api", "log", "oorandom", @@ -2406,33 +2577,48 @@ dependencies = [ [[package]] name = "scarb-metadata" -version = "1.0.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2480a9a896395a1414feebcfe8550b35f4dce0e6a437eeaa0c3d79ec938ddf42" +checksum = "26ba10c59bd4ebde82de954e3a3d6d503eb17bd634106ef144af1356b28b8f0f" dependencies = [ "camino", - "derive_builder", - "semver 1.0.17", + "semver", "serde", "serde_json", "thiserror", ] [[package]] -name = "scopeguard" -version = "1.1.0" +name = "schemars" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +dependencies = [ + "dyn-clone", + "indexmap 1.9.2", + "schemars_derive", + "serde", + "serde_json", +] [[package]] -name = "semver" -version = "0.11.0" +name = "schemars_derive" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ - "semver-parser", + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.103", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "semver" version = "1.0.17" @@ -2442,49 +2628,42 @@ dependencies = [ "serde", ] -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - [[package]] name = "serde" -version = "1.0.158" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] -name = "serde_bytes" -version = "0.11.9" +name = "serde_derive" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ - "serde", + "proc-macro2", + "quote", + "syn 2.0.26", ] [[package]] -name = "serde_derive" -version = "1.0.158" +name = "serde_derive_internals" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.3", + "syn 1.0.103", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -2502,27 +2681,49 @@ dependencies = [ "syn 1.0.103", ] +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest", ] [[package]] name = "sha3" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.6", + "digest", "keccak", ] +[[package]] +name = "sierra-compile" +version = "2.0.2" +dependencies = [ + "anyhow", + "cairo-lang-sierra", + "cairo-lang-sierra-to-casm", + "cairo-lang-utils", + "clap", + "indoc", + "log", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -2589,11 +2790,21 @@ dependencies = [ "num-traits 0.1.43", ] +[[package]] +name = "starknet-compile" +version = "2.0.2" +dependencies = [ + "anyhow", + "cairo-lang-compiler", + "cairo-lang-starknet", + "clap", +] + [[package]] name = "starknet-crypto" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d49eb65d58fa98a164ad2cd4d04775885386b83bdad6060f168a38ede77c9aed" +checksum = "693e6362f150f9276e429a910481fb7f3bcb8d6aa643743f587cfece0b374874" dependencies = [ "crypto-bigint", "hex", @@ -2604,43 +2815,65 @@ dependencies = [ "rfc6979", "sha2", "starknet-crypto-codegen", - "starknet-curve", + "starknet-curve 0.3.0", "starknet-ff", "zeroize", ] [[package]] name = "starknet-crypto-codegen" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" +dependencies = [ + "starknet-curve 0.4.0", + "starknet-ff", + "syn 2.0.26", +] + +[[package]] +name = "starknet-curve" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff08f74f3ac785ac34ac05c68c5bd4df280107ab35df69dbcbde35183d89eba" +checksum = "252610baff59e4c4332ce3569f7469c5d3f9b415a2240d698fb238b2b4fc0942" dependencies = [ - "starknet-curve", "starknet-ff", - "syn 1.0.103", ] [[package]] name = "starknet-curve" -version = "0.2.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0dbde7ef14d54c2117bc6d2efb68c2383005f1cd749b277c11df874d07b7af" +checksum = "a68a0d87ae56572abf83ddbfd44259a7c90dbeeee1629a1ffe223e7f9a8f3052" dependencies = [ "starknet-ff", ] [[package]] name = "starknet-ff" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78d484109da192f3a8cd58f674861c2d5e4b3e1765a466362c6f350ef213dfd1" +checksum = "db2cb1d9c0a50380cddab99cb202c6bfb3332728a2769bd0ca2ee80b0b390dd4" dependencies = [ - "ark-ff 0.3.0", + "ark-ff", "crypto-bigint", "getrandom", "hex", ] +[[package]] +name = "starknet-sierra-compile" +version = "2.0.2" +dependencies = [ + "anyhow", + "cairo-lang-sierra", + "cairo-lang-starknet", + "cairo-lang-utils", + "clap", + "serde", + "serde_json", +] + [[package]] name = "string_cache" version = "0.8.4" @@ -2679,9 +2912,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.3" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -2728,18 +2961,18 @@ dependencies = [ [[package]] name = "test-case" -version = "2.2.2" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21d6cf5a7dffb3f9dceec8e6b8ca528d9bd71d36c9f074defb548ce161f598c0" +checksum = "2a1d6e7bde536b0412f20765b76e921028059adfd1b90d8974d33fd3c91b25df" dependencies = [ "test-case-macros", ] [[package]] -name = "test-case-macros" -version = "2.2.2" +name = "test-case-core" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45b7bf6e19353ddd832745c8fcf77a17a93171df7151187f26623f2b75b5b26" +checksum = "d10394d5d1e27794f772b6fc854c7e91a2dc26e2cbf807ad523370c2a59c0cee" dependencies = [ "cfg-if", "proc-macro-error", @@ -2748,6 +2981,19 @@ dependencies = [ "syn 1.0.103", ] +[[package]] +name = "test-case-macros" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb9a44b1c6a54c1ba58b152797739dba2a83ca74e18168a68c980eb142f9404" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.103", + "test-case-core", +] + [[package]] name = "test-log" version = "0.2.11" @@ -2761,7 +3007,7 @@ dependencies = [ [[package]] name = "tests" -version = "1.1.1" +version = "2.0.2" dependencies = [ "assert_matches", "cairo-felt", @@ -2783,7 +3029,7 @@ dependencies = [ "cairo-lang-test-utils", "cairo-lang-utils", "env_logger", - "itertools", + "itertools 0.11.0", "log", "num-bigint", "once_cell", @@ -2811,7 +3057,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.3", + "syn 2.0.26", ] [[package]] @@ -2943,11 +3189,36 @@ dependencies = [ [[package]] name = "toml" -version = "0.4.10" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ + "indexmap 2.0.0", "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -2972,9 +3243,9 @@ checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] name = "tower-lsp" -version = "0.17.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e094780b4447366c59f79acfd65b1375ecaa84e61dddbde1421aa506334024" +checksum = "9b38fb0e6ce037835174256518aace3ca621c4f96383c56bb846cfc11b341910" dependencies = [ "async-trait", "auto_impl", @@ -2982,7 +3253,6 @@ dependencies = [ "dashmap", "futures", "httparse", - "log", "lsp-types", "memchr", "serde", @@ -2991,13 +3261,14 @@ dependencies = [ "tokio-util", "tower", "tower-lsp-macros", + "tracing", ] [[package]] name = "tower-lsp-macros" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebd99eec668d0a450c177acbc4d05e0d0d13b1f8d3db13cd706c52cbec4ac04" +checksum = "34723c06344244474fdde365b76aebef8050bf6be61a935b91ee9ff7c4e91157" dependencies = [ "proc-macro2", "quote", @@ -3018,9 +3289,21 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.26", +] + [[package]] name = "tracing-core" version = "0.1.30" @@ -3036,12 +3319,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[package]] -name = "ucd-trie" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" - [[package]] name = "unescaper" version = "0.1.1" @@ -3285,6 +3562,15 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "winnow" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" +dependencies = [ + "memchr", +] + [[package]] name = "wyz" version = "0.5.1" @@ -3317,9 +3603,9 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 3927b6991..753694083 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,6 @@ +[profile.release] +overflow-checks = true # Enable integer overflow checks. + [workspace] members = [ @@ -22,16 +25,26 @@ members = [ "cairo/crates/cairo-lang-sierra-gas", "cairo/crates/cairo-lang-sierra-generator", "cairo/crates/cairo-lang-sierra-to-casm", + "cairo/crates/cairo-lang-sierra-type-size", "cairo/crates/cairo-lang-starknet", "cairo/crates/cairo-lang-syntax", "cairo/crates/cairo-lang-syntax-codegen", "cairo/crates/cairo-lang-test-runner", "cairo/crates/cairo-lang-utils", + "cairo/crates/bin/cairo-language-server", + "cairo/crates/bin/cairo-compile", + "cairo/crates/bin/cairo-format", + "cairo/crates/bin/cairo-test", + "cairo/crates/bin/cairo-run", + "cairo/crates/bin/sierra-compile", + "cairo/crates/bin/starknet-compile", + "cairo/crates/bin/starknet-sierra-compile", + "cairo/crates/bin/generate-syntax", "cairo/tests", ] [workspace.package] -version = "1.1.1" +version = "2.0.2" edition = "2021" repository = "https://github.com/starkware-libs/cairo/" license = "Apache-2.0" @@ -40,53 +53,63 @@ license-file = "LICENSE" [workspace.dependencies] anyhow = "1.0.66" ark-ff = "0.4.0-alpha.7" -ark-std = "0.3.0" +ark-secp256k1 = "0.4.0" +ark-secp256r1 = "0.4.0" +ark-std = "0.4.0" assert_matches = "1.5" bimap = "0.6.2" -cairo-felt = "0.3.0-rc1" -cairo-vm = "0.3.0-rc1" +cairo-felt = "0.8.2" +cairo-vm = "0.8.2" clap = { version = "4.0", features = ["derive"] } colored = "2" const-fnv1a-hash = "1.1.0" convert_case = "0.6.0" derivative = "2.2.0" diffy = "0.3.0" -env_logger = "0.9.3" +env_logger = "0.10.0" genco = "0.17.0" good_lp = { version = "1.3.2", features = ["minilp"], default-features = false } id-arena = "2.2.1" ignore = "0.4.20" -indexmap = { version = "1.9.1", features = ["serde"] } +indent = "0.1.1" +indexmap = { version = "2.0.0", features = ["serde"] } indoc = "2.0.1" -itertools = "0.10.3" +itertools = "0.11.0" keccak = "0.1.3" -lalrpop-util = { version = "0.19.9", features = ["lexer"] } +lalrpop-util = { version = "0.20.0", features = ["lexer"] } log = "0.4" -lsp = { version = "0.93", package = "lsp-types" } +lsp = { version = "0.94", package = "lsp-types" } num-bigint = "0.4" num-integer = "0.1" num-traits = "0.2" once_cell = "1.17.1" -path-clean = "0.1.0" +parity-scale-codec = "3.5.0" +parity-scale-codec-derive = "3.1.4" +path-clean = "1.0.1" pretty_assertions = "1.2.1" proc-macro2 = "1.0" quote = "1.0.21" rayon = "1.7.0" -rstest = "0.16.0" +rstest = "0.18.1" salsa = "0.16.1" -scarb-metadata = "1.0.1" +scarb-metadata = "1.4.2" +schemars = { version = "0.8.12", features = ["preserve_order"] } serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0" sha3 = "0.10.6" smol_str = { version = "0.2.0", features = ["serde"] } -syn = { version = "1.0.99", features = ["full", "extra-traits"] } -test-case = "2.2.2" +syn = { version = "2.0.25", features = ["full", "extra-traits"] } +test-case = "3.1.0" test-case-macros = "2.2.2" test-log = "0.2.11" thiserror = "1.0.32" -time = { version = "0.3.20", features = ["formatting", "macros", "local-offset"] } +time = { version = "0.3.20", features = [ + "formatting", + "macros", + "local-offset", +] } tokio = { version = "1.18.2", features = ["full", "sync"] } -toml = "0.4.2" -tower-lsp = "0.17.0" +toml = "0.7.6" +tower-lsp = "0.19.0" unescaper = "0.1.1" xshell = "0.2.2" diff --git a/cairo b/cairo index c6b003cc4..06722bd86 160000 --- a/cairo +++ b/cairo @@ -1 +1 @@ -Subproject commit c6b003cc425907ac5fc846375a48737d5125f5b5 +Subproject commit 06722bd868b675500f61e87125cc5db519592e63 diff --git a/src/openzeppelin/introspection.cairo b/src/openzeppelin/introspection.cairo index 0819e4257..184f921e7 100644 --- a/src/openzeppelin/introspection.cairo +++ b/src/openzeppelin/introspection.cairo @@ -1,2 +1,3 @@ mod src5; mod dual_src5; +mod interface; diff --git a/src/openzeppelin/introspection/dual_src5.cairo b/src/openzeppelin/introspection/dual_src5.cairo index f693aac45..ca6868cae 100644 --- a/src/openzeppelin/introspection/dual_src5.cairo +++ b/src/openzeppelin/introspection/dual_src5.cairo @@ -2,7 +2,6 @@ use array::ArrayTrait; use starknet::ContractAddress; use openzeppelin::utils::selectors; -use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::try_selector_with_fallback; use openzeppelin::utils::UnwrapAndCast; @@ -17,8 +16,7 @@ trait DualCaseSRC5Trait { impl DualCaseSRC5Impl of DualCaseSRC5Trait { fn supports_interface(self: @DualCaseSRC5, interface_id: felt252) -> bool { - let mut args = ArrayTrait::new(); - args.append_serde(interface_id); + let mut args = array![interface_id]; try_selector_with_fallback( *self.contract_address, diff --git a/src/openzeppelin/introspection/interface.cairo b/src/openzeppelin/introspection/interface.cairo new file mode 100644 index 000000000..68909245c --- /dev/null +++ b/src/openzeppelin/introspection/interface.cairo @@ -0,0 +1,11 @@ +const ISRC5_ID: felt252 = 0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055; + +#[starknet::interface] +trait ISRC5 { + fn supports_interface(self: @TState, interface_id: felt252) -> bool; +} + +#[starknet::interface] +trait ISRC5Camel { + fn supportsInterface(self: @TState, interfaceId: felt252) -> bool; +} diff --git a/src/openzeppelin/introspection/src5.cairo b/src/openzeppelin/introspection/src5.cairo index 2b0384098..2f9a9389e 100644 --- a/src/openzeppelin/introspection/src5.cairo +++ b/src/openzeppelin/introspection/src5.cairo @@ -1,56 +1,38 @@ -const ISRC5_ID: felt252 = 0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055; - -#[abi] -trait ISRC5 { - fn supports_interface(interface_id: felt252) -> bool; -} - -#[abi] -trait ISRC5Camel { - fn supportsInterface(interfaceId: felt252) -> bool; -} - -#[contract] +#[starknet::contract] mod SRC5 { - use openzeppelin::introspection::src5; + use openzeppelin::introspection::interface; + #[storage] struct Storage { supported_interfaces: LegacyMap } - impl SRC5Impl of src5::ISRC5 { - fn supports_interface(interface_id: felt252) -> bool { - if interface_id == src5::ISRC5_ID { + #[external(v0)] + impl SRC5Impl of interface::ISRC5 { + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + if interface_id == interface::ISRC5_ID { return true; } - supported_interfaces::read(interface_id) + self.supported_interfaces.read(interface_id) } } - impl SRC5CamelImpl of src5::ISRC5Camel { - fn supportsInterface(interfaceId: felt252) -> bool { - SRC5Impl::supports_interface(interfaceId) + #[external(v0)] + impl SRC5CamelImpl of interface::ISRC5Camel { + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + SRC5Impl::supports_interface(self, interfaceId) } } - #[view] - fn supports_interface(interface_id: felt252) -> bool { - SRC5Impl::supports_interface(interface_id) - } - - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - SRC5CamelImpl::supportsInterface(interfaceId) - } - - #[internal] - fn register_interface(interface_id: felt252) { - supported_interfaces::write(interface_id, true); - } + #[generate_trait] + impl InternalImpl of InternalTrait { + fn register_interface(ref self: ContractState, interface_id: felt252) { + self.supported_interfaces.write(interface_id, true); + } - #[internal] - fn deregister_interface(interface_id: felt252) { - assert(interface_id != src5::ISRC5_ID, 'SRC5: invalid id'); - supported_interfaces::write(interface_id, false); + fn deregister_interface(ref self: ContractState, interface_id: felt252) { + assert(interface_id != interface::ISRC5_ID, 'SRC5: invalid id'); + self.supported_interfaces.write(interface_id, false); + } } } diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 47d73c605..03d22fd58 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,7 +1,7 @@ -mod access; +// mod access; mod introspection; -mod security; -mod account; -mod token; +// mod security; +// mod account; +// mod token; mod tests; mod utils; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 0110b5abc..7f8a46378 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,9 +1,9 @@ -mod access; -mod test_reentrancyguard; +// mod access; +// mod test_reentrancyguard; mod introspection; -mod account; -mod token; -mod test_initializable; -mod test_pausable; +// mod account; +// mod token; +// mod test_initializable; +// mod test_pausable; mod mocks; mod utils; diff --git a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo index 83908f95d..7a229576e 100644 --- a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo +++ b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo @@ -42,11 +42,8 @@ fn setup_snake() -> (DualCaseAccessControl, IAccessControlDispatcher) { calldata.append_serde(ADMIN()); let target = utils::deploy(SnakeAccessControlMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccessControl { - contract_address: target - }, IAccessControlDispatcher { - contract_address: target - } + DualCaseAccessControl { contract_address: target }, + IAccessControlDispatcher { contract_address: target } ) } @@ -55,11 +52,8 @@ fn setup_camel() -> (DualCaseAccessControl, IAccessControlCamelDispatcher) { calldata.append_serde(ADMIN()); let target = utils::deploy(CamelAccessControlMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccessControl { - contract_address: target - }, IAccessControlCamelDispatcher { - contract_address: target - } + DualCaseAccessControl { contract_address: target }, + IAccessControlCamelDispatcher { contract_address: target } ) } @@ -77,11 +71,8 @@ fn setup_accesscontrol_panic() -> (DualCaseAccessControl, DualCaseAccessControl) CamelAccessControlPanicMock::TEST_CLASS_HASH, ArrayTrait::new() ); ( - DualCaseAccessControl { - contract_address: snake_target - }, DualCaseAccessControl { - contract_address: camel_target - } + DualCaseAccessControl { contract_address: snake_target }, + DualCaseAccessControl { contract_address: camel_target } ) } diff --git a/src/openzeppelin/tests/access/test_dual_ownable.cairo b/src/openzeppelin/tests/access/test_dual_ownable.cairo index 87841fe8d..aa86d3874 100644 --- a/src/openzeppelin/tests/access/test_dual_ownable.cairo +++ b/src/openzeppelin/tests/access/test_dual_ownable.cairo @@ -47,11 +47,8 @@ fn setup_camel() -> (DualCaseOwnable, IOwnableCamelDispatcher) { calldata.append_serde(OWNER()); let target = utils::deploy(CamelOwnableMock::TEST_CLASS_HASH, calldata); ( - DualCaseOwnable { - contract_address: target - }, IOwnableCamelDispatcher { - contract_address: target - } + DualCaseOwnable { contract_address: target }, + IOwnableCamelDispatcher { contract_address: target } ) } @@ -65,11 +62,8 @@ fn setup_ownable_panic() -> (DualCaseOwnable, DualCaseOwnable) { let snake_target = utils::deploy(SnakeOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); let camel_target = utils::deploy(CamelOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); ( - DualCaseOwnable { - contract_address: snake_target - }, DualCaseOwnable { - contract_address: camel_target - } + DualCaseOwnable { contract_address: snake_target }, + DualCaseOwnable { contract_address: camel_target } ) } diff --git a/src/openzeppelin/tests/account/test_dual_account.cairo b/src/openzeppelin/tests/account/test_dual_account.cairo index 946119a6c..1d4e23840 100644 --- a/src/openzeppelin/tests/account/test_dual_account.cairo +++ b/src/openzeppelin/tests/account/test_dual_account.cairo @@ -33,11 +33,8 @@ fn setup_snake() -> (DualCaseAccount, AccountABIDispatcher) { calldata.append_serde(PUBLIC_KEY); let target = utils::deploy(SnakeAccountMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccount { - contract_address: target - }, AccountABIDispatcher { - contract_address: target - } + DualCaseAccount { contract_address: target }, + AccountABIDispatcher { contract_address: target } ) } @@ -46,11 +43,8 @@ fn setup_camel() -> (DualCaseAccount, AccountABICamelDispatcher) { calldata.append_serde(PUBLIC_KEY); let target = utils::deploy(CamelAccountMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccount { - contract_address: target - }, AccountABICamelDispatcher { - contract_address: target - } + DualCaseAccount { contract_address: target }, + AccountABICamelDispatcher { contract_address: target } ) } @@ -64,11 +58,8 @@ fn setup_account_panic() -> (DualCaseAccount, DualCaseAccount) { let snake_target = utils::deploy(SnakeAccountPanicMock::TEST_CLASS_HASH, ArrayTrait::new()); let camel_target = utils::deploy(CamelAccountPanicMock::TEST_CLASS_HASH, ArrayTrait::new()); ( - DualCaseAccount { - contract_address: snake_target - }, DualCaseAccount { - contract_address: camel_target - } + DualCaseAccount { contract_address: snake_target }, + DualCaseAccount { contract_address: camel_target } ) } diff --git a/src/openzeppelin/tests/introspection/test_dual_src5.cairo b/src/openzeppelin/tests/introspection/test_dual_src5.cairo index 5693b941c..4e47773cc 100644 --- a/src/openzeppelin/tests/introspection/test_dual_src5.cairo +++ b/src/openzeppelin/tests/introspection/test_dual_src5.cairo @@ -1,9 +1,9 @@ use array::ArrayTrait; -use openzeppelin::introspection::src5::ISRC5_ID; -use openzeppelin::introspection::src5::ISRC5Dispatcher; -use openzeppelin::introspection::src5::ISRC5DispatcherTrait; -use openzeppelin::introspection::src5::ISRC5CamelDispatcher; -use openzeppelin::introspection::src5::ISRC5CamelDispatcherTrait; +use openzeppelin::introspection::interface::ISRC5_ID; +use openzeppelin::introspection::interface::ISRC5Dispatcher; +use openzeppelin::introspection::interface::ISRC5DispatcherTrait; +use openzeppelin::introspection::interface::ISRC5CamelDispatcher; +use openzeppelin::introspection::interface::ISRC5CamelDispatcherTrait; use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; use openzeppelin::tests::mocks::src5_mocks::SnakeSRC5Mock; @@ -18,32 +18,29 @@ use openzeppelin::tests::utils; // fn setup_snake() -> DualCaseSRC5 { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; let target = utils::deploy(SnakeSRC5Mock::TEST_CLASS_HASH, calldata); DualCaseSRC5 { contract_address: target } } fn setup_camel() -> DualCaseSRC5 { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; let target = utils::deploy(CamelSRC5Mock::TEST_CLASS_HASH, calldata); DualCaseSRC5 { contract_address: target } } fn setup_non_src5() -> DualCaseSRC5 { - let calldata = ArrayTrait::new(); + let calldata = array![]; let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); DualCaseSRC5 { contract_address: target } } fn setup_src5_panic() -> (DualCaseSRC5, DualCaseSRC5) { - let snake_target = utils::deploy(SnakeSRC5PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); - let camel_target = utils::deploy(CamelSRC5PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + let snake_target = utils::deploy(SnakeSRC5PanicMock::TEST_CLASS_HASH, array![]); + let camel_target = utils::deploy(CamelSRC5PanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseSRC5 { - contract_address: snake_target - }, DualCaseSRC5 { - contract_address: camel_target - } + DualCaseSRC5 { contract_address: snake_target }, + DualCaseSRC5 { contract_address: camel_target } ) } diff --git a/src/openzeppelin/tests/introspection/test_src5.cairo b/src/openzeppelin/tests/introspection/test_src5.cairo index 9b43bf894..7b0ea5418 100644 --- a/src/openzeppelin/tests/introspection/test_src5.cairo +++ b/src/openzeppelin/tests/introspection/test_src5.cairo @@ -1,36 +1,44 @@ use openzeppelin::introspection::src5::SRC5; -use openzeppelin::introspection::src5::ISRC5_ID; +use openzeppelin::introspection::src5::SRC5::SRC5Impl; +use openzeppelin::introspection::src5::SRC5::InternalImpl; +use openzeppelin::introspection::interface::ISRC5_ID; const OTHER_ID: felt252 = 0x12345678; +fn STATE() -> SRC5::ContractState { + SRC5::contract_state_for_testing() +} + #[test] #[available_gas(2000000)] fn test_default_behavior() { - let supports_default_interface: bool = SRC5::supports_interface(ISRC5_ID); + let supports_default_interface = SRC5Impl::supports_interface(@STATE(), ISRC5_ID); assert(supports_default_interface, 'Should support base interface'); } #[test] #[available_gas(2000000)] fn test_not_registered_interface() { - let supports_unregistered_interface: bool = SRC5::supports_interface(OTHER_ID); + let supports_unregistered_interface = SRC5Impl::supports_interface(@STATE(), OTHER_ID); assert(!supports_unregistered_interface, 'Should not support unregistered'); } #[test] #[available_gas(2000000)] fn test_register_interface() { - SRC5::register_interface(OTHER_ID); - let supports_new_interface: bool = SRC5::supports_interface(OTHER_ID); + let mut state = STATE(); + InternalImpl::register_interface(ref state, OTHER_ID); + let supports_new_interface = SRC5Impl::supports_interface(@state, OTHER_ID); assert(supports_new_interface, 'Should support new interface'); } #[test] #[available_gas(2000000)] fn test_deregister_interface() { - SRC5::register_interface(OTHER_ID); - SRC5::deregister_interface(OTHER_ID); - let supports_old_interface: bool = SRC5::supports_interface(OTHER_ID); + let mut state = STATE(); + InternalImpl::register_interface(ref state, OTHER_ID); + InternalImpl::deregister_interface(ref state, OTHER_ID); + let supports_old_interface = SRC5Impl::supports_interface(@state, OTHER_ID); assert(!supports_old_interface, 'Should not support interface'); } @@ -38,5 +46,6 @@ fn test_deregister_interface() { #[available_gas(2000000)] #[should_panic(expected: ('SRC5: invalid id', ))] fn test_deregister_default_interface() { - SRC5::deregister_interface(ISRC5_ID); + let mut state = STATE(); + InternalImpl::deregister_interface(ref state, ISRC5_ID); } diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 7ed138560..d8bdaa92b 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -1,21 +1,21 @@ -mod reentrancy_attacker_mock; -mod reentrancy_mock; -mod erc721_receiver; -mod erc721_panic_mock; -mod mock_pausable; -mod camel20_mock; -mod snake20_mock; -mod erc20_panic; -mod non721_mock; -mod accesscontrol_panic_mock; -mod account_panic_mock; -mod camel_accesscontrol_mock; -mod camel_account_mock; -mod snake_accesscontrol_mock; -mod snake_account_mock; -mod dual_ownable_mocks; -mod snake721_mock; -mod camel721_mock; +// mod reentrancy_attacker_mock; +// mod reentrancy_mock; +// mod erc721_receiver; +// mod erc721_panic_mock; +// mod mock_pausable; +// mod camel20_mock; +// mod snake20_mock; +// mod erc20_panic; +// mod non721_mock; +// mod accesscontrol_panic_mock; +// mod account_panic_mock; +// mod camel_accesscontrol_mock; +// mod camel_account_mock; +// mod snake_accesscontrol_mock; +// mod snake_account_mock; +// mod dual_ownable_mocks; +// mod snake721_mock; +// mod camel721_mock; mod non_implementing_mock; -mod dual721_receiver_mocks; +// mod dual721_receiver_mocks; mod src5_mocks; diff --git a/src/openzeppelin/tests/mocks/non_implementing_mock.cairo b/src/openzeppelin/tests/mocks/non_implementing_mock.cairo index d614d1da7..ffa12f857 100644 --- a/src/openzeppelin/tests/mocks/non_implementing_mock.cairo +++ b/src/openzeppelin/tests/mocks/non_implementing_mock.cairo @@ -1,7 +1,10 @@ -#[contract] +#[starknet::contract] mod NonImplementingMock { - #[view] - fn nope() -> bool { + #[storage] + struct Storage {} + + #[external(v0)] + fn nope(self: @ContractState) -> bool { false } } diff --git a/src/openzeppelin/tests/mocks/src5_mocks.cairo b/src/openzeppelin/tests/mocks/src5_mocks.cairo index 28ccf2b6b..cebdd0910 100644 --- a/src/openzeppelin/tests/mocks/src5_mocks.cairo +++ b/src/openzeppelin/tests/mocks/src5_mocks.cairo @@ -1,34 +1,48 @@ use openzeppelin::introspection::src5::SRC5; -#[contract] +#[starknet::contract] mod SnakeSRC5Mock { - #[view] - fn supports_interface(interface_id: felt252) -> bool { - super::SRC5::supports_interface(interface_id) + #[storage] + struct Storage {} + + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = super::SRC5::unsafe_new_contract_state(); + super::SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) } } -#[contract] +#[starknet::contract] mod CamelSRC5Mock { - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - super::SRC5::supportsInterface(interfaceId) + #[storage] + struct Storage {} + + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = super::SRC5::unsafe_new_contract_state(); + super::SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) } } -#[contract] +#[starknet::contract] mod SnakeSRC5PanicMock { - #[view] - fn supports_interface(interface_id: felt252) -> bool { + #[storage] + struct Storage {} + + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { panic_with_felt252('Some error'); false } } -#[contract] +#[starknet::contract] mod CamelSRC5PanicMock { - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { + #[storage] + struct Storage {} + + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { panic_with_felt252('Some error'); false } diff --git a/src/openzeppelin/tests/token/test_dual721.cairo b/src/openzeppelin/tests/token/test_dual721.cairo index 4adab5d29..b0e45e568 100644 --- a/src/openzeppelin/tests/token/test_dual721.cairo +++ b/src/openzeppelin/tests/token/test_dual721.cairo @@ -76,11 +76,8 @@ fn setup_camel() -> (DualCaseERC721, IERC721CamelDispatcher) { set_caller_address(OWNER()); let target = utils::deploy(CamelERC721Mock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721 { - contract_address: target - }, IERC721CamelDispatcher { - contract_address: target - } + DualCaseERC721 { contract_address: target }, + IERC721CamelDispatcher { contract_address: target } ) } @@ -94,11 +91,8 @@ fn setup_erc721_panic() -> (DualCaseERC721, DualCaseERC721) { let snake_target = utils::deploy(SnakeERC721PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); let camel_target = utils::deploy(CamelERC721PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); ( - DualCaseERC721 { - contract_address: snake_target - }, DualCaseERC721 { - contract_address: camel_target - } + DualCaseERC721 { contract_address: snake_target }, + DualCaseERC721 { contract_address: camel_target } ) } diff --git a/src/openzeppelin/tests/token/test_dual721_receiver.cairo b/src/openzeppelin/tests/token/test_dual721_receiver.cairo index ef02380a9..a3197dddc 100644 --- a/src/openzeppelin/tests/token/test_dual721_receiver.cairo +++ b/src/openzeppelin/tests/token/test_dual721_receiver.cairo @@ -49,11 +49,8 @@ fn setup_snake() -> (DualCaseERC721Receiver, IERC721ReceiverDispatcher) { let mut calldata = ArrayTrait::new(); let target = utils::deploy(SnakeERC721ReceiverMock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721Receiver { - contract_address: target - }, IERC721ReceiverDispatcher { - contract_address: target - } + DualCaseERC721Receiver { contract_address: target }, + IERC721ReceiverDispatcher { contract_address: target } ) } @@ -61,11 +58,8 @@ fn setup_camel() -> (DualCaseERC721Receiver, IERC721ReceiverCamelDispatcher) { let mut calldata = ArrayTrait::new(); let target = utils::deploy(CamelERC721ReceiverMock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721Receiver { - contract_address: target - }, IERC721ReceiverCamelDispatcher { - contract_address: target - } + DualCaseERC721Receiver { contract_address: target }, + IERC721ReceiverCamelDispatcher { contract_address: target } ) } @@ -83,11 +77,8 @@ fn setup_erc721_receiver_panic() -> (DualCaseERC721Receiver, DualCaseERC721Recei CamelERC721ReceiverPanicMock::TEST_CLASS_HASH, ArrayTrait::new() ); ( - DualCaseERC721Receiver { - contract_address: snake_target - }, DualCaseERC721Receiver { - contract_address: camel_target - } + DualCaseERC721Receiver { contract_address: snake_target }, + DualCaseERC721Receiver { contract_address: camel_target } ) } diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/openzeppelin/token/erc721/erc721.cairo index 3cda6ff3f..339c63ebd 100644 --- a/src/openzeppelin/token/erc721/erc721.cairo +++ b/src/openzeppelin/token/erc721/erc721.cairo @@ -454,12 +454,9 @@ mod ERC721 { fn _check_on_erc721_received( from: ContractAddress, to: ContractAddress, token_id: u256, data: Span ) -> bool { - if (DualCaseSRC5 { - contract_address: to - }.supports_interface(erc721::interface::IERC721_RECEIVER_ID)) { - DualCaseERC721Receiver { - contract_address: to - } + if (DualCaseSRC5 { contract_address: to } + .supports_interface(erc721::interface::IERC721_RECEIVER_ID)) { + DualCaseERC721Receiver { contract_address: to } .on_erc721_received( get_caller_address(), from, token_id, data ) == erc721::interface::IERC721_RECEIVER_ID diff --git a/src/openzeppelin/utils/serde.cairo b/src/openzeppelin/utils/serde.cairo index aca966485..45b33c8e4 100644 --- a/src/openzeppelin/utils/serde.cairo +++ b/src/openzeppelin/utils/serde.cairo @@ -1,22 +1,6 @@ use array::ArrayTrait; use array::SpanTrait; use serde::Serde; -use serde::serialize_array_helper; -use serde::deserialize_array_helper; - -impl SpanSerde< - T, impl TSerde: Serde, impl TCopy: Copy, impl TDrop: Drop -> of Serde> { - fn serialize(self: @Span, ref output: Array) { - (*self).len().serialize(ref output); - serialize_array_helper(*self, ref output); - } - fn deserialize(ref serialized: Span) -> Option> { - let length = *serialized.pop_front()?; - let mut arr = ArrayTrait::new(); - Option::Some(deserialize_array_helper(ref serialized, arr, length)?.span()) - } -} trait SerializedAppend { fn append_serde(ref self: Array, value: T); From c4590b98e8d3cf529cb708b519d75b875f8289df Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 18 Jul 2023 16:34:52 -0400 Subject: [PATCH 066/124] Migrate initializable to cairo2 (#661) * bump to cairo v2.0.2 * update Cargo * comment out mods * update initializable syntax * move security tests * update initializable tests * fix formatting * update cairo * update Cargo * simplify and clarify tests * fix formatting * Apply suggestions from code review Co-authored-by: Eric Nordelo * fix tests --------- Co-authored-by: Eric Nordelo --- src/openzeppelin/lib.cairo | 2 +- src/openzeppelin/security.cairo | 4 ++-- src/openzeppelin/security/initializable.cairo | 20 +++++++++------- src/openzeppelin/tests.cairo | 4 +--- src/openzeppelin/tests/security.cairo | 5 ++++ .../tests/security/test_initializable.cairo | 24 +++++++++++++++++++ .../tests/{ => security}/test_pausable.cairo | 0 .../{ => security}/test_reentrancyguard.cairo | 0 .../tests/test_initializable.cairo | 17 ------------- 9 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 src/openzeppelin/tests/security.cairo create mode 100644 src/openzeppelin/tests/security/test_initializable.cairo rename src/openzeppelin/tests/{ => security}/test_pausable.cairo (100%) rename src/openzeppelin/tests/{ => security}/test_reentrancyguard.cairo (100%) delete mode 100644 src/openzeppelin/tests/test_initializable.cairo diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 03d22fd58..6a2a521b4 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,6 +1,6 @@ // mod access; mod introspection; -// mod security; +mod security; // mod account; // mod token; mod tests; diff --git a/src/openzeppelin/security.cairo b/src/openzeppelin/security.cairo index 45a9c998a..1e38ab41a 100644 --- a/src/openzeppelin/security.cairo +++ b/src/openzeppelin/security.cairo @@ -1,3 +1,3 @@ -mod reentrancyguard; -mod pausable; +//mod reentrancyguard; +//mod pausable; mod initializable; diff --git a/src/openzeppelin/security/initializable.cairo b/src/openzeppelin/security/initializable.cairo index 8485238bb..1be5ab059 100644 --- a/src/openzeppelin/security/initializable.cairo +++ b/src/openzeppelin/security/initializable.cairo @@ -1,17 +1,19 @@ -#[contract] +#[starknet::contract] mod Initializable { + #[storage] struct Storage { initialized: bool } - #[internal] - fn is_initialized() -> bool { - initialized::read() - } + #[generate_trait] + impl InternalImpl of InternalTrait { + fn is_initialized(self: @ContractState) -> bool { + self.initialized.read() + } - #[internal] - fn initialize() { - assert(!is_initialized(), 'Initializable: is initialized'); - initialized::write(true); + fn initialize(ref self: ContractState) { + assert(!self.is_initialized(), 'Initializable: is initialized'); + self.initialized.write(true); + } } } diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 7f8a46378..01fb135b7 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,9 +1,7 @@ // mod access; -// mod test_reentrancyguard; mod introspection; +mod security; // mod account; // mod token; -// mod test_initializable; -// mod test_pausable; mod mocks; mod utils; diff --git a/src/openzeppelin/tests/security.cairo b/src/openzeppelin/tests/security.cairo new file mode 100644 index 000000000..56019a336 --- /dev/null +++ b/src/openzeppelin/tests/security.cairo @@ -0,0 +1,5 @@ +mod test_initializable; +//mod test_pausable; +//mod test_reentrancyguard; + + diff --git a/src/openzeppelin/tests/security/test_initializable.cairo b/src/openzeppelin/tests/security/test_initializable.cairo new file mode 100644 index 000000000..86bf68fbc --- /dev/null +++ b/src/openzeppelin/tests/security/test_initializable.cairo @@ -0,0 +1,24 @@ +use openzeppelin::security::initializable::Initializable; +use openzeppelin::security::initializable::Initializable::InternalImpl; + +fn STATE() -> Initializable::ContractState { + Initializable::contract_state_for_testing() +} + +#[test] +#[available_gas(2000000)] +fn test_initialize() { + let mut state = STATE(); + assert(!InternalImpl::is_initialized(@state), 'Should not be initialized'); + InternalImpl::initialize(ref state); + assert(InternalImpl::is_initialized(@state), 'Should be initialized'); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Initializable: is initialized', ))] +fn test_initialize_when_initialized() { + let mut state = STATE(); + InternalImpl::initialize(ref state); + InternalImpl::initialize(ref state); +} diff --git a/src/openzeppelin/tests/test_pausable.cairo b/src/openzeppelin/tests/security/test_pausable.cairo similarity index 100% rename from src/openzeppelin/tests/test_pausable.cairo rename to src/openzeppelin/tests/security/test_pausable.cairo diff --git a/src/openzeppelin/tests/test_reentrancyguard.cairo b/src/openzeppelin/tests/security/test_reentrancyguard.cairo similarity index 100% rename from src/openzeppelin/tests/test_reentrancyguard.cairo rename to src/openzeppelin/tests/security/test_reentrancyguard.cairo diff --git a/src/openzeppelin/tests/test_initializable.cairo b/src/openzeppelin/tests/test_initializable.cairo deleted file mode 100644 index cfd7ec003..000000000 --- a/src/openzeppelin/tests/test_initializable.cairo +++ /dev/null @@ -1,17 +0,0 @@ -use openzeppelin::security::initializable::Initializable; - -#[test] -#[available_gas(2000000)] -fn test_initialize() { - assert(!Initializable::is_initialized(), 'Should not be initialized'); - Initializable::initialize(); - assert(Initializable::is_initialized(), 'Should be initialized'); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Initializable: is initialized', ))] -fn test_initialize_when_initialized() { - Initializable::initialize(); - Initializable::initialize(); -} From f18fcdbeeb0bd9b2b3ea799fb14f89fd96e92a30 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 20 Jul 2023 12:20:02 +0200 Subject: [PATCH 067/124] Migrate Account to Cairo 2 (#666) * feat: migrate files * feat: add interface.cairo * feat: apply review updates * refactor: improve readability * fix: dual account tests * fix: account tests * feat: apply review updates --- src/openzeppelin/account.cairo | 4 +- src/openzeppelin/account/account.cairo | 278 ++++++------- src/openzeppelin/account/dual_account.cairo | 15 +- src/openzeppelin/account/interface.cairo | 29 +- src/openzeppelin/lib.cairo | 4 +- src/openzeppelin/tests.cairo | 4 +- .../tests/account/test_account.cairo | 368 +++++++++--------- .../tests/account/test_dual_account.cairo | 45 +-- src/openzeppelin/tests/mocks.cairo | 6 +- .../tests/mocks/account_panic_mock.cairo | 44 ++- .../tests/mocks/camel_account_mock.cairo | 40 +- .../tests/mocks/snake_account_mock.cairo | 62 ++- 12 files changed, 425 insertions(+), 474 deletions(-) diff --git a/src/openzeppelin/account.cairo b/src/openzeppelin/account.cairo index d995b6329..47e57df8a 100644 --- a/src/openzeppelin/account.cairo +++ b/src/openzeppelin/account.cairo @@ -1,7 +1,7 @@ mod account; use account::{ - Account, AccountABIDispatcher, AccountABIDispatcherTrait, AccountABICamelDispatcher, - AccountABICamelDispatcherTrait, TRANSACTION_VERSION, QUERY_VERSION + Account, AccountCamelABIDispatcher, AccountCamelABIDispatcherTrait, AccountABIDispatcher, + AccountABIDispatcherTrait, TRANSACTION_VERSION, QUERY_VERSION }; mod dual_account; diff --git a/src/openzeppelin/account/account.cairo b/src/openzeppelin/account/account.cairo index 3c7a860ea..714f1f89f 100644 --- a/src/openzeppelin/account/account.cairo +++ b/src/openzeppelin/account/account.cairo @@ -2,96 +2,92 @@ use array::ArrayTrait; use array::SpanTrait; use option::OptionTrait; use serde::Serde; +use starknet::account::Call; use starknet::ContractAddress; -use openzeppelin::account::interface::Call; -use openzeppelin::utils::serde::SpanSerde; const TRANSACTION_VERSION: felt252 = 1; + // 2**128 + TRANSACTION_VERSION const QUERY_VERSION: felt252 = 340282366920938463463374607431768211457; -#[abi] -trait AccountABI { - #[external] - fn __execute__(calls: Array) -> Array>; - #[external] - fn __validate__(calls: Array) -> felt252; - #[external] - fn __validate_declare__(class_hash: felt252) -> felt252; - #[external] +#[starknet::interface] +trait AccountABI { + fn __execute__(self: @TState, calls: Array) -> Array>; + fn __validate__(self: @TState, calls: Array) -> felt252; + fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252; fn __validate_deploy__( - class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + self: @TState, class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 ) -> felt252; - #[external] - fn set_public_key(new_public_key: felt252); - #[view] - fn get_public_key() -> felt252; - #[view] - fn is_valid_signature(hash: felt252, signature: Array) -> felt252; - #[view] - fn supports_interface(interface_id: felt252) -> bool; + fn set_public_key(ref self: TState, new_public_key: felt252); + fn get_public_key(self: @TState) -> felt252; + fn is_valid_signature(self: @TState, hash: felt252, signature: Array) -> felt252; + fn supports_interface(self: @TState, interface_id: felt252) -> bool; } // Entry points case-convention is enforced by the protocol -#[abi] -trait AccountABICamel { - #[external] - fn __execute__(calls: Array) -> Array>; - #[external] - fn __validate__(calls: Array) -> felt252; - #[external] - fn __validate_declare__(classHash: felt252) -> felt252; - #[external] +#[starknet::interface] +trait AccountCamelABI { + fn __execute__(self: @TState, calls: Array) -> Array>; + fn __validate__(self: @TState, calls: Array) -> felt252; + fn __validate_declare__(self: @TState, classHash: felt252) -> felt252; fn __validate_deploy__( - classHash: felt252, contractAddressSalt: felt252, _publicKey: felt252 + self: @TState, classHash: felt252, contractAddressSalt: felt252, _publicKey: felt252 ) -> felt252; - #[external] - fn setPublicKey(newPublicKey: felt252); - #[view] - fn getPublicKey() -> felt252; - #[view] - fn isValidSignature(hash: felt252, signature: Array) -> felt252; - #[view] - fn supportsInterface(interfaceId: felt252) -> bool; + fn setPublicKey(ref self: TState, newPublicKey: felt252); + fn getPublicKey(self: @TState) -> felt252; + fn isValidSignature(self: @TState, hash: felt252, signature: Array) -> felt252; + fn supportsInterface(self: @TState, interfaceId: felt252) -> bool; +} + +trait PublicKeyTrait { + fn set_public_key(ref self: TState, new_public_key: felt252); + fn get_public_key(self: @TState) -> felt252; } -#[account_contract] +trait PublicKeyCamelTrait { + fn setPublicKey(ref self: TState, newPublicKey: felt252); + fn getPublicKey(self: @TState) -> felt252; +} + +#[starknet::contract] mod Account { use array::SpanTrait; use array::ArrayTrait; use box::BoxTrait; use ecdsa::check_ecdsa_signature; use option::OptionTrait; - use serde::ArraySerde; use starknet::get_tx_info; use starknet::get_caller_address; use starknet::get_contract_address; use zeroable::Zeroable; - use openzeppelin::account::interface::IDeclarer; - use openzeppelin::account::interface::ISRC6; - use openzeppelin::account::interface::ISRC6Camel; - use openzeppelin::account::interface::ISRC6_ID; - use openzeppelin::introspection::src5::ISRC5; + use openzeppelin::account::interface; + use openzeppelin::introspection::interface::ISRC5; + use openzeppelin::introspection::interface::ISRC5Camel; use openzeppelin::introspection::src5::SRC5; use super::Call; use super::QUERY_VERSION; - use super::SpanSerde; use super::TRANSACTION_VERSION; + #[storage] struct Storage { public_key: felt252 } #[constructor] - fn constructor(_public_key: felt252) { - initializer(_public_key); + fn constructor(ref self: ContractState, _public_key: felt252) { + self.initializer(_public_key); } - impl SRC6Impl of ISRC6 { - fn __execute__(mut calls: Array) -> Array> { + // + // External + // + + #[external(v0)] + impl SRC6Impl of interface::ISRC6 { + fn __execute__(self: @ContractState, mut calls: Array) -> Array> { // Avoid calls from other contracts // https://github.com/OpenZeppelin/cairo-contracts/issues/344 let sender = get_caller_address(); @@ -107,12 +103,14 @@ mod Account { _execute_calls(calls) } - fn __validate__(mut calls: Array) -> felt252 { - validate_transaction() + fn __validate__(self: @ContractState, mut calls: Array) -> felt252 { + self.validate_transaction() } - fn is_valid_signature(hash: felt252, signature: Array) -> felt252 { - if _is_valid_signature(hash, signature.span()) { + fn is_valid_signature( + self: @ContractState, hash: felt252, signature: Array + ) -> felt252 { + if self._is_valid_signature(hash, signature.span()) { starknet::VALIDATED } else { 0 @@ -120,111 +118,105 @@ mod Account { } } - impl SRC6CamelImpl of ISRC6Camel { - fn __execute__(mut calls: Array) -> Array> { - SRC6Impl::__execute__(calls) - } - - fn __validate__(mut calls: Array) -> felt252 { - SRC6Impl::__validate__(calls) + #[external(v0)] + impl SRC6CamelOnlyImpl of interface::ISRC6CamelOnly { + fn isValidSignature( + self: @ContractState, hash: felt252, signature: Array + ) -> felt252 { + SRC6Impl::is_valid_signature(self, hash, signature) } + } - fn isValidSignature(hash: felt252, signature: Array) -> felt252 { - SRC6Impl::is_valid_signature(hash, signature) + #[external(v0)] + impl DeclarerImpl of interface::IDeclarer { + fn __validate_declare__(self: @ContractState, class_hash: felt252) -> felt252 { + self.validate_transaction() } } - impl DeclarerImpl of IDeclarer { - fn __validate_declare__(class_hash: felt252) -> felt252 { - validate_transaction() + #[external(v0)] + impl SRC5Impl of ISRC5 { + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) } } - impl SRC5Impl of ISRC5 { - fn supports_interface(interface_id: felt252) -> bool { - SRC5::supports_interface(interface_id) + #[external(v0)] + impl SRC5CamelImpl of ISRC5Camel { + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) } } - // - // Externals - // + #[external(v0)] + impl PublicKeyImpl of super::PublicKeyTrait { + fn get_public_key(self: @ContractState) -> felt252 { + self.public_key.read() + } - #[external] - fn __execute__(mut calls: Array) -> Array> { - SRC6Impl::__execute__(calls) + fn set_public_key(ref self: ContractState, new_public_key: felt252) { + assert_only_self(); + self.public_key.write(new_public_key); + } } - #[external] - fn __validate__(mut calls: Array) -> felt252 { - SRC6Impl::__validate__(calls) - } + #[external(v0)] + impl PublicKeyCamelImpl of super::PublicKeyCamelTrait { + fn getPublicKey(self: @ContractState) -> felt252 { + self.public_key.read() + } - #[external] - fn __validate_declare__(class_hash: felt252) -> felt252 { - DeclarerImpl::__validate_declare__(class_hash) + fn setPublicKey(ref self: ContractState, newPublicKey: felt252) { + assert_only_self(); + self.public_key.write(newPublicKey); + } } - #[external] + #[external(v0)] fn __validate_deploy__( - class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + self: @ContractState, + class_hash: felt252, + contract_address_salt: felt252, + _public_key: felt252 ) -> felt252 { - validate_transaction() - } - - #[external] - fn set_public_key(new_public_key: felt252) { - assert_only_self(); - public_key::write(new_public_key); - } - - #[external] - fn setPublicKey(newPublicKey: felt252) { - set_public_key(newPublicKey); + self.validate_transaction() } // - // View + // Internal // - #[view] - fn get_public_key() -> felt252 { - public_key::read() - } - - #[view] - fn getPublicKey() -> felt252 { - get_public_key() - } - - #[view] - fn is_valid_signature(hash: felt252, signature: Array) -> felt252 { - SRC6Impl::is_valid_signature(hash, signature) - } - - #[view] - fn isValidSignature(hash: felt252, signature: Array) -> felt252 { - SRC6CamelImpl::isValidSignature(hash, signature) - } - - #[view] - fn supports_interface(interface_id: felt252) -> bool { - SRC5Impl::supports_interface(interface_id) - } + #[generate_trait] + impl InternalImpl of InternalTrait { + fn initializer(ref self: ContractState, _public_key: felt252) { + let mut unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::InternalImpl::register_interface(ref unsafe_state, interface::ISRC6_ID); + self.public_key.write(_public_key); + } - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - supports_interface(interfaceId) - } + fn validate_transaction(self: @ContractState) -> felt252 { + let tx_info = get_tx_info().unbox(); + let tx_hash = tx_info.transaction_hash; + let signature = tx_info.signature; + assert(self._is_valid_signature(tx_hash, signature), 'Account: invalid signature'); + starknet::VALIDATED + } - // - // Internals - // + fn _is_valid_signature( + self: @ContractState, hash: felt252, signature: Span + ) -> bool { + let valid_length = signature.len() == 2_u32; - #[internal] - fn initializer(_public_key: felt252) { - SRC5::register_interface(ISRC6_ID); - public_key::write(_public_key); + if valid_length { + check_ecdsa_signature( + hash, self.public_key.read(), *signature.at(0_u32), *signature.at(1_u32) + ) + } else { + false + } + } } #[internal] @@ -234,28 +226,6 @@ mod Account { assert(self == caller, 'Account: unauthorized'); } - #[internal] - fn validate_transaction() -> felt252 { - let tx_info = get_tx_info().unbox(); - let tx_hash = tx_info.transaction_hash; - let signature = tx_info.signature; - assert(_is_valid_signature(tx_hash, signature), 'Account: invalid signature'); - starknet::VALIDATED - } - - #[internal] - fn _is_valid_signature(hash: felt252, signature: Span) -> bool { - let valid_length = signature.len() == 2_u32; - - if valid_length { - check_ecdsa_signature( - hash, public_key::read(), *signature.at(0_u32), *signature.at(1_u32) - ) - } else { - false - } - } - #[internal] fn _execute_calls(mut calls: Array) -> Array> { let mut res = ArrayTrait::new(); diff --git a/src/openzeppelin/account/dual_account.cairo b/src/openzeppelin/account/dual_account.cairo index ad6903659..ee4e1c0b6 100644 --- a/src/openzeppelin/account/dual_account.cairo +++ b/src/openzeppelin/account/dual_account.cairo @@ -13,7 +13,7 @@ struct DualCaseAccount { contract_address: ContractAddress } -trait DualCaseAccountTrait { +trait DualCaseAccountABI { fn set_public_key(self: @DualCaseAccount, new_public_key: felt252); fn get_public_key(self: @DualCaseAccount) -> felt252; fn is_valid_signature( @@ -22,10 +22,9 @@ trait DualCaseAccountTrait { fn supports_interface(self: @DualCaseAccount, interface_id: felt252) -> bool; } -impl DualCaseAccountImpl of DualCaseAccountTrait { +impl DualCaseAccountImpl of DualCaseAccountABI { fn set_public_key(self: @DualCaseAccount, new_public_key: felt252) { - let mut args = ArrayTrait::new(); - args.append_serde(new_public_key); + let mut args = array![new_public_key]; try_selector_with_fallback( *self.contract_address, selectors::set_public_key, selectors::setPublicKey, args.span() @@ -34,7 +33,7 @@ impl DualCaseAccountImpl of DualCaseAccountTrait { } fn get_public_key(self: @DualCaseAccount) -> felt252 { - let mut args = ArrayTrait::new(); + let mut args = array![]; try_selector_with_fallback( *self.contract_address, selectors::get_public_key, selectors::getPublicKey, args.span() @@ -45,8 +44,7 @@ impl DualCaseAccountImpl of DualCaseAccountTrait { fn is_valid_signature( self: @DualCaseAccount, hash: felt252, signature: Array ) -> felt252 { - let mut args = ArrayTrait::new(); - args.append_serde(hash); + let mut args = array![hash]; args.append_serde(signature); try_selector_with_fallback( @@ -59,8 +57,7 @@ impl DualCaseAccountImpl of DualCaseAccountTrait { } fn supports_interface(self: @DualCaseAccount, interface_id: felt252) -> bool { - let mut args = ArrayTrait::new(); - args.append_serde(interface_id); + let mut args = array![interface_id]; try_selector_with_fallback( *self.contract_address, diff --git a/src/openzeppelin/account/interface.cairo b/src/openzeppelin/account/interface.cairo index af454163c..2027c0c99 100644 --- a/src/openzeppelin/account/interface.cairo +++ b/src/openzeppelin/account/interface.cairo @@ -1,28 +1,23 @@ use array::ArrayTrait; use array::SpanTrait; +use starknet::account::Call; use starknet::ContractAddress; const ISRC6_ID: felt252 = 0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd; -#[derive(Serde, Drop)] -struct Call { - to: ContractAddress, - selector: felt252, - calldata: Array +#[starknet::interface] +trait ISRC6 { + fn __execute__(self: @TState, calls: Array) -> Array>; + fn __validate__(self: @TState, calls: Array) -> felt252; + fn is_valid_signature(self: @TState, hash: felt252, signature: Array) -> felt252; } -trait ISRC6 { - fn __execute__(calls: Array) -> Array>; - fn __validate__(calls: Array) -> felt252; - fn is_valid_signature(hash: felt252, signature: Array) -> felt252; +#[starknet::interface] +trait ISRC6CamelOnly { + fn isValidSignature(self: @TState, hash: felt252, signature: Array) -> felt252; } -trait ISRC6Camel { - fn __execute__(calls: Array) -> Array>; - fn __validate__(calls: Array) -> felt252; - fn isValidSignature(hash: felt252, signature: Array) -> felt252; -} - -trait IDeclarer { - fn __validate_declare__(class_hash: felt252) -> felt252; +#[starknet::interface] +trait IDeclarer { + fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252; } diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 6a2a521b4..5c658386e 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,7 +1,7 @@ // mod access; +mod account; mod introspection; mod security; -// mod account; -// mod token; mod tests; +// mod token; mod utils; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 01fb135b7..440fdfc2f 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,7 +1,7 @@ // mod access; +mod account; mod introspection; +mod mocks; mod security; -// mod account; // mod token; -mod mocks; mod utils; diff --git a/src/openzeppelin/tests/account/test_account.cairo b/src/openzeppelin/tests/account/test_account.cairo index 6ece0c5e9..48ab02685 100644 --- a/src/openzeppelin/tests/account/test_account.cairo +++ b/src/openzeppelin/tests/account/test_account.cairo @@ -2,6 +2,7 @@ use array::ArrayTrait; use core::traits::Into; use option::OptionTrait; use serde::Serde; +use starknet::account::Call; use starknet::contract_address_const; use starknet::ContractAddress; use starknet::testing; @@ -9,15 +10,14 @@ use starknet::testing; use openzeppelin::account::Account; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; -use openzeppelin::account::interface::Call; use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::account::QUERY_VERSION; use openzeppelin::account::TRANSACTION_VERSION; -use openzeppelin::introspection::src5::ISRC5_ID; +use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::utils; -use openzeppelin::token::erc20::ERC20; -use openzeppelin::token::erc20::interface::IERC20Dispatcher; -use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; +// use openzeppelin::token::erc20::ERC20; +// use openzeppelin::token::erc20::interface::IERC20Dispatcher; +// use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; @@ -38,6 +38,9 @@ struct SignedTransactionData { s: felt252 } +fn STATE() -> Account::ContractState { + Account::contract_state_for_testing() +} fn CLASS_HASH() -> felt252 { Account::TEST_CLASS_HASH } @@ -59,44 +62,35 @@ fn SIGNED_TX_DATA() -> SignedTransactionData { // fn setup_dispatcher(data: Option<@SignedTransactionData>) -> AccountABIDispatcher { - // Set the transaction version testing::set_version(TRANSACTION_VERSION); - // Deploy the account contract - let mut calldata = ArrayTrait::new(); - + let mut calldata = array![]; if data.is_some() { let data = data.unwrap(); - - // Set the signature and transaction hash - let mut signature = ArrayTrait::new(); - signature.append(*data.r); - signature.append(*data.s); - testing::set_signature(signature.span()); + testing::set_signature(array![*data.r, *data.s].span()); testing::set_transaction_hash(*data.transaction_hash); calldata.append(*data.public_key); } else { calldata.append(PUBLIC_KEY); } - let address = utils::deploy(CLASS_HASH(), calldata); AccountABIDispatcher { contract_address: address } } -fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispatcher { - let name = 0; - let symbol = 0; - let mut calldata = ArrayTrait::new(); +// fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispatcher { +// let name = 0; +// let symbol = 0; +// let mut calldata = array![]; - calldata.append_serde(name); - calldata.append_serde(symbol); - calldata.append_serde(initial_supply); - calldata.append_serde(recipient); +// calldata.append_serde(name); +// calldata.append_serde(symbol); +// calldata.append_serde(initial_supply); +// calldata.append_serde(recipient); - let address = utils::deploy(ERC20::TEST_CLASS_HASH, calldata); - IERC20Dispatcher { contract_address: address } -} +// let address = utils::deploy(ERC20::TEST_CLASS_HASH, calldata); +// IERC20Dispatcher { contract_address: address } +// } // // constructor @@ -105,8 +99,11 @@ fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispa #[test] #[available_gas(2000000)] fn test_constructor() { - Account::constructor(PUBLIC_KEY); - assert(Account::get_public_key() == PUBLIC_KEY, 'Should return public key'); + let mut state = STATE(); + Account::constructor(ref state, PUBLIC_KEY); + assert( + Account::PublicKeyImpl::get_public_key(@state) == PUBLIC_KEY, 'Should return public key' + ); } // @@ -116,24 +113,26 @@ fn test_constructor() { #[test] #[available_gas(2000000)] fn test_supports_interface() { - Account::constructor(PUBLIC_KEY); + let mut state = STATE(); + Account::constructor(ref state, PUBLIC_KEY); - let supports_default_interface = Account::supports_interface(ISRC5_ID); + let supports_default_interface = Account::SRC5Impl::supports_interface(@state, ISRC5_ID); assert(supports_default_interface, 'Should support base interface'); - let supports_account_interface = Account::supports_interface(ISRC6_ID); + let supports_account_interface = Account::SRC5Impl::supports_interface(@state, ISRC6_ID); assert(supports_account_interface, 'Should support account id'); } #[test] #[available_gas(2000000)] fn test_supportsInterface() { - Account::constructor(PUBLIC_KEY); + let mut state = STATE(); + Account::constructor(ref state, PUBLIC_KEY); - let supports_default_interface = Account::supportsInterface(ISRC5_ID); + let supports_default_interface = Account::SRC5CamelImpl::supportsInterface(@state, ISRC5_ID); assert(supports_default_interface, 'Should support base interface'); - let supports_account_interface = Account::supportsInterface(ISRC6_ID); + let supports_account_interface = Account::SRC5CamelImpl::supportsInterface(@state, ISRC6_ID); assert(supports_account_interface, 'Should support account id'); } @@ -144,46 +143,38 @@ fn test_supportsInterface() { #[test] #[available_gas(2000000)] fn test_is_valid_signature() { + let mut state = STATE(); let data = SIGNED_TX_DATA(); let hash = data.transaction_hash; - let mut good_signature = ArrayTrait::new(); - good_signature.append(data.r); - good_signature.append(data.s); + let mut good_signature = array![data.r, data.s]; + let mut bad_signature = array![0x987, 0x564]; - let mut bad_signature = ArrayTrait::new(); - bad_signature.append(0x987); - bad_signature.append(0x564); + Account::PublicKeyImpl::set_public_key(ref state, data.public_key); - Account::set_public_key(data.public_key); - - let is_valid = Account::is_valid_signature(hash, good_signature); + let is_valid = Account::SRC6Impl::is_valid_signature(@state, hash, good_signature); assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); - let is_valid = Account::is_valid_signature(hash, bad_signature); + let is_valid = Account::SRC6Impl::is_valid_signature(@state, hash, bad_signature); assert(is_valid == 0, 'Should reject invalid signature'); } #[test] #[available_gas(2000000)] fn test_isValidSignature() { + let mut state = STATE(); let data = SIGNED_TX_DATA(); let hash = data.transaction_hash; - let mut good_signature = ArrayTrait::new(); - good_signature.append(data.r); - good_signature.append(data.s); - - let mut bad_signature = ArrayTrait::new(); - bad_signature.append(0x987); - bad_signature.append(0x564); + let mut good_signature = array![data.r, data.s]; + let mut bad_signature = array![0x987, 0x564]; - Account::set_public_key(data.public_key); + Account::PublicKeyImpl::set_public_key(ref state, data.public_key); - let is_valid = Account::is_valid_signature(hash, good_signature); + let is_valid = Account::SRC6CamelOnlyImpl::isValidSignature(@state, hash, good_signature); assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); - let is_valid = Account::is_valid_signature(hash, bad_signature); + let is_valid = Account::SRC6CamelOnlyImpl::isValidSignature(@state, hash, bad_signature); assert(is_valid == 0, 'Should reject invalid signature'); } @@ -221,7 +212,7 @@ fn test_validate_deploy_invalid_signature_data() { #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_deploy_invalid_signature_length() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); - let mut signature = ArrayTrait::new(); + let mut signature = array![]; signature.append(0x1); testing::set_signature(signature.span()); @@ -234,7 +225,7 @@ fn test_validate_deploy_invalid_signature_length() { #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_deploy_empty_signature() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); - let empty_sig = ArrayTrait::new(); + let empty_sig = array![]; testing::set_signature(empty_sig.span()); account.__validate_deploy__(CLASS_HASH(), SALT, PUBLIC_KEY); @@ -270,7 +261,7 @@ fn test_validate_declare_invalid_signature_data() { #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_declare_invalid_signature_length() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); - let mut signature = ArrayTrait::new(); + let mut signature = array![]; signature.append(0x1); testing::set_signature(signature.span()); @@ -283,71 +274,71 @@ fn test_validate_declare_invalid_signature_length() { #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_declare_empty_signature() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); - let empty_sig = ArrayTrait::new(); + let empty_sig = array![]; testing::set_signature(empty_sig.span()); account.__validate_declare__(CLASS_HASH()); } -fn test_execute_with_version(version: Option) { - let data = SIGNED_TX_DATA(); - let account = setup_dispatcher(Option::Some(@data)); - let erc20 = deploy_erc20(account.contract_address, 1000); - let recipient = contract_address_const::<0x123>(); - - // Craft call and add to calls array - let mut calldata = ArrayTrait::new(); - let amount: u256 = 200; - calldata.append_serde(recipient); - calldata.append_serde(amount); - let call = Call { - to: erc20.contract_address, selector: selectors::transfer, calldata: calldata - }; - let mut calls = ArrayTrait::new(); - calls.append(call); - - // Handle version for test - if version.is_some() { - testing::set_version(version.unwrap()); - } - - // Execute - let ret = account.__execute__(calls); - - // Assert that the transfer was successful - assert(erc20.balance_of(account.contract_address) == 800, 'Should have remainder'); - assert(erc20.balance_of(recipient) == amount, 'Should have transferred'); - - // Test return value - let mut call_serialized_retval = *ret.at(0); - let call_retval = Serde::::deserialize(ref call_serialized_retval); - assert(call_retval.unwrap(), 'Should have succeeded'); -} - -#[test] -#[available_gas(2000000)] -fn test_execute() { - test_execute_with_version(Option::None(())); -} - -#[test] -#[available_gas(2000000)] -fn test_execute_query_version() { - test_execute_with_version(Option::Some(QUERY_VERSION)); -} - -#[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Account: invalid tx version', 'ENTRYPOINT_FAILED'))] -fn test_execute_invalid_version() { - test_execute_with_version(Option::Some(TRANSACTION_VERSION - 1)); -} +// fn test_execute_with_version(version: Option) { +// let data = SIGNED_TX_DATA(); +// let account = setup_dispatcher(Option::Some(@data)); +// let erc20 = deploy_erc20(account.contract_address, 1000); +// let recipient = contract_address_const::<0x123>(); + +// // Craft call and add to calls array +// let mut calldata = array![]; +// let amount: u256 = 200; +// calldata.append_serde(recipient); +// calldata.append_serde(amount); +// let call = Call { +// to: erc20.contract_address, selector: selectors::transfer, calldata: calldata +// }; +// let mut calls = array![]; +// calls.append(call); + +// // Handle version for test +// if version.is_some() { +// testing::set_version(version.unwrap()); +// } + +// // Execute +// let ret = account.__execute__(calls); + +// // Assert that the transfer was successful +// assert(erc20.balance_of(account.contract_address) == 800, 'Should have remainder'); +// assert(erc20.balance_of(recipient) == amount, 'Should have transferred'); + +// // Test return value +// let mut call_serialized_retval = *ret.at(0); +// let call_retval = Serde::::deserialize(ref call_serialized_retval); +// assert(call_retval.unwrap(), 'Should have succeeded'); +// } + +// #[test] +// #[available_gas(2000000)] +// fn test_execute() { +// test_execute_with_version(Option::None(())); +// } + +// #[test] +// #[available_gas(2000000)] +// fn test_execute_query_version() { +// test_execute_with_version(Option::Some(QUERY_VERSION)); +// } + +// #[test] +// #[available_gas(2000000)] +// #[should_panic(expected: ('Account: invalid tx version', 'ENTRYPOINT_FAILED'))] +// fn test_execute_invalid_version() { +// test_execute_with_version(Option::Some(TRANSACTION_VERSION - 1)); +// } #[test] #[available_gas(2000000)] fn test_validate() { - let calls = ArrayTrait::new(); + let calls = array![]; let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); assert(account.__validate__(calls) == starknet::VALIDATED, 'Should validate correctly'); @@ -357,7 +348,7 @@ fn test_validate() { #[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_invalid() { - let calls = ArrayTrait::new(); + let calls = array![]; let mut data = SIGNED_TX_DATA(); data.transaction_hash += 1; let account = setup_dispatcher(Option::Some(@data)); @@ -365,57 +356,57 @@ fn test_validate_invalid() { account.__validate__(calls); } -#[test] -#[available_gas(2000000)] -fn test_multicall() { - let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); - let erc20 = deploy_erc20(account.contract_address, 1000); - let recipient1 = contract_address_const::<0x123>(); - let recipient2 = contract_address_const::<0x456>(); - let mut calls = ArrayTrait::new(); - - // Craft call1 - let mut calldata1 = ArrayTrait::new(); - let amount1: u256 = 300; - calldata1.append_serde(recipient1); - calldata1.append_serde(amount1); - let call1 = Call { - to: erc20.contract_address, selector: selectors::transfer, calldata: calldata1 - }; - - // Craft call2 - let mut calldata2 = ArrayTrait::new(); - let amount2: u256 = 500; - calldata2.append_serde(recipient2); - calldata2.append_serde(amount2); - let call2 = Call { - to: erc20.contract_address, selector: selectors::transfer, calldata: calldata2 - }; - - // Bundle calls and exeute - calls.append(call1); - calls.append(call2); - let ret = account.__execute__(calls); - - // Assert that the transfers were successful - assert(erc20.balance_of(account.contract_address) == 200, 'Should have remainder'); - assert(erc20.balance_of(recipient1) == 300, 'Should have transferred'); - assert(erc20.balance_of(recipient2) == 500, 'Should have transferred'); - - // Test return value - let mut call1_serialized_retval = *ret.at(0); - let mut call2_serialized_retval = *ret.at(1); - let call1_retval = Serde::::deserialize(ref call1_serialized_retval); - let call2_retval = Serde::::deserialize(ref call2_serialized_retval); - assert(call1_retval.unwrap(), 'Should have succeeded'); - assert(call2_retval.unwrap(), 'Should have succeeded'); -} +// #[test] +// #[available_gas(2000000)] +// fn test_multicall() { +// let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); +// let erc20 = deploy_erc20(account.contract_address, 1000); +// let recipient1 = contract_address_const::<0x123>(); +// let recipient2 = contract_address_const::<0x456>(); +// let mut calls = array![]; + +// // Craft call1 +// let mut calldata1 = array![]; +// let amount1: u256 = 300; +// calldata1.append_serde(recipient1); +// calldata1.append_serde(amount1); +// let call1 = Call { +// to: erc20.contract_address, selector: selectors::transfer, calldata: calldata1 +// }; + +// // Craft call2 +// let mut calldata2 = array![]; +// let amount2: u256 = 500; +// calldata2.append_serde(recipient2); +// calldata2.append_serde(amount2); +// let call2 = Call { +// to: erc20.contract_address, selector: selectors::transfer, calldata: calldata2 +// }; + +// // Bundle calls and exeute +// calls.append(call1); +// calls.append(call2); +// let ret = account.__execute__(calls); + +// // Assert that the transfers were successful +// assert(erc20.balance_of(account.contract_address) == 200, 'Should have remainder'); +// assert(erc20.balance_of(recipient1) == 300, 'Should have transferred'); +// assert(erc20.balance_of(recipient2) == 500, 'Should have transferred'); + +// // Test return value +// let mut call1_serialized_retval = *ret.at(0); +// let mut call2_serialized_retval = *ret.at(1); +// let call1_retval = Serde::::deserialize(ref call1_serialized_retval); +// let call2_retval = Serde::::deserialize(ref call2_serialized_retval); +// assert(call1_retval.unwrap(), 'Should have succeeded'); +// assert(call2_retval.unwrap(), 'Should have succeeded'); +// } #[test] #[available_gas(2000000)] fn test_multicall_zero_calls() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); - let mut calls = ArrayTrait::new(); + let mut calls = array![]; let ret = account.__execute__(calls); @@ -427,11 +418,13 @@ fn test_multicall_zero_calls() { #[available_gas(2000000)] #[should_panic(expected: ('Account: invalid caller', ))] fn test_account_called_from_contract() { - let calls = ArrayTrait::new(); + let calls = array![]; let caller = contract_address_const::<0x123>(); + testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(caller); - Account::__execute__(calls); + + Account::SRC6Impl::__execute__(@STATE(), calls); } // @@ -441,11 +434,13 @@ fn test_account_called_from_contract() { #[test] #[available_gas(2000000)] fn test_public_key_setter_and_getter() { + let mut state = STATE(); testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(ACCOUNT_ADDRESS()); - Account::set_public_key(NEW_PUBKEY); - let public_key = Account::get_public_key(); + Account::PublicKeyImpl::set_public_key(ref state, NEW_PUBKEY); + + let public_key = Account::PublicKeyImpl::get_public_key(@state); assert(public_key == NEW_PUBKEY, 'Should update key'); } @@ -453,10 +448,12 @@ fn test_public_key_setter_and_getter() { #[available_gas(2000000)] #[should_panic(expected: ('Account: unauthorized', ))] fn test_public_key_setter_different_account() { + let mut state = STATE(); let caller = contract_address_const::<0x123>(); testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(caller); - Account::set_public_key(NEW_PUBKEY); + + Account::PublicKeyImpl::set_public_key(ref state, NEW_PUBKEY); } // @@ -466,11 +463,13 @@ fn test_public_key_setter_different_account() { #[test] #[available_gas(2000000)] fn test_public_key_setter_and_getter_camel() { + let mut state = STATE(); testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(ACCOUNT_ADDRESS()); - Account::setPublicKey(NEW_PUBKEY); - let public_key = Account::getPublicKey(); + Account::PublicKeyCamelImpl::setPublicKey(ref state, NEW_PUBKEY); + + let public_key = Account::PublicKeyCamelImpl::getPublicKey(@state); assert(public_key == NEW_PUBKEY, 'Should update key'); } @@ -478,10 +477,12 @@ fn test_public_key_setter_and_getter_camel() { #[available_gas(2000000)] #[should_panic(expected: ('Account: unauthorized', ))] fn test_public_key_setter_different_account_camel() { + let mut state = STATE(); let caller = contract_address_const::<0x123>(); testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(caller); - Account::setPublicKey(NEW_PUBKEY); + + Account::PublicKeyCamelImpl::setPublicKey(ref state, NEW_PUBKEY); } // @@ -491,8 +492,11 @@ fn test_public_key_setter_different_account_camel() { #[test] #[available_gas(2000000)] fn test_initializer() { - Account::initializer(PUBLIC_KEY); - assert(Account::get_public_key() == PUBLIC_KEY, 'Should return public key'); + let mut state = STATE(); + Account::InternalImpl::initializer(ref state, PUBLIC_KEY); + assert( + Account::PublicKeyImpl::get_public_key(@state) == PUBLIC_KEY, 'Should return public key' + ); } #[test] @@ -516,28 +520,24 @@ fn test_assert_only_self_false() { #[test] #[available_gas(2000000)] fn test__is_valid_signature() { + let mut state = STATE(); let data = SIGNED_TX_DATA(); let hash = data.transaction_hash; - let mut good_signature = ArrayTrait::new(); - good_signature.append(data.r); - good_signature.append(data.s); + let mut good_signature = array![data.r, data.s]; + let mut bad_signature = array![0x987, 0x564]; + let mut invalid_length_signature = array![0x987]; - let mut bad_signature = ArrayTrait::new(); - bad_signature.append(0x987); - bad_signature.append(0x564); + Account::PublicKeyImpl::set_public_key(ref state, data.public_key); - let mut invalid_length_signature = ArrayTrait::new(); - invalid_length_signature.append(0x987); - - Account::set_public_key(data.public_key); - - let is_valid = Account::_is_valid_signature(hash, good_signature.span()); + let is_valid = Account::InternalImpl::_is_valid_signature(@state, hash, good_signature.span()); assert(is_valid, 'Should accept valid signature'); - let is_valid = Account::_is_valid_signature(hash, bad_signature.span()); + let is_valid = Account::InternalImpl::_is_valid_signature(@state, hash, bad_signature.span()); assert(!is_valid, 'Should reject invalid signature'); - let is_valid = Account::_is_valid_signature(hash, invalid_length_signature.span()); + let is_valid = Account::InternalImpl::_is_valid_signature( + @state, hash, invalid_length_signature.span() + ); assert(!is_valid, 'Should reject invalid length'); } diff --git a/src/openzeppelin/tests/account/test_dual_account.cairo b/src/openzeppelin/tests/account/test_dual_account.cairo index 1d4e23840..76ea9fb99 100644 --- a/src/openzeppelin/tests/account/test_dual_account.cairo +++ b/src/openzeppelin/tests/account/test_dual_account.cairo @@ -1,13 +1,12 @@ -use array::ArrayTrait; use starknet::testing; use openzeppelin::account::dual_account::DualCaseAccount; -use openzeppelin::account::dual_account::DualCaseAccountTrait; -use openzeppelin::account::AccountABICamelDispatcher; -use openzeppelin::account::AccountABICamelDispatcherTrait; +use openzeppelin::account::dual_account::DualCaseAccountABI; +use openzeppelin::account::AccountCamelABIDispatcher; +use openzeppelin::account::AccountCamelABIDispatcherTrait; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; -use openzeppelin::introspection::src5::ISRC5_ID; +use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::account::test_account::SIGNED_TX_DATA; use openzeppelin::tests::mocks::account_panic_mock::CamelAccountPanicMock; use openzeppelin::tests::mocks::account_panic_mock::SnakeAccountPanicMock; @@ -15,7 +14,6 @@ use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::snake_account_mock::SnakeAccountMock; use openzeppelin::tests::utils; -use openzeppelin::utils::serde::SerializedAppend; // // Constants @@ -29,8 +27,7 @@ const NEW_PUBLIC_KEY: felt252 = 0x444444; // fn setup_snake() -> (DualCaseAccount, AccountABIDispatcher) { - let mut calldata = ArrayTrait::new(); - calldata.append_serde(PUBLIC_KEY); + let mut calldata = array![PUBLIC_KEY]; let target = utils::deploy(SnakeAccountMock::TEST_CLASS_HASH, calldata); ( DualCaseAccount { contract_address: target }, @@ -38,25 +35,24 @@ fn setup_snake() -> (DualCaseAccount, AccountABIDispatcher) { ) } -fn setup_camel() -> (DualCaseAccount, AccountABICamelDispatcher) { - let mut calldata = ArrayTrait::new(); - calldata.append_serde(PUBLIC_KEY); +fn setup_camel() -> (DualCaseAccount, AccountCamelABIDispatcher) { + let mut calldata = array![PUBLIC_KEY]; let target = utils::deploy(CamelAccountMock::TEST_CLASS_HASH, calldata); ( DualCaseAccount { contract_address: target }, - AccountABICamelDispatcher { contract_address: target } + AccountCamelABIDispatcher { contract_address: target } ) } fn setup_non_account() -> DualCaseAccount { - let calldata = ArrayTrait::new(); + let calldata = array![]; let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); DualCaseAccount { contract_address: target } } fn setup_account_panic() -> (DualCaseAccount, DualCaseAccount) { - let snake_target = utils::deploy(SnakeAccountPanicMock::TEST_CLASS_HASH, ArrayTrait::new()); - let camel_target = utils::deploy(CamelAccountPanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + let snake_target = utils::deploy(SnakeAccountPanicMock::TEST_CLASS_HASH, array![]); + let camel_target = utils::deploy(CamelAccountPanicMock::TEST_CLASS_HASH, array![]); ( DualCaseAccount { contract_address: snake_target }, DualCaseAccount { contract_address: camel_target } @@ -124,10 +120,7 @@ fn test_dual_is_valid_signature() { let data = SIGNED_TX_DATA(); let hash = data.transaction_hash; - - let mut signature = ArrayTrait::new(); - signature.append(data.r); - signature.append(data.s); + let mut signature = array![data.r, data.s]; testing::set_contract_address(snake_dispatcher.contract_address); target.set_public_key(data.public_key); @@ -141,7 +134,7 @@ fn test_dual_is_valid_signature() { #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_dual_no_is_valid_signature() { let hash = 0x0; - let signature = ArrayTrait::::new(); + let signature = array![]; let dispatcher = setup_non_account(); dispatcher.is_valid_signature(hash, signature); @@ -152,13 +145,12 @@ fn test_dual_no_is_valid_signature() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_is_valid_signature_exists_and_panics() { let hash = 0x0; - let signature = ArrayTrait::::new(); + let signature = array![]; let (dispatcher, _) = setup_account_panic(); dispatcher.is_valid_signature(hash, signature); } - #[test] #[available_gas(2000000)] fn test_dual_supports_interface() { @@ -227,10 +219,7 @@ fn test_dual_isValidSignature() { let data = SIGNED_TX_DATA(); let hash = data.transaction_hash; - - let mut signature = ArrayTrait::new(); - signature.append(data.r); - signature.append(data.s); + let mut signature = array![data.r, data.s]; testing::set_contract_address(camel_dispatcher.contract_address); target.setPublicKey(data.public_key); @@ -244,13 +233,12 @@ fn test_dual_isValidSignature() { #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] fn test_dual_isValidSignature_exists_and_panics() { let hash = 0x0; - let signature = ArrayTrait::::new(); + let signature = array![]; let (_, dispatcher) = setup_account_panic(); dispatcher.is_valid_signature(hash, signature); } - #[test] #[available_gas(2000000)] fn test_dual_supportsInterface() { @@ -265,3 +253,4 @@ fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_account_panic(); dispatcher.supports_interface(ISRC5_ID); } + diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index d8bdaa92b..3c1483fb3 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -8,11 +8,11 @@ // mod erc20_panic; // mod non721_mock; // mod accesscontrol_panic_mock; -// mod account_panic_mock; +mod account_panic_mock; // mod camel_accesscontrol_mock; -// mod camel_account_mock; +mod camel_account_mock; // mod snake_accesscontrol_mock; -// mod snake_account_mock; +mod snake_account_mock; // mod dual_ownable_mocks; // mod snake721_mock; // mod camel721_mock; diff --git a/src/openzeppelin/tests/mocks/account_panic_mock.cairo b/src/openzeppelin/tests/mocks/account_panic_mock.cairo index f3809b807..0a85c890c 100644 --- a/src/openzeppelin/tests/mocks/account_panic_mock.cairo +++ b/src/openzeppelin/tests/mocks/account_panic_mock.cairo @@ -4,53 +4,61 @@ // 3 for felt252 // false for bool -#[account_contract] +#[starknet::contract] mod SnakeAccountPanicMock { - #[external] - fn set_public_key(new_public_key: felt252) { + #[storage] + struct Storage {} + + #[external(v0)] + fn set_public_key(ref self: ContractState, new_public_key: felt252) { panic_with_felt252('Some error'); } - #[view] - fn get_public_key() -> felt252 { + #[external(v0)] + fn get_public_key(self: @ContractState) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn is_valid_signature(hash: felt252, signature: Array) -> felt252 { + #[external(v0)] + fn is_valid_signature( + self: @ContractState, hash: felt252, signature: Array + ) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn supports_interface(interface_id: felt252) -> bool { + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { panic_with_felt252('Some error'); false } } -#[account_contract] +#[starknet::contract] mod CamelAccountPanicMock { - #[external] - fn setPublicKey(newPublicKey: felt252) { + #[storage] + struct Storage {} + + #[external(v0)] + fn setPublicKey(ref self: ContractState, newPublicKey: felt252) { panic_with_felt252('Some error'); } - #[view] - fn getPublicKey() -> felt252 { + #[external(v0)] + fn getPublicKey(self: @ContractState) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn isValidSignature(hash: felt252, signature: Array) -> felt252 { + #[external(v0)] + fn isValidSignature(self: @ContractState, hash: felt252, signature: Array) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { panic_with_felt252('Some error'); false } diff --git a/src/openzeppelin/tests/mocks/camel_account_mock.cairo b/src/openzeppelin/tests/mocks/camel_account_mock.cairo index 01ee5b53e..19cf1725c 100644 --- a/src/openzeppelin/tests/mocks/camel_account_mock.cairo +++ b/src/openzeppelin/tests/mocks/camel_account_mock.cairo @@ -1,31 +1,37 @@ -#[account_contract] +#[starknet::contract] mod CamelAccountMock { - use openzeppelin::account::interface::Call; use openzeppelin::account::Account; - use openzeppelin::utils::serde::SpanSerde; + + #[storage] + struct Storage {} #[constructor] - fn constructor(_publicKey: felt252) { - Account::initializer(_publicKey); + fn constructor(ref self: ContractState, _publicKey: felt252) { + let mut unsafe_state = Account::unsafe_new_contract_state(); + Account::InternalImpl::initializer(ref unsafe_state, _publicKey); } - #[external] - fn setPublicKey(newPublicKey: felt252) { - Account::setPublicKey(newPublicKey); + #[external(v0)] + fn setPublicKey(ref self: ContractState, newPublicKey: felt252) { + let mut unsafe_state = Account::unsafe_new_contract_state(); + Account::PublicKeyCamelImpl::setPublicKey(ref unsafe_state, newPublicKey); } - #[view] - fn getPublicKey() -> felt252 { - Account::getPublicKey() + #[external(v0)] + fn getPublicKey(self: @ContractState) -> felt252 { + let unsafe_state = Account::unsafe_new_contract_state(); + Account::PublicKeyCamelImpl::getPublicKey(@unsafe_state) } - #[view] - fn isValidSignature(hash: felt252, signature: Array) -> felt252 { - Account::isValidSignature(hash, signature) + #[external(v0)] + fn isValidSignature(self: @ContractState, hash: felt252, signature: Array) -> felt252 { + let unsafe_state = Account::unsafe_new_contract_state(); + Account::SRC6CamelOnlyImpl::isValidSignature(@unsafe_state, hash, signature) } - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - Account::supportsInterface(interfaceId) + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = Account::unsafe_new_contract_state(); + Account::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) } } diff --git a/src/openzeppelin/tests/mocks/snake_account_mock.cairo b/src/openzeppelin/tests/mocks/snake_account_mock.cairo index 03b9cd05d..80dc1f715 100644 --- a/src/openzeppelin/tests/mocks/snake_account_mock.cairo +++ b/src/openzeppelin/tests/mocks/snake_account_mock.cairo @@ -1,53 +1,39 @@ -#[account_contract] +#[starknet::contract] mod SnakeAccountMock { - use openzeppelin::account::interface::Call; use openzeppelin::account::Account; - use openzeppelin::utils::serde::SpanSerde; - #[constructor] - fn constructor(_public_key: felt252) { - Account::initializer(_public_key); - } + #[storage] + struct Storage {} - #[external] - fn __execute__(mut calls: Array) -> Array> { - Account::__execute__(calls) + #[constructor] + fn constructor(ref self: ContractState, _public_key: felt252) { + let mut unsafe_state = Account::unsafe_new_contract_state(); + Account::InternalImpl::initializer(ref unsafe_state, _public_key); } - #[external] - fn __validate__(mut calls: Array) -> felt252 { - Account::__validate__(calls) + #[external(v0)] + fn set_public_key(ref self: ContractState, new_public_key: felt252) { + let mut unsafe_state = Account::unsafe_new_contract_state(); + Account::PublicKeyImpl::set_public_key(ref unsafe_state, new_public_key); } - #[external] - fn __validate_declare__(class_hash: felt252) -> felt252 { - Account::__validate_declare__(class_hash) + #[external(v0)] + fn get_public_key(self: @ContractState) -> felt252 { + let unsafe_state = Account::unsafe_new_contract_state(); + Account::PublicKeyImpl::get_public_key(@unsafe_state) } - #[external] - fn __validate_deploy__( - class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + #[external(v0)] + fn is_valid_signature( + self: @ContractState, hash: felt252, signature: Array ) -> felt252 { - Account::__validate_deploy__(class_hash, contract_address_salt, _public_key) - } - - #[external] - fn set_public_key(new_public_key: felt252) { - Account::set_public_key(new_public_key); - } - - #[view] - fn get_public_key() -> felt252 { - Account::get_public_key() - } - - #[view] - fn is_valid_signature(hash: felt252, signature: Array) -> felt252 { - Account::is_valid_signature(hash, signature) + let unsafe_state = Account::unsafe_new_contract_state(); + Account::SRC6Impl::is_valid_signature(@unsafe_state, hash, signature) } - #[view] - fn supports_interface(interface_id: felt252) -> bool { - Account::supports_interface(interface_id) + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = Account::unsafe_new_contract_state(); + Account::SRC5Impl::supports_interface(@unsafe_state, interface_id) } } From dc4a233cd0c56b80eadb51fd0a8dabd7fce135e7 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 20 Jul 2023 09:17:44 -0400 Subject: [PATCH 068/124] Migrate pausable to cairo2 (#662) * bump to cairo v2.0.2 * update Cargo * comment out mods * update initializable syntax * move security tests * update initializable tests * fix formatting * update pausable syntax * update pausable tests * update cairo * update Cargo * simplify and clarify tests * fix formatting * simplify and clarify tests * Apply suggestions from code review Co-authored-by: Eric Nordelo * fix tests * change StorageTrait to InternalTrait * use InternalImpl * add external pausable impl * Apply suggestions from code review Co-authored-by: Eric Nordelo --------- Co-authored-by: Eric Nordelo --- src/openzeppelin/security.cairo | 2 +- src/openzeppelin/security/pausable.cairo | 65 +++++++---- src/openzeppelin/tests/security.cairo | 2 +- .../tests/security/test_pausable.cairo | 104 ++++++++++++++---- 4 files changed, 127 insertions(+), 46 deletions(-) diff --git a/src/openzeppelin/security.cairo b/src/openzeppelin/security.cairo index 1e38ab41a..25183eb51 100644 --- a/src/openzeppelin/security.cairo +++ b/src/openzeppelin/security.cairo @@ -1,3 +1,3 @@ //mod reentrancyguard; -//mod pausable; +mod pausable; mod initializable; diff --git a/src/openzeppelin/security/pausable.cairo b/src/openzeppelin/security/pausable.cairo index 0a9018f51..66e159181 100644 --- a/src/openzeppelin/security/pausable.cairo +++ b/src/openzeppelin/security/pausable.cairo @@ -1,39 +1,60 @@ -#[contract] +#[starknet::interface] +trait IPausable { + fn is_paused(self: @TState) -> bool; +} + +#[starknet::contract] mod Pausable { use starknet::ContractAddress; use starknet::get_caller_address; + #[storage] struct Storage { paused: bool } #[event] - fn Paused(account: ContractAddress) {} - - #[event] - fn Unpaused(account: ContractAddress) {} - - fn is_paused() -> bool { - paused::read() + #[derive(Drop, starknet::Event)] + enum Event { + Paused: Paused, + Unpaused: Unpaused, } - - fn assert_not_paused() { - assert(!is_paused(), 'Pausable: paused'); + #[derive(Drop, starknet::Event)] + struct Paused { + account: ContractAddress } - - fn assert_paused() { - assert(is_paused(), 'Pausable: not paused'); + #[derive(Drop, starknet::Event)] + struct Unpaused { + account: ContractAddress } - fn pause() { - assert_not_paused(); - paused::write(true); - Paused(get_caller_address()); + #[external(v0)] + impl PausableImpl of super::IPausable { + fn is_paused(self: @ContractState) -> bool { + self.paused.read() + } } - fn unpause() { - assert_paused(); - paused::write(false); - Unpaused(get_caller_address()); + #[generate_trait] + impl InternalImpl of InternalTrait { + fn assert_not_paused(self: @ContractState) { + assert(!self.paused.read(), 'Pausable: paused'); + } + + fn assert_paused(self: @ContractState) { + assert(self.paused.read(), 'Pausable: not paused'); + } + + fn _pause(ref self: ContractState) { + self.assert_not_paused(); + self.paused.write(true); + self.emit(Paused { account: get_caller_address() }); + } + + fn _unpause(ref self: ContractState) { + self.assert_paused(); + self.paused.write(false); + self.emit(Unpaused { account: get_caller_address() }); + } } } diff --git a/src/openzeppelin/tests/security.cairo b/src/openzeppelin/tests/security.cairo index 56019a336..c350e48b3 100644 --- a/src/openzeppelin/tests/security.cairo +++ b/src/openzeppelin/tests/security.cairo @@ -1,5 +1,5 @@ mod test_initializable; -//mod test_pausable; +mod test_pausable; //mod test_reentrancyguard; diff --git a/src/openzeppelin/tests/security/test_pausable.cairo b/src/openzeppelin/tests/security/test_pausable.cairo index 6b76e9375..79bafced6 100644 --- a/src/openzeppelin/tests/security/test_pausable.cairo +++ b/src/openzeppelin/tests/security/test_pausable.cairo @@ -1,47 +1,107 @@ -use openzeppelin::tests::mocks::mock_pausable::MockPausable; +use openzeppelin::security::pausable::Pausable; +use openzeppelin::security::pausable::Pausable::PausableImpl; +use openzeppelin::security::pausable::Pausable::InternalImpl; + +fn STATE() -> Pausable::ContractState { + Pausable::contract_state_for_testing() +} + +// +// is_paused +// #[test] #[available_gas(2000000)] -fn test_pause_when_unpaused() { - assert(!MockPausable::is_paused(), 'Should not be paused'); - assert(MockPausable::get_count() == 0, 'Should be 0'); - MockPausable::assert_unpaused_and_increment(); - assert(MockPausable::get_count() == 1, 'Should increment'); - MockPausable::pause(); - assert(MockPausable::is_paused(), 'Should be paused'); +fn test_is_paused() { + let mut state = STATE(); + assert(!PausableImpl::is_paused(@state), 'Should not be paused'); + + InternalImpl::_pause(ref state); + assert(PausableImpl::is_paused(@state), 'Should be paused'); + + InternalImpl::_unpause(ref state); + assert(!PausableImpl::is_paused(@state), 'Should not be paused'); +} + +// +// assert_paused +// + +#[test] +#[available_gas(2000000)] +fn test_assert_paused_when_paused() { + let mut state = STATE(); + InternalImpl::_pause(ref state); + InternalImpl::assert_paused(@state); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Pausable: not paused', ))] +fn test_assert_paused_when_not_paused() { + let state = STATE(); + InternalImpl::assert_paused(@state); } +// +// assert_not_paused +// + #[test] #[available_gas(2000000)] #[should_panic(expected: ('Pausable: paused', ))] -fn test_pause_when_paused() { - MockPausable::pause(); - MockPausable::pause(); +fn test_assert_not_paused_when_paused() { + let mut state = STATE(); + InternalImpl::_pause(ref state); + InternalImpl::assert_not_paused(@state); +} + +#[test] +#[available_gas(2000000)] +fn test_assert_not_paused_when_not_paused() { + let state = STATE(); + InternalImpl::assert_not_paused(@state); +} + +// +// pause +// + +#[test] +#[available_gas(2000000)] +fn test_pause_when_unpaused() { + let mut state = STATE(); + InternalImpl::_pause(ref state); + assert(PausableImpl::is_paused(@state), 'Should be paused'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Pausable: paused', ))] -fn test_pause_increment() { - MockPausable::pause(); - MockPausable::assert_unpaused_and_increment(); +fn test_pause_when_paused() { + let mut state = STATE(); + InternalImpl::_pause(ref state); + InternalImpl::_pause(ref state); } +// +// unpause +// + #[test] #[available_gas(2000000)] fn test_unpause_when_paused() { - MockPausable::pause(); - assert(MockPausable::is_paused(), 'Should be paused'); - MockPausable::unpause(); - assert(!MockPausable::is_paused(), 'Should not be paused'); - MockPausable::assert_unpaused_and_increment(); - assert(MockPausable::get_count() == 1, 'Should increment'); + let mut state = STATE(); + InternalImpl::_pause(ref state); + InternalImpl::_unpause(ref state); + assert(!PausableImpl::is_paused(@state), 'Should not be paused'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Pausable: not paused', ))] fn test_unpause_when_unpaused() { - assert(!MockPausable::is_paused(), 'Should be unpaused'); - MockPausable::unpause(); + let mut state = STATE(); + assert(!PausableImpl::is_paused(@state), 'Should be paused'); + InternalImpl::_unpause(ref state); } From 27514b17a203a17d7c37dca14dcfcce7c2485e2e Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 20 Jul 2023 09:45:30 -0400 Subject: [PATCH 069/124] Migrate reentrancyguard to cairo2 (#663) * bump to cairo v2.0.2 * update Cargo * comment out mods * update initializable syntax * move security tests * update initializable tests * fix formatting * remove SpanSerde * update reentrancyguard syntax * add reentrancyguard mocks * update reentrancyguard tests * update cairo * update Cargo * simplify and clarify tests * fix formatting * simplify and clarify tests * fix formatting * Apply suggestions from code review Co-authored-by: Eric Nordelo * fix tests * change StorageTrait to InternalTrait * remove internal is_entered * use internal contract state * Apply suggestions from code review Co-authored-by: Eric Nordelo * fix import order * change generic state to TState --------- Co-authored-by: Eric Nordelo --- src/openzeppelin/security.cairo | 2 +- .../security/reentrancyguard.cairo | 18 ++- src/openzeppelin/tests/mocks.cairo | 4 +- .../mocks/reentrancy_attacker_mock.cairo | 26 ++-- .../tests/mocks/reentrancy_mock.cairo | 135 +++++++++--------- src/openzeppelin/tests/security.cairo | 4 +- .../tests/security/test_reentrancyguard.cairo | 31 ++-- src/openzeppelin/utils/serde.cairo | 2 - 8 files changed, 117 insertions(+), 105 deletions(-) diff --git a/src/openzeppelin/security.cairo b/src/openzeppelin/security.cairo index 25183eb51..45a9c998a 100644 --- a/src/openzeppelin/security.cairo +++ b/src/openzeppelin/security.cairo @@ -1,3 +1,3 @@ -//mod reentrancyguard; +mod reentrancyguard; mod pausable; mod initializable; diff --git a/src/openzeppelin/security/reentrancyguard.cairo b/src/openzeppelin/security/reentrancyguard.cairo index 4aa7375a6..17a2e8d9c 100644 --- a/src/openzeppelin/security/reentrancyguard.cairo +++ b/src/openzeppelin/security/reentrancyguard.cairo @@ -1,17 +1,21 @@ -#[contract] +#[starknet::contract] mod ReentrancyGuard { use starknet::get_caller_address; + #[storage] struct Storage { entered: bool } - fn start() { - assert(!entered::read(), 'ReentrancyGuard: reentrant call'); - entered::write(true); - } + #[generate_trait] + impl InternalImpl of InternalTrait { + fn start(ref self: ContractState) { + assert(!self.entered.read(), 'ReentrancyGuard: reentrant call'); + self.entered.write(true); + } - fn end() { - entered::write(false); + fn end(ref self: ContractState) { + self.entered.write(false); + } } } diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 3c1483fb3..b40cba35f 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -1,5 +1,5 @@ -// mod reentrancy_attacker_mock; -// mod reentrancy_mock; +mod reentrancy_attacker_mock; +mod reentrancy_mock; // mod erc721_receiver; // mod erc721_panic_mock; // mod mock_pausable; diff --git a/src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo b/src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo index 072432d00..39560f902 100644 --- a/src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo +++ b/src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo @@ -1,21 +1,23 @@ -#[abi] -trait IAttacker { - fn call_sender(); +#[starknet::interface] +trait IAttacker { + fn call_sender(self: @TState); } -#[contract] +#[starknet::contract] mod Attacker { - // Dispatcher + use starknet::ContractAddress; + use starknet::get_caller_address; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcherTrait; - // Other - use starknet::ContractAddress; - use starknet::get_caller_address; + #[storage] + struct Storage {} - #[external] - fn call_sender() { - let caller: ContractAddress = get_caller_address(); - IReentrancyMockDispatcher { contract_address: caller }.callback(); + #[external(v0)] + impl IAttackerImpl of super::IAttacker { + fn call_sender(self: @ContractState) { + let caller: ContractAddress = get_caller_address(); + IReentrancyMockDispatcher { contract_address: caller }.callback(); + } } } diff --git a/src/openzeppelin/tests/mocks/reentrancy_mock.cairo b/src/openzeppelin/tests/mocks/reentrancy_mock.cairo index a950d27f1..0850954c5 100644 --- a/src/openzeppelin/tests/mocks/reentrancy_mock.cairo +++ b/src/openzeppelin/tests/mocks/reentrancy_mock.cairo @@ -1,93 +1,92 @@ use starknet::ContractAddress; -#[abi] -trait IReentrancyGuarded { - fn count_external_recursive(n: felt252); +#[starknet::interface] +trait IReentrancyGuarded { + fn count_external_recursive(ref self: TState, n: felt252); } -#[abi] -trait IReentrancyMock { - #[view] - fn current_count() -> felt252; - #[external] - fn callback(); - #[external] - fn count_local_recursive(n: felt252); - #[external] - fn count_external_recursive(n: felt252); - #[external] - fn count_and_call(attacker: ContractAddress); - #[external] - fn count(); +#[starknet::interface] +trait IReentrancyMock { + fn current_count(self: @TState) -> felt252; + fn callback(ref self: TState); + fn count_local_recursive(ref self: TState, n: felt252); + fn count_external_recursive(ref self: TState, n: felt252); + fn count_and_call(ref self: TState, attacker: ContractAddress); } -#[contract] +#[starknet::contract] mod ReentrancyMock { - // OZ modules + use starknet::ContractAddress; + use starknet::get_contract_address; use openzeppelin::security::reentrancyguard::ReentrancyGuard; - - // Dispatchers - use super::IReentrancyGuardedDispatcher; - use super::IReentrancyGuardedDispatcherTrait; use openzeppelin::tests::mocks::reentrancy_attacker_mock::IAttackerDispatcher; use openzeppelin::tests::mocks::reentrancy_attacker_mock::IAttackerDispatcherTrait; + use super::IReentrancyGuardedDispatcher; + use super::IReentrancyGuardedDispatcherTrait; - // Other - use option::OptionTrait; - use starknet::ContractAddress; - use starknet::get_caller_address; - use starknet::get_contract_address; - + #[storage] struct Storage { counter: felt252 } - #[view] - fn current_count() -> felt252 { - counter::read() - } + #[generate_trait] + impl InternalImpl of InternalTrait { + fn count(ref self: ContractState) { + self.counter.write(self.counter.read() + 1); + } - #[external] - fn callback() { - ReentrancyGuard::start(); - count(); - ReentrancyGuard::end(); - } + fn _count_local_recursive(ref self: ContractState, n: felt252) { + let mut unsafe_state = ReentrancyGuard::unsafe_new_contract_state(); + ReentrancyGuard::InternalImpl::start(ref unsafe_state); - #[external] - fn count_local_recursive(n: felt252) { - ReentrancyGuard::start(); - gas::withdraw_gas().expect('Out of gas'); - if n != 0 { - count(); - count_local_recursive(n - 1); + if n != 0 { + self.count(); + self._count_local_recursive(n - 1); + } + + ReentrancyGuard::InternalImpl::end(ref unsafe_state); } - ReentrancyGuard::end(); } - #[external] - fn count_external_recursive(n: felt252) { - ReentrancyGuard::start(); - gas::withdraw_gas().expect('Out of gas'); - if n != 0 { - count(); - let this: ContractAddress = get_contract_address(); - IReentrancyGuardedDispatcher { contract_address: this }.count_external_recursive(n - 1) + #[external(v0)] + impl IReentrancyMockImpl of super::IReentrancyMock { + fn current_count(self: @ContractState) -> felt252 { + self.counter.read() } - ReentrancyGuard::end(); - } - #[external] - fn count_and_call(attacker: ContractAddress) { - ReentrancyGuard::start(); - gas::withdraw_gas().expect('Out of gas'); - count(); - IAttackerDispatcher { contract_address: attacker }.call_sender(); - ReentrancyGuard::end(); - } + fn callback(ref self: ContractState) { + let mut unsafe_state = ReentrancyGuard::unsafe_new_contract_state(); + ReentrancyGuard::InternalImpl::start(ref unsafe_state); + self.count(); + ReentrancyGuard::InternalImpl::end(ref unsafe_state); + } + + fn count_local_recursive(ref self: ContractState, n: felt252) { + self._count_local_recursive(n); + } + + fn count_external_recursive(ref self: ContractState, n: felt252) { + let mut unsafe_state = ReentrancyGuard::unsafe_new_contract_state(); + ReentrancyGuard::InternalImpl::start(ref unsafe_state); - #[external] - fn count() { - counter::write(counter::read() + 1); + if n != 0 { + self.count(); + let this: ContractAddress = get_contract_address(); + IReentrancyGuardedDispatcher { contract_address: this } + .count_external_recursive(n - 1) + } + + ReentrancyGuard::InternalImpl::end(ref unsafe_state); + } + + fn count_and_call(ref self: ContractState, attacker: ContractAddress) { + let mut unsafe_state = ReentrancyGuard::unsafe_new_contract_state(); + ReentrancyGuard::InternalImpl::start(ref unsafe_state); + + self.count(); + IAttackerDispatcher { contract_address: attacker }.call_sender(); + + ReentrancyGuard::InternalImpl::end(ref unsafe_state); + } } } diff --git a/src/openzeppelin/tests/security.cairo b/src/openzeppelin/tests/security.cairo index c350e48b3..1efdf53c8 100644 --- a/src/openzeppelin/tests/security.cairo +++ b/src/openzeppelin/tests/security.cairo @@ -1,5 +1,3 @@ mod test_initializable; +mod test_reentrancyguard; mod test_pausable; -//mod test_reentrancyguard; - - diff --git a/src/openzeppelin/tests/security/test_reentrancyguard.cairo b/src/openzeppelin/tests/security/test_reentrancyguard.cairo index 174035cb7..f0891b213 100644 --- a/src/openzeppelin/tests/security/test_reentrancyguard.cairo +++ b/src/openzeppelin/tests/security/test_reentrancyguard.cairo @@ -1,14 +1,18 @@ use openzeppelin::security::reentrancyguard::ReentrancyGuard; +use openzeppelin::security::reentrancyguard::ReentrancyGuard::InternalImpl; +use openzeppelin::security::reentrancyguard::ReentrancyGuard::entered::InternalContractStateTrait; use openzeppelin::tests::mocks::reentrancy_mock::ReentrancyMock; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcherTrait; use openzeppelin::tests::mocks::reentrancy_attacker_mock::Attacker; use openzeppelin::tests::utils; -use array::ArrayTrait; +fn STATE() -> ReentrancyGuard::ContractState { + ReentrancyGuard::contract_state_for_testing() +} fn deploy_mock() -> IReentrancyMockDispatcher { - let calldata = ArrayTrait::new(); + let calldata = array![]; let address = utils::deploy(ReentrancyMock::TEST_CLASS_HASH, calldata); IReentrancyMockDispatcher { contract_address: address } } @@ -20,25 +24,32 @@ fn deploy_mock() -> IReentrancyMockDispatcher { #[test] #[available_gas(2000000)] fn test_reentrancy_guard_start() { - assert(!ReentrancyGuard::entered::read(), 'Guard should not be active'); - ReentrancyGuard::start(); - assert(ReentrancyGuard::entered::read(), 'Guard should be active'); + let mut state = STATE(); + + assert(!state.entered.read(), 'Should not be entered'); + InternalImpl::start(ref state); + assert(state.entered.read(), 'Should be entered'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ReentrancyGuard: reentrant call', ))] fn test_reentrancy_guard_start_when_started() { - ReentrancyGuard::start(); - ReentrancyGuard::start(); + let mut state = STATE(); + + InternalImpl::start(ref state); + InternalImpl::start(ref state); } #[test] #[available_gas(2000000)] fn test_reentrancy_guard_end() { - ReentrancyGuard::start(); - ReentrancyGuard::end(); - assert(!ReentrancyGuard::entered::read(), 'Guard should not be active'); + let mut state = STATE(); + + InternalImpl::start(ref state); + assert(state.entered.read(), 'Should be entered'); + InternalImpl::end(ref state); + assert(!state.entered.read(), 'Should no longer be entered'); } // diff --git a/src/openzeppelin/utils/serde.cairo b/src/openzeppelin/utils/serde.cairo index 45b33c8e4..1b3ea8cd8 100644 --- a/src/openzeppelin/utils/serde.cairo +++ b/src/openzeppelin/utils/serde.cairo @@ -1,5 +1,3 @@ -use array::ArrayTrait; -use array::SpanTrait; use serde::Serde; trait SerializedAppend { From 8e108217b2e90c0c318b532c4c8898a55f0f320c Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 21 Jul 2023 18:04:18 +0200 Subject: [PATCH 070/124] Migrate ERC721 to Cairo2 (#667) * feat: migrate files * feat: add interface.cairo * feat: apply review updates * refactor: improve readability * fix: dual account tests * fix: account tests * fix: mocks * fix: dual721 tests * fix: erc721 tests * feat: apply review updates * feat: apply review suggestions --- src/openzeppelin/account/account.cairo | 1 - src/openzeppelin/lib.cairo | 2 +- src/openzeppelin/tests.cairo | 2 +- src/openzeppelin/tests/mocks.cairo | 11 +- .../tests/mocks/camel721_mock.cairo | 115 ++- .../tests/mocks/dual721_receiver_mocks.cairo | 86 +- .../tests/mocks/erc721_panic_mock.cairo | 118 +-- .../tests/mocks/erc721_receiver.cairo | 87 +- .../tests/mocks/non721_mock.cairo | 7 - .../tests/mocks/snake721_mock.cairo | 115 ++- src/openzeppelin/tests/token.cairo | 4 +- .../tests/token/test_dual20.cairo | 4 +- .../tests/token/test_dual721.cairo | 28 +- .../tests/token/test_erc721.cairo | 814 ++++++++++-------- src/openzeppelin/token.cairo | 2 +- src/openzeppelin/token/erc20.cairo | 6 +- src/openzeppelin/token/erc721.cairo | 7 +- src/openzeppelin/token/erc721/dual721.cairo | 28 +- .../token/erc721/dual721_receiver.cairo | 2 +- src/openzeppelin/token/erc721/erc721.cairo | 580 +++++-------- src/openzeppelin/token/erc721/interface.cairo | 102 ++- 21 files changed, 1096 insertions(+), 1025 deletions(-) delete mode 100644 src/openzeppelin/tests/mocks/non721_mock.cairo diff --git a/src/openzeppelin/account/account.cairo b/src/openzeppelin/account/account.cairo index 714f1f89f..e1a3d57dd 100644 --- a/src/openzeppelin/account/account.cairo +++ b/src/openzeppelin/account/account.cairo @@ -5,7 +5,6 @@ use serde::Serde; use starknet::account::Call; use starknet::ContractAddress; - const TRANSACTION_VERSION: felt252 = 1; // 2**128 + TRANSACTION_VERSION diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index 5c658386e..ef3dfb94f 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -3,5 +3,5 @@ mod account; mod introspection; mod security; mod tests; -// mod token; +mod token; mod utils; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index 440fdfc2f..d2a724b37 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -3,5 +3,5 @@ mod account; mod introspection; mod mocks; mod security; -// mod token; +mod token; mod utils; diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index b40cba35f..0e838248e 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -1,12 +1,11 @@ mod reentrancy_attacker_mock; mod reentrancy_mock; -// mod erc721_receiver; -// mod erc721_panic_mock; +mod erc721_receiver; +mod erc721_panic_mock; // mod mock_pausable; // mod camel20_mock; // mod snake20_mock; // mod erc20_panic; -// mod non721_mock; // mod accesscontrol_panic_mock; mod account_panic_mock; // mod camel_accesscontrol_mock; @@ -14,8 +13,8 @@ mod camel_account_mock; // mod snake_accesscontrol_mock; mod snake_account_mock; // mod dual_ownable_mocks; -// mod snake721_mock; -// mod camel721_mock; +mod snake721_mock; +mod camel721_mock; mod non_implementing_mock; -// mod dual721_receiver_mocks; +mod dual721_receiver_mocks; mod src5_mocks; diff --git a/src/openzeppelin/tests/mocks/camel721_mock.cairo b/src/openzeppelin/tests/mocks/camel721_mock.cairo index b2e02793b..553114f7e 100644 --- a/src/openzeppelin/tests/mocks/camel721_mock.cairo +++ b/src/openzeppelin/tests/mocks/camel721_mock.cairo @@ -1,80 +1,103 @@ -#[contract] +#[starknet::contract] mod CamelERC721Mock { use starknet::ContractAddress; use starknet::get_caller_address; use openzeppelin::token::erc721::ERC721; - use openzeppelin::utils::serde::SpanSerde; + use openzeppelin::token::erc721::ERC721::InternalImpl; + use openzeppelin::token::erc721::ERC721::ERC721CamelOnlyImpl; + + #[storage] + struct Storage {} #[constructor] - fn constructor(name: felt252, symbol: felt252, tokenId: u256, uri: felt252) { - ERC721::initializer(name, symbol); - ERC721::_mint(get_caller_address(), tokenId); - ERC721::_set_token_uri(tokenId, uri); + fn constructor( + ref self: ContractState, name: felt252, symbol: felt252, tokenId: u256, uri: felt252 + ) { + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + InternalImpl::initializer(ref unsafe_state, name, symbol); + InternalImpl::_mint(ref unsafe_state, get_caller_address(), tokenId); + InternalImpl::_set_token_uri(ref unsafe_state, tokenId, uri); } - // View - - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - ERC721::supportsInterface(interfaceId) + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) } - #[view] - fn name() -> felt252 { - ERC721::name() + #[external(v0)] + fn name(self: @ContractState) -> felt252 { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::ERC721MetadataImpl::name(@unsafe_state) } - #[view] - fn symbol() -> felt252 { - ERC721::symbol() + #[external(v0)] + fn symbol(self: @ContractState) -> felt252 { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::ERC721MetadataImpl::symbol(@unsafe_state) } - #[view] - fn tokenUri(tokenId: u256) -> felt252 { - ERC721::tokenUri(tokenId) + #[external(v0)] + fn tokenUri(self: @ContractState, tokenId: u256) -> felt252 { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::ERC721MetadataCamelOnlyImpl::tokenUri(@unsafe_state, tokenId) } - #[view] - fn balanceOf(account: ContractAddress) -> u256 { - ERC721::balanceOf(account) + #[external(v0)] + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721CamelOnlyImpl::balanceOf(@unsafe_state, account) } - #[view] - fn ownerOf(tokenId: u256) -> ContractAddress { - ERC721::ownerOf(tokenId) + #[external(v0)] + fn ownerOf(self: @ContractState, tokenId: u256) -> ContractAddress { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721CamelOnlyImpl::ownerOf(@unsafe_state, tokenId) } - #[view] - fn getApproved(tokenId: u256) -> ContractAddress { - ERC721::getApproved(tokenId) + #[external(v0)] + fn getApproved(self: @ContractState, tokenId: u256) -> ContractAddress { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721CamelOnlyImpl::getApproved(@unsafe_state, tokenId) } - #[view] - fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool { - ERC721::isApprovedForAll(owner, operator) + #[external(v0)] + fn isApprovedForAll( + self: @ContractState, owner: ContractAddress, operator: ContractAddress + ) -> bool { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721CamelOnlyImpl::isApprovedForAll(@unsafe_state, owner, operator) } - // External - - #[external] - fn approve(to: ContractAddress, tokenId: u256) { - ERC721::approve(to, tokenId) + #[external(v0)] + fn approve(ref self: ContractState, to: ContractAddress, tokenId: u256) { + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::ERC721Impl::approve(ref unsafe_state, to, tokenId) } - #[external] - fn setApprovalForAll(operator: ContractAddress, approved: bool) { - ERC721::setApprovalForAll(operator, approved) + #[external(v0)] + fn setApprovalForAll(ref self: ContractState, operator: ContractAddress, approved: bool) { + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721CamelOnlyImpl::setApprovalForAll(ref unsafe_state, operator, approved) } - #[external] - fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256) { - ERC721::transferFrom(from, to, tokenId) + #[external(v0)] + fn transferFrom( + ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256 + ) { + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721CamelOnlyImpl::transferFrom(ref unsafe_state, from, to, tokenId) } - #[external] + #[external(v0)] fn safeTransferFrom( - from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ref self: ContractState, + from: ContractAddress, + to: ContractAddress, + tokenId: u256, + data: Span ) { - ERC721::safeTransferFrom(from, to, tokenId, data) + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721CamelOnlyImpl::safeTransferFrom(ref unsafe_state, from, to, tokenId, data) } } diff --git a/src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo b/src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo index 3ffb3df74..897918b68 100644 --- a/src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo +++ b/src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo @@ -2,80 +2,110 @@ use openzeppelin::introspection::src5::SRC5; use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver::IERC721_RECEIVER_ID; -#[contract] +#[starknet::contract] mod SnakeERC721ReceiverMock { - use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; use super::ERC721Receiver; use super::IERC721_RECEIVER_ID; use super::SRC5; + #[storage] + struct Storage {} + #[constructor] - fn constructor() { - SRC5::register_interface(IERC721_RECEIVER_ID); + fn constructor(ref self: ContractState) { + let mut unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::InternalImpl::register_interface(ref unsafe_state, IERC721_RECEIVER_ID); } - #[view] + #[external(v0)] fn on_erc721_received( - operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + self: @ContractState, + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + data: Span ) -> felt252 { - ERC721Receiver::on_erc721_received(operator, from, token_id, data) + let unsafe_state = ERC721Receiver::unsafe_new_contract_state(); + ERC721Receiver::on_erc721_received(@unsafe_state, operator, from, token_id, data) } - #[view] - fn supports_interface(interface_id: felt252) -> bool { - ERC721Receiver::supports_interface(interface_id) + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = ERC721Receiver::unsafe_new_contract_state(); + ERC721Receiver::supports_interface(@unsafe_state, interface_id) } } -#[contract] +#[starknet::contract] mod CamelERC721ReceiverMock { - use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; use super::ERC721Receiver; use super::IERC721_RECEIVER_ID; use super::SRC5; + #[storage] + struct Storage {} + #[constructor] - fn constructor() { - SRC5::register_interface(IERC721_RECEIVER_ID); + fn constructor(ref self: ContractState) { + let mut unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::InternalImpl::register_interface(ref unsafe_state, IERC721_RECEIVER_ID); } - #[view] + #[external(v0)] fn onERC721Received( - operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + self: @ContractState, + operator: ContractAddress, + from: ContractAddress, + tokenId: u256, + data: Span ) -> felt252 { - ERC721Receiver::on_erc721_received(operator, from, tokenId, data) + let unsafe_state = ERC721Receiver::unsafe_new_contract_state(); + ERC721Receiver::on_erc721_received(@unsafe_state, operator, from, tokenId, data) } - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - ERC721Receiver::supportsInterface(interfaceId) + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = ERC721Receiver::unsafe_new_contract_state(); + ERC721Receiver::supportsInterface(@unsafe_state, interfaceId) } } -#[contract] +#[starknet::contract] mod SnakeERC721ReceiverPanicMock { - use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; - #[view] + #[storage] + struct Storage {} + + #[external(v0)] fn on_erc721_received( - operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + self: @ContractState, + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + data: Span ) -> felt252 { panic_with_felt252('Some error'); 3 } } -#[contract] +#[starknet::contract] mod CamelERC721ReceiverPanicMock { - use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; - #[view] + #[storage] + struct Storage {} + + #[external(v0)] fn onERC721Received( - operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + self: @ContractState, + operator: ContractAddress, + from: ContractAddress, + tokenId: u256, + data: Span ) -> felt252 { panic_with_felt252('Some error'); 3 diff --git a/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo b/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo index b824bf125..6d172c379 100644 --- a/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo +++ b/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo @@ -5,146 +5,158 @@ // zero for ContractAddress // u256 { 3, 3 } for u256 -#[contract] +#[starknet::contract] mod SnakeERC721PanicMock { - use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; use zeroable::Zeroable; - // - // agnostic - // + #[storage] + struct Storage {} - #[view] - fn name() -> felt252 { + #[external(v0)] + fn name(self: @ContractState) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn symbol() -> felt252 { + #[external(v0)] + fn symbol(self: @ContractState) -> felt252 { panic_with_felt252('Some error'); 3 } - #[external] - fn approve(to: ContractAddress, token_id: u256) { + #[external(v0)] + fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) { panic_with_felt252('Some error'); } - // - // snake - // - - #[view] - fn supports_interface(interface_id: felt252) -> bool { + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { panic_with_felt252('Some error'); false } - #[view] - fn token_uri(token_id: u256) -> felt252 { + #[external(v0)] + fn token_uri(self: @ContractState, token_id: u256) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn balance_of(account: ContractAddress) -> u256 { + #[external(v0)] + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { panic_with_felt252('Some error'); u256 { low: 3, high: 3 } } - #[view] - fn owner_of(token_id: u256) -> ContractAddress { + #[external(v0)] + fn owner_of(self: @ContractState, token_id: u256) -> ContractAddress { panic_with_felt252('Some error'); Zeroable::zero() } - #[view] - fn get_approved(token_id: u256) -> ContractAddress { + #[external(v0)] + fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress { panic_with_felt252('Some error'); Zeroable::zero() } - #[view] - fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool { + #[external(v0)] + fn is_approved_for_all( + self: @ContractState, owner: ContractAddress, operator: ContractAddress + ) -> bool { panic_with_felt252('Some error'); false } - #[external] - fn set_approval_for_all(operator: ContractAddress, approved: bool) { + #[external(v0)] + fn set_approval_for_all(ref self: ContractState, operator: ContractAddress, approved: bool) { panic_with_felt252('Some error'); } - #[external] - fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) { + #[external(v0)] + fn transfer_from( + ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ) { panic_with_felt252('Some error'); } - #[external] + #[external(v0)] fn safe_transfer_from( - from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ref self: ContractState, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span ) { panic_with_felt252('Some error'); } } -#[contract] +#[starknet::contract] mod CamelERC721PanicMock { - use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; use zeroable::Zeroable; - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { + #[storage] + struct Storage {} + + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { panic_with_felt252('Some error'); false } - #[view] - fn tokenUri(tokenId: u256) -> felt252 { + #[external(v0)] + fn tokenUri(self: @ContractState, tokenId: u256) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn balanceOf(account: ContractAddress) -> u256 { + #[external(v0)] + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { panic_with_felt252('Some error'); u256 { low: 3, high: 3 } } - #[view] - fn ownerOf(tokenId: u256) -> ContractAddress { + #[external(v0)] + fn ownerOf(self: @ContractState, tokenId: u256) -> ContractAddress { panic_with_felt252('Some error'); Zeroable::zero() } - #[view] - fn getApproved(tokenId: u256) -> ContractAddress { + #[external(v0)] + fn getApproved(self: @ContractState, tokenId: u256) -> ContractAddress { panic_with_felt252('Some error'); Zeroable::zero() } - #[view] - fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool { + #[external(v0)] + fn isApprovedForAll( + self: @ContractState, owner: ContractAddress, operator: ContractAddress + ) -> bool { panic_with_felt252('Some error'); false } - #[external] - fn setApprovalForAll(operator: ContractAddress, approved: bool) { + #[external(v0)] + fn setApprovalForAll(ref self: ContractState, operator: ContractAddress, approved: bool) { panic_with_felt252('Some error'); } - #[external] - fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256) { + #[external(v0)] + fn transferFrom( + ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256 + ) { panic_with_felt252('Some error'); } - #[external] + #[external(v0)] fn safeTransferFrom( - from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ref self: ContractState, + from: ContractAddress, + to: ContractAddress, + tokenId: u256, + data: Span ) { panic_with_felt252('Some error'); } diff --git a/src/openzeppelin/tests/mocks/erc721_receiver.cairo b/src/openzeppelin/tests/mocks/erc721_receiver.cairo index aff07e7aa..673e4100e 100644 --- a/src/openzeppelin/tests/mocks/erc721_receiver.cairo +++ b/src/openzeppelin/tests/mocks/erc721_receiver.cairo @@ -1,37 +1,48 @@ const SUCCESS: felt252 = 123123; const FAILURE: felt252 = 456456; -#[contract] +#[starknet::contract] mod ERC721Receiver { + use array::SpanTrait; + use starknet::ContractAddress; + use openzeppelin::token::erc721::interface::IERC721Receiver; use openzeppelin::token::erc721::interface::IERC721ReceiverCamel; use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; - use openzeppelin::introspection::src5; + use openzeppelin::introspection::interface::ISRC5; + use openzeppelin::introspection::interface::ISRC5Camel; + use openzeppelin::introspection::src5::SRC5; - use array::SpanTrait; - use openzeppelin::utils::serde::SpanSerde; - use starknet::ContractAddress; + #[storage] + struct Storage {} #[constructor] - fn constructor() { - src5::SRC5::register_interface(IERC721_RECEIVER_ID); + fn constructor(ref self: ContractState) { + let mut unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::InternalImpl::register_interface(ref unsafe_state, IERC721_RECEIVER_ID); } - impl ISRC5Impl of src5::ISRC5 { - fn supports_interface(interface_id: felt252) -> bool { - src5::SRC5::supports_interface(interface_id) + impl ISRC5Impl of ISRC5 { + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) } } - impl ISRC5CamelImpl of src5::ISRC5Camel { - fn supportsInterface(interfaceId: felt252) -> bool { - src5::SRC5::supportsInterface(interfaceId) + impl ISRC5CamelImpl of ISRC5Camel { + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) } } - impl ERC721ReceiverImpl of IERC721Receiver { + impl ERC721ReceiverImpl of IERC721Receiver { fn on_erc721_received( - operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + self: @ContractState, + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + data: Span ) -> felt252 { if *data.at(0) == super::SUCCESS { IERC721_RECEIVER_ID @@ -41,39 +52,47 @@ mod ERC721Receiver { } } - impl ERC721ReceiverCamelImpl of IERC721ReceiverCamel { + impl ERC721ReceiverCamelImpl of IERC721ReceiverCamel { fn onERC721Received( - operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + self: @ContractState, + operator: ContractAddress, + from: ContractAddress, + tokenId: u256, + data: Span ) -> felt252 { - ERC721ReceiverImpl::on_erc721_received(operator, from, tokenId, data) + ERC721ReceiverImpl::on_erc721_received(self, operator, from, tokenId, data) } } - #[view] - fn supports_interface(interface_id: felt252) -> bool { - ISRC5Impl::supports_interface(interface_id) + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + ISRC5Impl::supports_interface(self, interface_id) } - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - ISRC5CamelImpl::supportsInterface(interfaceId) + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + ISRC5CamelImpl::supportsInterface(self, interfaceId) } - #[external] + #[external(v0)] fn on_erc721_received( - operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + self: @ContractState, + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + data: Span ) -> felt252 { - ERC721ReceiverImpl::on_erc721_received(operator, from, token_id, data) + ERC721ReceiverImpl::on_erc721_received(self, operator, from, token_id, data) } - #[external] + #[external(v0)] fn onERC721Received( - operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + self: @ContractState, + operator: ContractAddress, + from: ContractAddress, + tokenId: u256, + data: Span ) -> felt252 { - ERC721ReceiverCamelImpl::onERC721Received(operator, from, tokenId, data) + ERC721ReceiverCamelImpl::onERC721Received(self, operator, from, tokenId, data) } } - - -#[contract] -mod ERC721NonReceiver {} diff --git a/src/openzeppelin/tests/mocks/non721_mock.cairo b/src/openzeppelin/tests/mocks/non721_mock.cairo deleted file mode 100644 index 05c7d140c..000000000 --- a/src/openzeppelin/tests/mocks/non721_mock.cairo +++ /dev/null @@ -1,7 +0,0 @@ -#[contract] -mod NonERC721 { - #[view] - fn nope() -> bool { - false - } -} diff --git a/src/openzeppelin/tests/mocks/snake721_mock.cairo b/src/openzeppelin/tests/mocks/snake721_mock.cairo index eca3d70cb..13335a52f 100644 --- a/src/openzeppelin/tests/mocks/snake721_mock.cairo +++ b/src/openzeppelin/tests/mocks/snake721_mock.cairo @@ -1,80 +1,103 @@ -#[contract] +#[starknet::contract] mod SnakeERC721Mock { use starknet::ContractAddress; use starknet::get_caller_address; use openzeppelin::token::erc721::ERC721; - use openzeppelin::utils::serde::SpanSerde; + use openzeppelin::token::erc721::ERC721::InternalImpl; + use openzeppelin::token::erc721::ERC721::ERC721Impl; + + #[storage] + struct Storage {} #[constructor] - fn constructor(name: felt252, symbol: felt252, token_id: u256, uri: felt252) { - ERC721::initializer(name, symbol); - ERC721::_mint(get_caller_address(), token_id); - ERC721::_set_token_uri(token_id, uri); + fn constructor( + ref self: ContractState, name: felt252, symbol: felt252, token_id: u256, uri: felt252 + ) { + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + InternalImpl::initializer(ref unsafe_state, name, symbol); + InternalImpl::_mint(ref unsafe_state, get_caller_address(), token_id); + InternalImpl::_set_token_uri(ref unsafe_state, token_id, uri); } - // View - - #[view] - fn supports_interface(interface_id: felt252) -> bool { - ERC721::supports_interface(interface_id) + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::SRC5Impl::supports_interface(@unsafe_state, interface_id) } - #[view] - fn name() -> felt252 { - ERC721::name() + #[external(v0)] + fn name(self: @ContractState) -> felt252 { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::ERC721MetadataImpl::name(@unsafe_state) } - #[view] - fn symbol() -> felt252 { - ERC721::symbol() + #[external(v0)] + fn symbol(self: @ContractState) -> felt252 { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::ERC721MetadataImpl::symbol(@unsafe_state) } - #[view] - fn token_uri(token_id: u256) -> felt252 { - ERC721::token_uri(token_id) + #[external(v0)] + fn token_uri(self: @ContractState, token_id: u256) -> felt252 { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721::ERC721MetadataImpl::token_uri(@unsafe_state, token_id) } - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC721::balance_of(account) + #[external(v0)] + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721Impl::balance_of(@unsafe_state, account) } - #[view] - fn owner_of(token_id: u256) -> ContractAddress { - ERC721::owner_of(token_id) + #[external(v0)] + fn owner_of(self: @ContractState, token_id: u256) -> ContractAddress { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721Impl::owner_of(@unsafe_state, token_id) } - #[view] - fn get_approved(token_id: u256) -> ContractAddress { - ERC721::get_approved(token_id) + #[external(v0)] + fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721Impl::get_approved(@unsafe_state, token_id) } - #[view] - fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool { - ERC721::is_approved_for_all(owner, operator) + #[external(v0)] + fn is_approved_for_all( + self: @ContractState, owner: ContractAddress, operator: ContractAddress + ) -> bool { + let unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721Impl::is_approved_for_all(@unsafe_state, owner, operator) } - // External - - #[external] - fn approve(to: ContractAddress, token_id: u256) { - ERC721::approve(to, token_id) + #[external(v0)] + fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) { + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721Impl::approve(ref unsafe_state, to, token_id) } - #[external] - fn set_approval_for_all(operator: ContractAddress, approved: bool) { - ERC721::set_approval_for_all(operator, approved) + #[external(v0)] + fn set_approval_for_all(ref self: ContractState, operator: ContractAddress, approved: bool) { + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721Impl::set_approval_for_all(ref unsafe_state, operator, approved) } - #[external] - fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) { - ERC721::transfer_from(from, to, token_id) + #[external(v0)] + fn transfer_from( + ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ) { + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721Impl::transfer_from(ref unsafe_state, from, to, token_id) } - #[external] + #[external(v0)] fn safe_transfer_from( - from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ref self: ContractState, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span ) { - ERC721::safe_transfer_from(from, to, token_id, data) + let mut unsafe_state = ERC721::unsafe_new_contract_state(); + ERC721Impl::safe_transfer_from(ref unsafe_state, from, to, token_id, data) } } diff --git a/src/openzeppelin/tests/token.cairo b/src/openzeppelin/tests/token.cairo index ebb5dc5c4..ffee08cb1 100644 --- a/src/openzeppelin/tests/token.cairo +++ b/src/openzeppelin/tests/token.cairo @@ -1,5 +1,5 @@ -mod test_dual20; +// mod test_dual20; mod test_dual721; -mod test_erc20; +// mod test_erc20; mod test_erc721; mod test_dual721_receiver; diff --git a/src/openzeppelin/tests/token/test_dual20.cairo b/src/openzeppelin/tests/token/test_dual20.cairo index 1afa77c31..52d0f0906 100644 --- a/src/openzeppelin/tests/token/test_dual20.cairo +++ b/src/openzeppelin/tests/token/test_dual20.cairo @@ -6,7 +6,7 @@ use starknet::testing::set_contract_address; use openzeppelin::tests::mocks::camel20_mock::CamelERC20Mock; use openzeppelin::tests::mocks::erc20_panic::SnakeERC20Panic; use openzeppelin::tests::mocks::erc20_panic::CamelERC20Panic; -use openzeppelin::tests::mocks::non721_mock::NonERC721; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::snake20_mock::SnakeERC20Mock; use openzeppelin::token::erc20::dual20::DualERC20; use openzeppelin::token::erc20::dual20::DualERC20Trait; @@ -66,7 +66,7 @@ fn setup_camel() -> (DualERC20, IERC20CamelDispatcher) { fn setup_non_erc20() -> DualERC20 { let calldata = ArrayTrait::new(); - let target = utils::deploy(NonERC721::TEST_CLASS_HASH, calldata); + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); DualERC20 { contract_address: target } } diff --git a/src/openzeppelin/tests/token/test_dual721.cairo b/src/openzeppelin/tests/token/test_dual721.cairo index b0e45e568..dfaa53bad 100644 --- a/src/openzeppelin/tests/token/test_dual721.cairo +++ b/src/openzeppelin/tests/token/test_dual721.cairo @@ -5,9 +5,9 @@ use starknet::testing::set_caller_address; use starknet::testing::set_contract_address; use openzeppelin::token::erc721::interface::IERC721_ID; use openzeppelin::token::erc721::interface::IERC721Dispatcher; -use openzeppelin::token::erc721::interface::IERC721CamelDispatcher; +use openzeppelin::token::erc721::interface::IERC721CamelOnlyDispatcher; use openzeppelin::token::erc721::interface::IERC721DispatcherTrait; -use openzeppelin::token::erc721::interface::IERC721CamelDispatcherTrait; +use openzeppelin::token::erc721::interface::IERC721CamelOnlyDispatcherTrait; use openzeppelin::token::erc721::dual721::DualCaseERC721Trait; use openzeppelin::token::erc721::dual721::DualCaseERC721; use openzeppelin::tests::mocks::snake721_mock::SnakeERC721Mock; @@ -43,7 +43,7 @@ fn OPERATOR() -> ContractAddress { contract_address_const::<40>() } fn DATA(success: bool) -> Span { - let mut data = ArrayTrait::new(); + let mut data = array![]; if success { data.append_serde(SUCCESS); } else { @@ -57,7 +57,7 @@ fn DATA(success: bool) -> Span { // fn setup_snake() -> (DualCaseERC721, IERC721Dispatcher) { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; calldata.append_serde(NAME); calldata.append_serde(SYMBOL); calldata.append_serde(TOKEN_ID); @@ -67,8 +67,8 @@ fn setup_snake() -> (DualCaseERC721, IERC721Dispatcher) { (DualCaseERC721 { contract_address: target }, IERC721Dispatcher { contract_address: target }) } -fn setup_camel() -> (DualCaseERC721, IERC721CamelDispatcher) { - let mut calldata = ArrayTrait::new(); +fn setup_camel() -> (DualCaseERC721, IERC721CamelOnlyDispatcher) { + let mut calldata = array![]; calldata.append_serde(NAME); calldata.append_serde(SYMBOL); calldata.append_serde(TOKEN_ID); @@ -77,19 +77,19 @@ fn setup_camel() -> (DualCaseERC721, IERC721CamelDispatcher) { let target = utils::deploy(CamelERC721Mock::TEST_CLASS_HASH, calldata); ( DualCaseERC721 { contract_address: target }, - IERC721CamelDispatcher { contract_address: target } + IERC721CamelOnlyDispatcher { contract_address: target } ) } fn setup_non_erc721() -> DualCaseERC721 { - let calldata = ArrayTrait::new(); + let calldata = array![]; let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); DualCaseERC721 { contract_address: target } } fn setup_erc721_panic() -> (DualCaseERC721, DualCaseERC721) { - let snake_target = utils::deploy(SnakeERC721PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); - let camel_target = utils::deploy(CamelERC721PanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + let snake_target = utils::deploy(SnakeERC721PanicMock::TEST_CLASS_HASH, array![]); + let camel_target = utils::deploy(CamelERC721PanicMock::TEST_CLASS_HASH, array![]); ( DualCaseERC721 { contract_address: snake_target }, DualCaseERC721 { contract_address: camel_target } @@ -97,7 +97,7 @@ fn setup_erc721_panic() -> (DualCaseERC721, DualCaseERC721) { } fn setup_receiver() -> ContractAddress { - utils::deploy(ERC721Receiver::TEST_CLASS_HASH, ArrayTrait::new()) + utils::deploy(ERC721Receiver::TEST_CLASS_HASH, array![]) } // @@ -155,7 +155,7 @@ fn test_dual_symbol_exists_and_panics() { } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_dual_approve() { let (snake_dispatcher, snake_target) = setup_snake(); set_contract_address(OWNER()); @@ -475,9 +475,9 @@ fn test_dual_safeTransferFrom_exists_and_panics() { #[test] #[available_gas(2000000)] fn test_dual_getApproved() { - let (dispatcher, target) = setup_camel(); + let (dispatcher, _) = setup_camel(); set_contract_address(OWNER()); - target.approve(SPENDER(), TOKEN_ID); + dispatcher.approve(SPENDER(), TOKEN_ID); assert(dispatcher.get_approved(TOKEN_ID) == SPENDER(), 'Should return approval'); } diff --git a/src/openzeppelin/tests/token/test_erc721.cairo b/src/openzeppelin/tests/token/test_erc721.cairo index 5037ae251..5c7fdc4f9 100644 --- a/src/openzeppelin/tests/token/test_erc721.cairo +++ b/src/openzeppelin/tests/token/test_erc721.cairo @@ -1,16 +1,3 @@ -use openzeppelin::account::Account; -use openzeppelin::introspection::src5; -use openzeppelin::token::erc721; -use openzeppelin::token::erc721::ERC721; - -use openzeppelin::tests::utils; -use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; -use openzeppelin::tests::mocks::erc721_receiver::ERC721NonReceiver; -use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; -use openzeppelin::tests::mocks::erc721_receiver::FAILURE; -use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; -use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; - use starknet::contract_address_const; use starknet::ContractAddress; use starknet::testing::set_caller_address; @@ -20,12 +7,38 @@ use array::ArrayTrait; use traits::Into; use zeroable::Zeroable; +use openzeppelin::account::Account; +use openzeppelin::introspection; +use openzeppelin::introspection::src5; +use openzeppelin::token::erc721; +use openzeppelin::token::erc721::ERC721; +use openzeppelin::token::erc721::ERC721::ERC721CamelOnlyImpl; +use openzeppelin::token::erc721::ERC721::ERC721Impl; +use openzeppelin::token::erc721::ERC721::ERC721MetadataCamelOnlyImpl; +use openzeppelin::token::erc721::ERC721::ERC721MetadataImpl; +use openzeppelin::token::erc721::ERC721::InternalImpl; +use openzeppelin::token::erc721::ERC721::SRC5CamelImpl; +use openzeppelin::token::erc721::ERC721::SRC5Impl; +use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; +use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; +use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; +use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; +use openzeppelin::tests::mocks::erc721_receiver::FAILURE; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils; + +use ERC721::_owners::InternalContractStateTrait as OwnersTrait; +use ERC721::_token_approvals::InternalContractStateTrait as TokenApprovalsTrait; + const NAME: felt252 = 111; const SYMBOL: felt252 = 222; const URI: felt252 = 333; const TOKEN_ID: u256 = 7; const PUBKEY: felt252 = 444; +fn STATE() -> ERC721::ContractState { + ERC721::contract_state_for_testing() +} fn ZERO() -> ContractAddress { Zeroable::zero() } @@ -46,7 +59,7 @@ fn OTHER() -> ContractAddress { } fn DATA(success: bool) -> Span { - let mut data = ArrayTrait::new(); + let mut data = array![]; if success { data.append(SUCCESS); } else { @@ -59,28 +72,28 @@ fn DATA(success: bool) -> Span { // Setup // -fn setup() { - ERC721::initializer(NAME, SYMBOL); - ERC721::_mint(OWNER(), TOKEN_ID); +fn setup() -> ERC721::ContractState { + let mut state = STATE(); + InternalImpl::initializer(ref state, NAME, SYMBOL); + InternalImpl::_mint(ref state, OWNER(), TOKEN_ID); + state } fn setup_receiver() -> ContractAddress { - utils::deploy(ERC721Receiver::TEST_CLASS_HASH, ArrayTrait::new()) + utils::deploy(ERC721Receiver::TEST_CLASS_HASH, array![]) } fn setup_camel_receiver() -> ContractAddress { - utils::deploy(CamelERC721ReceiverMock::TEST_CLASS_HASH, ArrayTrait::new()) + utils::deploy(CamelERC721ReceiverMock::TEST_CLASS_HASH, array![]) } fn setup_account() -> ContractAddress { - let mut calldata = ArrayTrait::new(); - calldata.append(PUBKEY); + let mut calldata = array![PUBKEY]; utils::deploy(Account::TEST_CLASS_HASH, calldata) } fn setup_camel_account() -> ContractAddress { - let mut calldata = ArrayTrait::new(); - calldata.append(PUBKEY); + let mut calldata = array![PUBKEY]; utils::deploy(CamelAccountMock::TEST_CLASS_HASH, calldata) } @@ -89,35 +102,49 @@ fn setup_camel_account() -> ContractAddress { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_constructor() { - ERC721::constructor(NAME, SYMBOL); + let mut state = STATE(); + ERC721::constructor(ref state, NAME, SYMBOL); - assert(ERC721::name() == NAME, 'Name should be NAME'); - assert(ERC721::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC721::balance_of(OWNER()) == 0, 'Balance should be zero'); + assert(ERC721MetadataImpl::name(@state) == NAME, 'Name should be NAME'); + assert(ERC721MetadataImpl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 0, 'Balance should be zero'); - assert(ERC721::supports_interface(erc721::interface::IERC721_ID), 'Missing interface ID'); assert( - ERC721::supports_interface(erc721::interface::IERC721_METADATA_ID), 'missing interface ID' + SRC5Impl::supports_interface(@state, erc721::interface::IERC721_ID), 'Missing interface ID' + ); + assert( + SRC5Impl::supports_interface(@state, erc721::interface::IERC721_METADATA_ID), + 'missing interface ID' + ); + assert( + SRC5Impl::supports_interface(@state, introspection::interface::ISRC5_ID), + 'missing interface ID' ); - assert(ERC721::supports_interface(src5::ISRC5_ID), 'missing interface ID'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_initialize() { - ERC721::initializer(NAME, SYMBOL); + let mut state = STATE(); + InternalImpl::initializer(ref state, NAME, SYMBOL); - assert(ERC721::name() == NAME, 'Name should be NAME'); - assert(ERC721::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC721::balance_of(OWNER()) == 0, 'Balance should be zero'); + assert(ERC721MetadataImpl::name(@state) == NAME, 'Name should be NAME'); + assert(ERC721MetadataImpl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 0, 'Balance should be zero'); - assert(ERC721::supports_interface(erc721::interface::IERC721_ID), 'Missing interface ID'); assert( - ERC721::supports_interface(erc721::interface::IERC721_METADATA_ID), 'missing interface ID' + SRC5Impl::supports_interface(@state, erc721::interface::IERC721_ID), 'Missing interface ID' + ); + assert( + SRC5Impl::supports_interface(@state, erc721::interface::IERC721_METADATA_ID), + 'missing interface ID' + ); + assert( + SRC5Impl::supports_interface(@state, introspection::interface::ISRC5_ID), + 'missing interface ID' ); - assert(ERC721::supports_interface(src5::ISRC5_ID), 'missing interface ID'); } // @@ -125,76 +152,78 @@ fn test_initialize() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_balance_of() { - setup(); - assert(ERC721::balance_of(OWNER()) == 1, 'Should return balance'); + let state = setup(); + assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Should return balance'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid account', ))] fn test_balance_of_zero() { - ERC721::balance_of(ZERO()); + ERC721Impl::balance_of(@STATE(), ZERO()); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_owner_of() { - setup(); - assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Should return owner'); + let state = setup(); + assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Should return owner'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_owner_of_non_minted() { - ERC721::owner_of(u256_from_felt252(7)); + ERC721Impl::owner_of(@STATE(), u256_from_felt252(7)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_token_uri_non_minted() { - ERC721::token_uri(u256_from_felt252(7)); + ERC721MetadataImpl::token_uri(@STATE(), u256_from_felt252(7)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_get_approved() { - setup(); + let mut state = setup(); let spender = SPENDER(); let token_id = TOKEN_ID; - assert(ERC721::get_approved(token_id) == ZERO(), 'Should return non-approval'); - ERC721::_approve(spender, token_id); - assert(ERC721::get_approved(token_id) == spender, 'Should return approval'); + assert(ERC721Impl::get_approved(@state, token_id) == ZERO(), 'Should return non-approval'); + InternalImpl::_approve(ref state, spender, token_id); + assert(ERC721Impl::get_approved(@state, token_id) == spender, 'Should return approval'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_get_approved_nonexistent() { - ERC721::get_approved(u256_from_felt252(7)); + ERC721Impl::get_approved(@STATE(), u256_from_felt252(7)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__exists() { + let mut state = STATE(); let zero = ZERO(); let token_id = TOKEN_ID; - assert(!ERC721::_exists(token_id), 'Token should not exist'); - assert(ERC721::_owners::read(token_id) == zero, 'Invalid owner'); - ERC721::_mint(RECIPIENT(), token_id); + assert(!InternalImpl::_exists(@state, token_id), 'Token should not exist'); + assert(state._owners.read(token_id) == zero, 'Invalid owner'); + + InternalImpl::_mint(ref state, RECIPIENT(), token_id); - assert(ERC721::_exists(token_id), 'Token should exist'); - assert(ERC721::_owners::read(token_id) == RECIPIENT(), 'Invalid owner'); + assert(InternalImpl::_exists(@state, token_id), 'Token should exist'); + assert(state._owners.read(token_id) == RECIPIENT(), 'Invalid owner'); - ERC721::_burn(token_id); + InternalImpl::_burn(ref state, token_id); - assert(!ERC721::_exists(token_id), 'Token should not exist'); - assert(ERC721::_owners::read(token_id) == zero, 'Invalid owner'); + assert(!InternalImpl::_exists(@state, token_id), 'Token should not exist'); + assert(state._owners.read(token_id) == zero, 'Invalid owner'); } // @@ -202,78 +231,84 @@ fn test__exists() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_approve_from_owner() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC721::approve(SPENDER(), TOKEN_ID); - assert(ERC721::get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); + ERC721Impl::approve(ref state, SPENDER(), TOKEN_ID); + assert( + ERC721Impl::get_approved(@state, TOKEN_ID) == SPENDER(), 'Spender not approved correctly' + ); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_approve_from_operator() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC721::set_approval_for_all(OPERATOR(), true); + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); set_caller_address(OPERATOR()); - ERC721::approve(SPENDER(), TOKEN_ID); - assert(ERC721::get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); + ERC721Impl::approve(ref state, SPENDER(), TOKEN_ID); + assert( + ERC721Impl::get_approved(@state, TOKEN_ID) == SPENDER(), 'Spender not approved correctly' + ); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_approve_from_unauthorized() { - setup(); + let mut state = setup(); set_caller_address(OTHER()); - ERC721::approve(SPENDER(), TOKEN_ID); + ERC721Impl::approve(ref state, SPENDER(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: approval to owner', ))] fn test_approve_to_owner() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC721::approve(OWNER(), TOKEN_ID); + ERC721Impl::approve(ref state, OWNER(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_approve_nonexistent() { - ERC721::approve(SPENDER(), TOKEN_ID); + let mut state = STATE(); + ERC721Impl::approve(ref state, SPENDER(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__approve() { - setup(); - - ERC721::_approve(SPENDER(), TOKEN_ID); - assert(ERC721::get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); + let mut state = setup(); + InternalImpl::_approve(ref state, SPENDER(), TOKEN_ID); + assert( + ERC721Impl::get_approved(@state, TOKEN_ID) == SPENDER(), 'Spender not approved correctly' + ); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: approval to owner', ))] fn test__approve_to_owner() { - setup(); - - ERC721::_approve(OWNER(), TOKEN_ID); + let mut state = setup(); + InternalImpl::_approve(ref state, OWNER(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test__approve_nonexistent() { - ERC721::_approve(SPENDER(), TOKEN_ID); + let mut state = STATE(); + InternalImpl::_approve(ref state, SPENDER(), TOKEN_ID); } // @@ -281,58 +316,77 @@ fn test__approve_nonexistent() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_set_approval_for_all() { + let mut state = STATE(); set_caller_address(OWNER()); - assert(!ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Invalid default value'); - ERC721::set_approval_for_all(OPERATOR(), true); - assert(ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + assert(!ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), 'Invalid default value'); + + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + assert( + ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), + 'Operator not approved correctly' + ); - ERC721::set_approval_for_all(OPERATOR(), false); - assert(!ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Approval not revoked correctly'); + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), false); + assert( + !ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), + 'Approval not revoked correctly' + ); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval', ))] fn test_set_approval_for_all_owner_equal_operator_true() { + let mut state = STATE(); set_caller_address(OWNER()); - ERC721::set_approval_for_all(OWNER(), true); + ERC721Impl::set_approval_for_all(ref state, OWNER(), true); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval', ))] fn test_set_approval_for_all_owner_equal_operator_false() { + let mut state = STATE(); set_caller_address(OWNER()); - ERC721::set_approval_for_all(OWNER(), false); + ERC721Impl::set_approval_for_all(ref state, OWNER(), false); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__set_approval_for_all() { - assert(!ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Invalid default value'); + let mut state = STATE(); + assert(!ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), 'Invalid default value'); - ERC721::_set_approval_for_all(OWNER(), OPERATOR(), true); - assert(ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + InternalImpl::_set_approval_for_all(ref state, OWNER(), OPERATOR(), true); + assert( + ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), + 'Operator not approved correctly' + ); - ERC721::_set_approval_for_all(OWNER(), OPERATOR(), false); - assert(!ERC721::is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + InternalImpl::_set_approval_for_all(ref state, OWNER(), OPERATOR(), false); + assert( + !ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), + 'Operator not approved correctly' + ); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval', ))] fn test__set_approval_for_all_owner_equal_operator_true() { - ERC721::_set_approval_for_all(OWNER(), OWNER(), true); + let mut state = STATE(); + InternalImpl::_set_approval_for_all(ref state, OWNER(), OWNER(), true); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval', ))] fn test__set_approval_for_all_owner_equal_operator_false() { - ERC721::_set_approval_for_all(OWNER(), OWNER(), false); + let mut state = STATE(); + InternalImpl::_set_approval_for_all(ref state, OWNER(), OWNER(), false); } // @@ -340,147 +394,148 @@ fn test__set_approval_for_all_owner_equal_operator_false() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_transfer_from_owner() { - setup(); + let mut state = setup(); let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); // set approval to check reset - ERC721::_approve(OTHER(), token_id); + InternalImpl::_approve(ref state, OTHER(), token_id); assert_state_before_transfer(token_id, owner, recipient); - assert(ERC721::get_approved(token_id) == OTHER(), 'Approval not implicitly reset'); + assert(ERC721Impl::get_approved(@state, token_id) == OTHER(), 'Approval not implicitly reset'); set_caller_address(owner); - ERC721::transfer_from(owner, recipient, token_id); + ERC721Impl::transfer_from(ref state, owner, recipient, token_id); assert_state_after_transfer(token_id, owner, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_transferFrom_owner() { - setup(); + let mut state = setup(); let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); // set approval to check reset - ERC721::_approve(OTHER(), token_id); + InternalImpl::_approve(ref state, OTHER(), token_id); assert_state_before_transfer(token_id, owner, recipient); - assert(ERC721::get_approved(token_id) == OTHER(), 'Approval not implicitly reset'); + assert(ERC721Impl::get_approved(@state, token_id) == OTHER(), 'Approval not implicitly reset'); set_caller_address(owner); - ERC721::transferFrom(owner, recipient, token_id); + ERC721CamelOnlyImpl::transferFrom(ref state, owner, recipient, token_id); assert_state_after_transfer(token_id, owner, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_transfer_from_nonexistent() { - ERC721::transfer_from(ZERO(), RECIPIENT(), TOKEN_ID); + let mut state = STATE(); + ERC721Impl::transfer_from(ref state, ZERO(), RECIPIENT(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_transferFrom_nonexistent() { - ERC721::transferFrom(ZERO(), RECIPIENT(), TOKEN_ID); + let mut state = STATE(); + ERC721CamelOnlyImpl::transferFrom(ref state, ZERO(), RECIPIENT(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test_transfer_from_to_zero() { - setup(); - + let mut state = setup(); set_caller_address(OWNER()); - ERC721::transfer_from(OWNER(), ZERO(), TOKEN_ID); + ERC721Impl::transfer_from(ref state, OWNER(), ZERO(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test_transferFrom_to_zero() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC721::transferFrom(OWNER(), ZERO(), TOKEN_ID); + ERC721CamelOnlyImpl::transferFrom(ref state, OWNER(), ZERO(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_transfer_from_to_owner() { - setup(); + let mut state = setup(); - assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); - assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner before'); + assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership before'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner before'); set_caller_address(OWNER()); - ERC721::transfer_from(OWNER(), OWNER(), TOKEN_ID); + ERC721Impl::transfer_from(ref state, OWNER(), OWNER(), TOKEN_ID); - assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership after'); - assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner after'); + assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership after'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner after'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_transferFrom_to_owner() { - setup(); + let mut state = setup(); - assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); - assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner before'); + assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership before'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner before'); set_caller_address(OWNER()); - ERC721::transferFrom(OWNER(), OWNER(), TOKEN_ID); + ERC721CamelOnlyImpl::transferFrom(ref state, OWNER(), OWNER(), TOKEN_ID); - assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership after'); - assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner after'); + assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership after'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner after'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_transfer_from_approved() { - setup(); + let mut state = setup(); let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); assert_state_before_transfer(token_id, owner, recipient); set_caller_address(owner); - ERC721::approve(OPERATOR(), token_id); + ERC721Impl::approve(ref state, OPERATOR(), token_id); set_caller_address(OPERATOR()); - ERC721::transfer_from(owner, recipient, token_id); + ERC721Impl::transfer_from(ref state, owner, recipient, token_id); assert_state_after_transfer(token_id, owner, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_transferFrom_approved() { - setup(); + let mut state = setup(); let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); assert_state_before_transfer(token_id, owner, recipient); set_caller_address(owner); - ERC721::approve(OPERATOR(), token_id); + ERC721Impl::approve(ref state, OPERATOR(), token_id); set_caller_address(OPERATOR()); - ERC721::transferFrom(owner, recipient, token_id); + ERC721CamelOnlyImpl::transferFrom(ref state, owner, recipient, token_id); assert_state_after_transfer(token_id, owner, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_transfer_from_approved_for_all() { - setup(); + let mut state = setup(); let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); @@ -488,18 +543,18 @@ fn test_transfer_from_approved_for_all() { assert_state_before_transfer(token_id, owner, recipient); set_caller_address(owner); - ERC721::set_approval_for_all(OPERATOR(), true); + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); set_caller_address(OPERATOR()); - ERC721::transfer_from(owner, recipient, token_id); + ERC721Impl::transfer_from(ref state, owner, recipient, token_id); assert_state_after_transfer(token_id, owner, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_transferFrom_approved_for_all() { - setup(); + let mut state = setup(); let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); @@ -507,32 +562,30 @@ fn test_transferFrom_approved_for_all() { assert_state_before_transfer(token_id, owner, recipient); set_caller_address(owner); - ERC721::set_approval_for_all(OPERATOR(), true); + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); set_caller_address(OPERATOR()); - ERC721::transferFrom(owner, recipient, token_id); + ERC721CamelOnlyImpl::transferFrom(ref state, owner, recipient, token_id); assert_state_after_transfer(token_id, owner, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_transfer_from_unauthorized() { - setup(); - + let mut state = setup(); set_caller_address(OTHER()); - ERC721::transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); + ERC721Impl::transfer_from(ref state, OWNER(), RECIPIENT(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_transferFrom_unauthorized() { - setup(); - + let mut state = setup(); set_caller_address(OTHER()); - ERC721::transferFrom(OWNER(), RECIPIENT(), TOKEN_ID); + ERC721CamelOnlyImpl::transferFrom(ref state, OWNER(), RECIPIENT(), TOKEN_ID); } // @@ -540,9 +593,9 @@ fn test_transferFrom_unauthorized() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_to_account() { - setup(); + let mut state = setup(); let account = setup_account(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -550,15 +603,15 @@ fn test_safe_transfer_from_to_account() { assert_state_before_transfer(token_id, owner, account); set_caller_address(owner); - ERC721::safe_transfer_from(owner, account, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, account, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, account); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_to_account() { - setup(); + let mut state = setup(); let account = setup_account(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -566,15 +619,15 @@ fn test_safeTransferFrom_to_account() { assert_state_before_transfer(token_id, owner, account); set_caller_address(owner); - ERC721::safeTransferFrom(owner, account, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, account, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, account); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_to_account_camel() { - setup(); + let mut state = setup(); let account = setup_camel_account(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -582,15 +635,15 @@ fn test_safe_transfer_from_to_account_camel() { assert_state_before_transfer(token_id, owner, account); set_caller_address(owner); - ERC721::safe_transfer_from(owner, account, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, account, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, account); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_to_account_camel() { - setup(); + let mut state = setup(); let account = setup_camel_account(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -598,15 +651,15 @@ fn test_safeTransferFrom_to_account_camel() { assert_state_before_transfer(token_id, owner, account); set_caller_address(owner); - ERC721::safeTransferFrom(owner, account, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, account, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, account); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_to_receiver() { - setup(); + let mut state = setup(); let receiver = setup_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -614,15 +667,15 @@ fn test_safe_transfer_from_to_receiver() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_to_receiver() { - setup(); + let mut state = setup(); let receiver = setup_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -630,15 +683,15 @@ fn test_safeTransferFrom_to_receiver() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_to_receiver_camel() { - setup(); + let mut state = setup(); let receiver = setup_camel_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -646,15 +699,15 @@ fn test_safe_transfer_from_to_receiver_camel() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_to_receiver_camel() { - setup(); + let mut state = setup(); let receiver = setup_camel_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -662,199 +715,203 @@ fn test_safeTransferFrom_to_receiver_camel() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed', ))] fn test_safe_transfer_from_to_receiver_failure() { - setup(); + let mut state = setup(); let receiver = setup_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); set_caller_address(owner); - ERC721::safe_transfer_from(owner, receiver, token_id, DATA(false)); + ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(false)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed', ))] fn test_safeTransferFrom_to_receiver_failure() { - setup(); + let mut state = setup(); let receiver = setup_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); set_caller_address(owner); - ERC721::safeTransferFrom(owner, receiver, token_id, DATA(false)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(false)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed', ))] fn test_safe_transfer_from_to_receiver_failure_camel() { - setup(); + let mut state = setup(); let receiver = setup_camel_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); set_caller_address(owner); - ERC721::safe_transfer_from(owner, receiver, token_id, DATA(false)); + ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(false)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed', ))] fn test_safeTransferFrom_to_receiver_failure_camel() { - setup(); + let mut state = setup(); let receiver = setup_camel_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); set_caller_address(owner); - ERC721::safeTransferFrom(owner, receiver, token_id, DATA(false)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(false)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_safe_transfer_from_to_non_receiver() { - setup(); - let recipient = utils::deploy(ERC721NonReceiver::TEST_CLASS_HASH, ArrayTrait::new()); + let mut state = setup(); + let recipient = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, array![]); let token_id = TOKEN_ID; let owner = OWNER(); set_caller_address(owner); - ERC721::safe_transfer_from(owner, recipient, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, recipient, token_id, DATA(true)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test_safeTransferFrom_to_non_receiver() { - setup(); - let recipient = utils::deploy(ERC721NonReceiver::TEST_CLASS_HASH, ArrayTrait::new()); + let mut state = setup(); + let recipient = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, array![]); let token_id = TOKEN_ID; let owner = OWNER(); set_caller_address(owner); - ERC721::safeTransferFrom(owner, recipient, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, recipient, token_id, DATA(true)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_safe_transfer_from_nonexistent() { - ERC721::safe_transfer_from(ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); + let mut state = STATE(); + ERC721Impl::safe_transfer_from(ref state, ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test_safeTransferFrom_nonexistent() { - ERC721::safeTransferFrom(ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); + let mut state = STATE(); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test_safe_transfer_from_to_zero() { - setup(); - + let mut state = setup(); set_caller_address(OWNER()); - ERC721::safe_transfer_from(OWNER(), ZERO(), TOKEN_ID, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, OWNER(), ZERO(), TOKEN_ID, DATA(true)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test_safeTransferFrom_to_zero() { - setup(); - + let mut state = setup(); set_caller_address(OWNER()); - ERC721::safeTransferFrom(OWNER(), ZERO(), TOKEN_ID, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, OWNER(), ZERO(), TOKEN_ID, DATA(true)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_to_owner() { + let mut state = STATE(); let token_id = TOKEN_ID; let owner = setup_receiver(); - ERC721::initializer(NAME, SYMBOL); - ERC721::_mint(owner, token_id); + InternalImpl::initializer(ref state, NAME, SYMBOL); + InternalImpl::_mint(ref state, owner, token_id); - assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); set_caller_address(owner); - ERC721::safe_transfer_from(owner, owner, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, owner, token_id, DATA(true)); - assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership after'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner after'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_to_owner() { + let mut state = STATE(); let token_id = TOKEN_ID; let owner = setup_receiver(); - ERC721::initializer(NAME, SYMBOL); - ERC721::_mint(owner, token_id); + InternalImpl::initializer(ref state, NAME, SYMBOL); + InternalImpl::_mint(ref state, owner, token_id); - assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); set_caller_address(owner); - ERC721::safeTransferFrom(owner, owner, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, owner, token_id, DATA(true)); - assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership after'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner after'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_to_owner_camel() { + let mut state = STATE(); let token_id = TOKEN_ID; let owner = setup_camel_receiver(); - ERC721::initializer(NAME, SYMBOL); - ERC721::_mint(owner, token_id); + InternalImpl::initializer(ref state, NAME, SYMBOL); + InternalImpl::_mint(ref state, owner, token_id); - assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); set_caller_address(owner); - ERC721::safe_transfer_from(owner, owner, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, owner, token_id, DATA(true)); - assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership after'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner after'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_to_owner_camel() { + let mut state = STATE(); let token_id = TOKEN_ID; let owner = setup_camel_receiver(); - ERC721::initializer(NAME, SYMBOL); - ERC721::_mint(owner, token_id); + InternalImpl::initializer(ref state, NAME, SYMBOL); + InternalImpl::_mint(ref state, owner, token_id); - assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); set_caller_address(owner); - ERC721::safeTransferFrom(owner, owner, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, owner, token_id, DATA(true)); - assert(ERC721::owner_of(token_id) == owner, 'Ownership after'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner after'); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership after'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner after'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_approved() { - setup(); + let mut state = setup(); let receiver = setup_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -862,18 +919,18 @@ fn test_safe_transfer_from_approved() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::approve(OPERATOR(), token_id); + ERC721Impl::approve(ref state, OPERATOR(), token_id); set_caller_address(OPERATOR()); - ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_approved() { - setup(); + let mut state = setup(); let receiver = setup_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -881,18 +938,18 @@ fn test_safeTransferFrom_approved() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::approve(OPERATOR(), token_id); + ERC721Impl::approve(ref state, OPERATOR(), token_id); set_caller_address(OPERATOR()); - ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_approved_camel() { - setup(); + let mut state = setup(); let receiver = setup_camel_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -900,18 +957,18 @@ fn test_safe_transfer_from_approved_camel() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::approve(OPERATOR(), token_id); + ERC721Impl::approve(ref state, OPERATOR(), token_id); set_caller_address(OPERATOR()); - ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_approved_camel() { - setup(); + let mut state = setup(); let receiver = setup_camel_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -919,18 +976,18 @@ fn test_safeTransferFrom_approved_camel() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::approve(OPERATOR(), token_id); + ERC721Impl::approve(ref state, OPERATOR(), token_id); set_caller_address(OPERATOR()); - ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_approved_for_all() { - setup(); + let mut state = setup(); let receiver = setup_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -938,18 +995,18 @@ fn test_safe_transfer_from_approved_for_all() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::set_approval_for_all(OPERATOR(), true); + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); set_caller_address(OPERATOR()); - ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_approved_for_all() { - setup(); + let mut state = setup(); let receiver = setup_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -957,18 +1014,18 @@ fn test_safeTransferFrom_approved_for_all() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::set_approval_for_all(OPERATOR(), true); + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); set_caller_address(OPERATOR()); - ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safe_transfer_from_approved_for_all_camel() { - setup(); + let mut state = setup(); let receiver = setup_camel_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -976,18 +1033,18 @@ fn test_safe_transfer_from_approved_for_all_camel() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::set_approval_for_all(OPERATOR(), true); + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); set_caller_address(OPERATOR()); - ERC721::safe_transfer_from(owner, receiver, token_id, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test_safeTransferFrom_approved_for_all_camel() { - setup(); + let mut state = setup(); let receiver = setup_camel_receiver(); let token_id = TOKEN_ID; let owner = OWNER(); @@ -995,30 +1052,30 @@ fn test_safeTransferFrom_approved_for_all_camel() { assert_state_before_transfer(token_id, owner, receiver); set_caller_address(owner); - ERC721::set_approval_for_all(OPERATOR(), true); + ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); set_caller_address(OPERATOR()); - ERC721::safeTransferFrom(owner, receiver, token_id, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); assert_state_after_transfer(token_id, owner, receiver); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_safe_transfer_from_unauthorized() { - setup(); + let mut state = setup(); set_caller_address(OTHER()); - ERC721::safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); + ERC721Impl::safe_transfer_from(ref state, OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_safeTransferFrom_unauthorized() { - setup(); + let mut state = setup(); set_caller_address(OTHER()); - ERC721::safeTransferFrom(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); + ERC721CamelOnlyImpl::safeTransferFrom(ref state, OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } // @@ -1026,41 +1083,40 @@ fn test_safeTransferFrom_unauthorized() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__transfer() { - setup(); + let mut state = setup(); let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); assert_state_before_transfer(token_id, owner, recipient); - ERC721::_transfer(owner, recipient, token_id); + InternalImpl::_transfer(ref state, owner, recipient, token_id); assert_state_after_transfer(token_id, owner, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test__transfer_nonexistent() { - ERC721::_transfer(ZERO(), RECIPIENT(), TOKEN_ID); + let mut state = STATE(); + InternalImpl::_transfer(ref state, ZERO(), RECIPIENT(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test__transfer_to_zero() { - setup(); - - ERC721::_transfer(OWNER(), ZERO(), TOKEN_ID); + let mut state = setup(); + InternalImpl::_transfer(ref state, OWNER(), ZERO(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: wrong sender', ))] fn test__transfer_from_invalid_owner() { - setup(); - - ERC721::_transfer(RECIPIENT(), OWNER(), TOKEN_ID); + let mut state = setup(); + InternalImpl::_transfer(ref state, RECIPIENT(), OWNER(), TOKEN_ID); } // @@ -1068,29 +1124,31 @@ fn test__transfer_from_invalid_owner() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__mint() { + let mut state = STATE(); let recipient = RECIPIENT(); let token_id = TOKEN_ID; + assert_state_before_mint(recipient); - ERC721::_mint(RECIPIENT(), TOKEN_ID); + InternalImpl::_mint(ref state, RECIPIENT(), TOKEN_ID); assert_state_after_mint(token_id, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test__mint_to_zero() { - ERC721::_mint(ZERO(), TOKEN_ID); + let mut state = STATE(); + InternalImpl::_mint(ref state, ZERO(), TOKEN_ID); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: token already minted', ))] fn test__mint_already_exist() { - setup(); - - ERC721::_mint(RECIPIENT(), TOKEN_ID); + let mut state = setup(); + InternalImpl::_mint(ref state, RECIPIENT(), TOKEN_ID); } // @@ -1098,98 +1156,106 @@ fn test__mint_already_exist() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__safe_mint_to_receiver() { + let mut state = STATE(); let recipient = setup_receiver(); let token_id = TOKEN_ID; assert_state_before_mint(recipient); - ERC721::_safe_mint(recipient, token_id, DATA(true)); + InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(true)); assert_state_after_mint(token_id, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__safe_mint_to_receiver_camel() { + let mut state = STATE(); let recipient = setup_camel_receiver(); let token_id = TOKEN_ID; assert_state_before_mint(recipient); - ERC721::_safe_mint(recipient, token_id, DATA(true)); + InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(true)); assert_state_after_mint(token_id, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__safe_mint_to_account() { + let mut state = STATE(); let account = setup_account(); let token_id = TOKEN_ID; assert_state_before_mint(account); - ERC721::_safe_mint(account, token_id, DATA(true)); + InternalImpl::_safe_mint(ref state, account, token_id, DATA(true)); assert_state_after_mint(token_id, account); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__safe_mint_to_account_camel() { + let mut state = STATE(); let account = setup_camel_account(); let token_id = TOKEN_ID; assert_state_before_mint(account); - ERC721::_safe_mint(account, token_id, DATA(true)); + InternalImpl::_safe_mint(ref state, account, token_id, DATA(true)); assert_state_after_mint(token_id, account); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] fn test__safe_mint_to_non_receiver() { - let recipient = utils::deploy(ERC721NonReceiver::TEST_CLASS_HASH, ArrayTrait::new()); + let mut state = STATE(); + let recipient = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, array![]); let token_id = TOKEN_ID; assert_state_before_mint(recipient); - ERC721::_safe_mint(recipient, token_id, DATA(true)); + InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(true)); assert_state_after_mint(token_id, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe mint failed', ))] fn test__safe_mint_to_receiver_failure() { + let mut state = STATE(); let recipient = setup_receiver(); let token_id = TOKEN_ID; assert_state_before_mint(recipient); - ERC721::_safe_mint(recipient, token_id, DATA(false)); + InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(false)); assert_state_after_mint(token_id, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe mint failed', ))] fn test__safe_mint_to_receiver_failure_camel() { + let mut state = STATE(); let recipient = setup_camel_receiver(); let token_id = TOKEN_ID; assert_state_before_mint(recipient); - ERC721::_safe_mint(recipient, token_id, DATA(false)); + InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(false)); assert_state_after_mint(token_id, recipient); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test__safe_mint_to_zero() { - ERC721::_safe_mint(ZERO(), TOKEN_ID, DATA(true)); + let mut state = STATE(); + InternalImpl::_safe_mint(ref state, ZERO(), TOKEN_ID, DATA(true)); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: token already minted', ))] fn test__safe_mint_already_exist() { - setup(); - ERC721::_safe_mint(RECIPIENT(), TOKEN_ID, DATA(true)); + let mut state = setup(); + InternalImpl::_safe_mint(ref state, RECIPIENT(), TOKEN_ID, DATA(true)); } // @@ -1197,28 +1263,29 @@ fn test__safe_mint_already_exist() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__burn() { - setup(); + let mut state = setup(); - ERC721::_approve(OTHER(), TOKEN_ID); + InternalImpl::_approve(ref state, OTHER(), TOKEN_ID); - assert(ERC721::owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); - assert(ERC721::balance_of(OWNER()) == 1, 'Balance of owner before'); - assert(ERC721::get_approved(TOKEN_ID) == OTHER(), 'Approval before'); + assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership before'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner before'); + assert(ERC721Impl::get_approved(@state, TOKEN_ID) == OTHER(), 'Approval before'); - ERC721::_burn(TOKEN_ID); + InternalImpl::_burn(ref state, TOKEN_ID); - assert(ERC721::_owners::read(TOKEN_ID) == ZERO(), 'Ownership after'); - assert(ERC721::balance_of(OWNER()) == 0, 'Balance of owner after'); - assert(ERC721::_token_approvals::read(TOKEN_ID) == ZERO(), 'Approval after'); + assert(state._owners.read(TOKEN_ID) == ZERO(), 'Ownership after'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 0, 'Balance of owner after'); + assert(state._token_approvals.read(TOKEN_ID) == ZERO(), 'Approval after'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test__burn_nonexistent() { - ERC721::_burn(TOKEN_ID); + let mut state = STATE(); + InternalImpl::_burn(ref state, TOKEN_ID); } // @@ -1226,20 +1293,21 @@ fn test__burn_nonexistent() { // #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] fn test__set_token_uri() { - setup(); + let mut state = setup(); - assert(ERC721::token_uri(TOKEN_ID) == 0, 'URI should be 0'); - ERC721::_set_token_uri(TOKEN_ID, URI); - assert(ERC721::token_uri(TOKEN_ID) == URI, 'URI should be set'); + assert(ERC721MetadataImpl::token_uri(@state, TOKEN_ID) == 0, 'URI should be 0'); + InternalImpl::_set_token_uri(ref state, TOKEN_ID, URI); + assert(ERC721MetadataImpl::token_uri(@state, TOKEN_ID) == URI, 'URI should be set'); } #[test] -#[available_gas(2000000)] +#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', ))] fn test__set_token_uri_nonexistent() { - ERC721::_set_token_uri(TOKEN_ID, URI); + let mut state = STATE(); + InternalImpl::_set_token_uri(ref state, TOKEN_ID, URI); } // @@ -1249,24 +1317,28 @@ fn test__set_token_uri_nonexistent() { fn assert_state_before_transfer( token_id: u256, owner: ContractAddress, recipient: ContractAddress ) { - assert(ERC721::owner_of(token_id) == owner, 'Ownership before'); - assert(ERC721::balance_of(owner) == 1, 'Balance of owner before'); - assert(ERC721::balance_of(recipient) == 0, 'Balance of recipient before'); + let state = STATE(); + assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); + assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); + assert(ERC721Impl::balance_of(@state, recipient) == 0, 'Balance of recipient before'); } fn assert_state_after_transfer(token_id: u256, owner: ContractAddress, recipient: ContractAddress) { - assert(ERC721::owner_of(token_id) == recipient, 'Ownership after'); - assert(ERC721::balance_of(owner) == 0, 'Balance of owner after'); - assert(ERC721::balance_of(recipient) == 1, 'Balance of recipient after'); - assert(ERC721::get_approved(token_id) == ZERO(), 'Approval not implicitly reset'); + let state = STATE(); + assert(ERC721Impl::owner_of(@state, token_id) == recipient, 'Ownership after'); + assert(ERC721Impl::balance_of(@state, owner) == 0, 'Balance of owner after'); + assert(ERC721Impl::balance_of(@state, recipient) == 1, 'Balance of recipient after'); + assert(ERC721Impl::get_approved(@state, token_id) == ZERO(), 'Approval not implicitly reset'); } fn assert_state_before_mint(recipient: ContractAddress) { - assert(ERC721::balance_of(recipient) == 0, 'Balance of recipient before'); + let state = STATE(); + assert(ERC721Impl::balance_of(@state, recipient) == 0, 'Balance of recipient before'); } fn assert_state_after_mint(token_id: u256, recipient: ContractAddress) { - assert(ERC721::owner_of(token_id) == recipient, 'Ownership after'); - assert(ERC721::balance_of(recipient) == 1, 'Balance of recipient after'); - assert(ERC721::get_approved(token_id) == ZERO(), 'Approval implicitly set'); + let state = STATE(); + assert(ERC721Impl::owner_of(@state, token_id) == recipient, 'Ownership after'); + assert(ERC721Impl::balance_of(@state, recipient) == 1, 'Balance of recipient after'); + assert(ERC721Impl::get_approved(@state, token_id) == ZERO(), 'Approval implicitly set'); } diff --git a/src/openzeppelin/token.cairo b/src/openzeppelin/token.cairo index f9a848d01..51f2f6d68 100644 --- a/src/openzeppelin/token.cairo +++ b/src/openzeppelin/token.cairo @@ -1,2 +1,2 @@ -mod erc20; +// mod erc20; mod erc721; diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo index 1a728ef23..bd33b3953 100644 --- a/src/openzeppelin/token/erc20.cairo +++ b/src/openzeppelin/token/erc20.cairo @@ -1,5 +1,7 @@ mod erc20; -use erc20::{ERC20, ERC20ABIDispatcher, ERC20ABIDispatcherTrait}; - mod interface; mod dual20; + +use erc20::ERC20; +use erc20::ERC20ABIDispatcher; +use erc20::ERC20ABIDispatcherTrait; diff --git a/src/openzeppelin/token/erc721.cairo b/src/openzeppelin/token/erc721.cairo index 0fab567a8..591703ecc 100644 --- a/src/openzeppelin/token/erc721.cairo +++ b/src/openzeppelin/token/erc721.cairo @@ -1,5 +1,6 @@ -mod erc721; -use erc721::ERC721; -mod interface; mod dual721; mod dual721_receiver; +mod erc721; +mod interface; + +use erc721::ERC721; diff --git a/src/openzeppelin/token/erc721/dual721.cairo b/src/openzeppelin/token/erc721/dual721.cairo index bdd49fd03..55655d9c7 100644 --- a/src/openzeppelin/token/erc721/dual721.cairo +++ b/src/openzeppelin/token/erc721/dual721.cairo @@ -39,21 +39,17 @@ trait DualCaseERC721Trait { impl DualCaseERC721Impl of DualCaseERC721Trait { fn name(self: @DualCaseERC721) -> felt252 { - let args = ArrayTrait::new(); - - call_contract_syscall(*self.contract_address, selectors::name, args.span()) + call_contract_syscall(*self.contract_address, selectors::name, array![].span()) .unwrap_and_cast() } fn symbol(self: @DualCaseERC721) -> felt252 { - let args = ArrayTrait::new(); - - call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) + call_contract_syscall(*self.contract_address, selectors::symbol, array![].span()) .unwrap_and_cast() } fn token_uri(self: @DualCaseERC721, token_id: u256) -> felt252 { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(token_id); try_selector_with_fallback( @@ -63,7 +59,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { } fn balance_of(self: @DualCaseERC721, account: ContractAddress) -> u256 { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(account); try_selector_with_fallback( @@ -73,7 +69,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { } fn owner_of(self: @DualCaseERC721, token_id: u256) -> ContractAddress { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(token_id); try_selector_with_fallback( @@ -83,7 +79,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { } fn get_approved(self: @DualCaseERC721, token_id: u256) -> ContractAddress { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(token_id); try_selector_with_fallback( @@ -95,7 +91,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { fn is_approved_for_all( self: @DualCaseERC721, owner: ContractAddress, operator: ContractAddress ) -> bool { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(owner); args.append_serde(operator); @@ -109,7 +105,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { } fn approve(self: @DualCaseERC721, to: ContractAddress, token_id: u256) { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(to); args.append_serde(token_id); call_contract_syscall(*self.contract_address, selectors::approve, args.span()) @@ -117,7 +113,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { } fn set_approval_for_all(self: @DualCaseERC721, operator: ContractAddress, approved: bool) { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(operator); args.append_serde(approved); @@ -133,7 +129,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { fn transfer_from( self: @DualCaseERC721, from: ContractAddress, to: ContractAddress, token_id: u256 ) { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(from); args.append_serde(to); args.append_serde(token_id); @@ -151,7 +147,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { token_id: u256, mut data: Span ) { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(from); args.append_serde(to); args.append_serde(token_id); @@ -167,7 +163,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { } fn supports_interface(self: @DualCaseERC721, interface_id: felt252) -> bool { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(interface_id); try_selector_with_fallback( diff --git a/src/openzeppelin/token/erc721/dual721_receiver.cairo b/src/openzeppelin/token/erc721/dual721_receiver.cairo index 3dc682b87..6c13fc931 100644 --- a/src/openzeppelin/token/erc721/dual721_receiver.cairo +++ b/src/openzeppelin/token/erc721/dual721_receiver.cairo @@ -29,7 +29,7 @@ impl DualCaseERC721ReceiverImpl of DualCaseERC721ReceiverTrait { token_id: u256, data: Span ) -> felt252 { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(operator); args.append_serde(from); args.append_serde(token_id); diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/openzeppelin/token/erc721/erc721.cairo index 339c63ebd..4e2a1bb80 100644 --- a/src/openzeppelin/token/erc721/erc721.cairo +++ b/src/openzeppelin/token/erc721/erc721.cairo @@ -1,75 +1,24 @@ use starknet::ContractAddress; -#[abi] -trait ERC721ABI { - // case agnostic - #[view] - fn name() -> felt252; - #[view] - fn symbol() -> felt252; - #[external] - fn approve(to: ContractAddress, token_id: u256); - // snake_case - #[view] - fn supports_interface(interface_id: felt252) -> bool; - #[view] - fn balance_of(account: ContractAddress) -> u256; - #[view] - fn owner_of(token_id: u256) -> ContractAddress; - #[external] - fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256); - #[external] - fn safe_transfer_from( - from: ContractAddress, to: ContractAddress, token_id: u256, data: Span - ); - #[external] - fn set_approval_for_all(operator: ContractAddress, approved: bool); - #[view] - fn get_approved(token_id: u256) -> ContractAddress; - #[view] - fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool; - #[view] - fn token_uri(token_id: u256) -> felt252; - // camelCase - #[view] - fn supportsInterface(interfaceId: felt252) -> bool; - #[view] - fn balanceOf(account: ContractAddress) -> u256; - #[view] - fn ownerOf(tokenId: u256) -> ContractAddress; - #[external] - fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256); - #[external] - fn safeTransferFrom( - from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span - ); - #[external] - fn setApprovalForAll(operator: ContractAddress, approved: bool); - #[view] - fn getApproved(tokenId: u256) -> ContractAddress; - #[view] - fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool; - #[view] - fn tokenUri(tokenId: u256) -> felt252; -} - -#[contract] +#[starknet::contract] mod ERC721 { + use array::SpanTrait; + use option::OptionTrait; + use starknet::ContractAddress; + use starknet::get_caller_address; + use zeroable::Zeroable; + use openzeppelin::account; use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; + use openzeppelin::introspection::interface::ISRC5; + use openzeppelin::introspection::interface::ISRC5Camel; use openzeppelin::introspection::src5; - use openzeppelin::token::erc721; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; - use openzeppelin::utils::serde::SpanSerde; - - use array::SpanTrait; - use option::OptionTrait; - use starknet::ContractAddress; - use starknet::get_caller_address; - use zeroable::Zeroable; + use openzeppelin::token::erc721::interface; + #[storage] struct Storage { _name: felt252, _symbol: felt252, @@ -81,385 +30,324 @@ mod ERC721 { } #[event] - fn Transfer(from: ContractAddress, to: ContractAddress, token_id: u256) {} + #[derive(Drop, starknet::Event)] + enum Event { + Transfer: Transfer, + Approval: Approval, + ApprovalForAll: ApprovalForAll + } - #[event] - fn Approval(owner: ContractAddress, approved: ContractAddress, token_id: u256) {} + #[derive(Drop, starknet::Event)] + struct Transfer { + from: ContractAddress, + to: ContractAddress, + token_id: u256 + } - #[event] - fn ApprovalForAll(owner: ContractAddress, operator: ContractAddress, approved: bool) {} + #[derive(Drop, starknet::Event)] + struct Approval { + owner: ContractAddress, + approved: ContractAddress, + token_id: u256 + } + + #[derive(Drop, starknet::Event)] + struct ApprovalForAll { + owner: ContractAddress, + operator: ContractAddress, + approved: bool + } #[constructor] - fn constructor(name: felt252, symbol: felt252) { - initializer(name, symbol); + fn constructor(ref self: ContractState, name: felt252, symbol: felt252) { + self.initializer(name, symbol); } - impl ISRC5Impl of src5::ISRC5 { - fn supports_interface(interface_id: felt252) -> bool { - src5::SRC5::supports_interface(interface_id) + // + // External + // + + #[external(v0)] + impl SRC5Impl of ISRC5 { + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = src5::SRC5::unsafe_new_contract_state(); + src5::SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) } } - impl ISRC5CamelImpl of src5::ISRC5Camel { - fn supportsInterface(interfaceId: felt252) -> bool { - src5::SRC5::supportsInterface(interfaceId) + #[external(v0)] + impl SRC5CamelImpl of ISRC5Camel { + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = src5::SRC5::unsafe_new_contract_state(); + src5::SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) } } - impl ERC721Impl of erc721::interface::IERC721 { - fn name() -> felt252 { - _name::read() + #[external(v0)] + impl ERC721MetadataImpl of interface::IERC721Metadata { + fn name(self: @ContractState) -> felt252 { + self._name.read() + } + + fn symbol(self: @ContractState) -> felt252 { + self._symbol.read() } - fn symbol() -> felt252 { - _symbol::read() + fn token_uri(self: @ContractState, token_id: u256) -> felt252 { + assert(self._exists(token_id), 'ERC721: invalid token ID'); + self._token_uri.read(token_id) } + } - fn token_uri(token_id: u256) -> felt252 { - assert(_exists(token_id), 'ERC721: invalid token ID'); - _token_uri::read(token_id) + #[external(v0)] + impl ERC721MetadataCamelOnlyImpl of interface::IERC721MetadataCamelOnly { + fn tokenUri(self: @ContractState, tokenId: u256) -> felt252 { + assert(self._exists(tokenId), 'ERC721: invalid token ID'); + self._token_uri.read(tokenId) } + } - fn balance_of(account: ContractAddress) -> u256 { + #[external(v0)] + impl ERC721Impl of interface::IERC721 { + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { assert(!account.is_zero(), 'ERC721: invalid account'); - _balances::read(account) + self._balances.read(account) } - fn owner_of(token_id: u256) -> ContractAddress { - _owner_of(token_id) + fn owner_of(self: @ContractState, token_id: u256) -> ContractAddress { + self._owner_of(token_id) } - fn get_approved(token_id: u256) -> ContractAddress { - assert(_exists(token_id), 'ERC721: invalid token ID'); - _token_approvals::read(token_id) + fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress { + assert(self._exists(token_id), 'ERC721: invalid token ID'); + self._token_approvals.read(token_id) } - fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool { - _operator_approvals::read((owner, operator)) + fn is_approved_for_all( + self: @ContractState, owner: ContractAddress, operator: ContractAddress + ) -> bool { + self._operator_approvals.read((owner, operator)) } - fn approve(to: ContractAddress, token_id: u256) { - let owner = _owner_of(token_id); + fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) { + let owner = self._owner_of(token_id); let caller = get_caller_address(); assert( - owner == caller | is_approved_for_all(owner, caller), 'ERC721: unauthorized caller' + owner == caller || ERC721Impl::is_approved_for_all(@self, owner, caller), + 'ERC721: unauthorized caller' ); - _approve(to, token_id); + self._approve(to, token_id); } - fn set_approval_for_all(operator: ContractAddress, approved: bool) { - _set_approval_for_all(get_caller_address(), operator, approved) + fn set_approval_for_all( + ref self: ContractState, operator: ContractAddress, approved: bool + ) { + self._set_approval_for_all(get_caller_address(), operator, approved) } - fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) { + fn transfer_from( + ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ) { assert( - _is_approved_or_owner(get_caller_address(), token_id), 'ERC721: unauthorized caller' + self._is_approved_or_owner(get_caller_address(), token_id), + 'ERC721: unauthorized caller' ); - _transfer(from, to, token_id); + self._transfer(from, to, token_id); } fn safe_transfer_from( - from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ref self: ContractState, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span ) { assert( - _is_approved_or_owner(get_caller_address(), token_id), 'ERC721: unauthorized caller' + self._is_approved_or_owner(get_caller_address(), token_id), + 'ERC721: unauthorized caller' ); - _safe_transfer(from, to, token_id, data); + self._safe_transfer(from, to, token_id, data); } } - impl ERC721CamelImpl of erc721::interface::IERC721Camel { - fn name() -> felt252 { - ERC721Impl::name() - } - - fn symbol() -> felt252 { - ERC721Impl::symbol() - } - - fn tokenUri(tokenId: u256) -> felt252 { - ERC721Impl::token_uri(tokenId) - } - - fn balanceOf(account: ContractAddress) -> u256 { - ERC721Impl::balance_of(account) - } - - fn ownerOf(tokenId: u256) -> ContractAddress { - ERC721Impl::owner_of(tokenId) + #[external(v0)] + impl ERC721CamelOnlyImpl of interface::IERC721CamelOnly { + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { + ERC721Impl::balance_of(self, account) } - fn approve(to: ContractAddress, tokenId: u256) { - ERC721Impl::approve(to, tokenId) + fn ownerOf(self: @ContractState, tokenId: u256) -> ContractAddress { + ERC721Impl::owner_of(self, tokenId) } - fn getApproved(tokenId: u256) -> ContractAddress { - ERC721Impl::get_approved(tokenId) + fn getApproved(self: @ContractState, tokenId: u256) -> ContractAddress { + ERC721Impl::get_approved(self, tokenId) } - fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool { - ERC721Impl::is_approved_for_all(owner, operator) + fn isApprovedForAll( + self: @ContractState, owner: ContractAddress, operator: ContractAddress + ) -> bool { + ERC721Impl::is_approved_for_all(self, owner, operator) } - fn setApprovalForAll(operator: ContractAddress, approved: bool) { - ERC721Impl::set_approval_for_all(operator, approved) + fn setApprovalForAll(ref self: ContractState, operator: ContractAddress, approved: bool) { + ERC721Impl::set_approval_for_all(ref self, operator, approved) } - fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256) { - ERC721Impl::transfer_from(from, to, tokenId) + fn transferFrom( + ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256 + ) { + ERC721Impl::transfer_from(ref self, from, to, tokenId) } fn safeTransferFrom( - from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ref self: ContractState, + from: ContractAddress, + to: ContractAddress, + tokenId: u256, + data: Span ) { - ERC721Impl::safe_transfer_from(from, to, tokenId, data) + ERC721Impl::safe_transfer_from(ref self, from, to, tokenId, data) } } - // View - - #[view] - fn supports_interface(interface_id: felt252) -> bool { - ISRC5Impl::supports_interface(interface_id) - } - - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - ISRC5CamelImpl::supportsInterface(interfaceId) - } - - #[view] - fn name() -> felt252 { - ERC721Impl::name() - } - - #[view] - fn symbol() -> felt252 { - ERC721Impl::symbol() - } - - #[view] - fn token_uri(token_id: u256) -> felt252 { - ERC721Impl::token_uri(token_id) - } - - #[view] - fn tokenUri(tokenId: u256) -> felt252 { - ERC721CamelImpl::tokenUri(tokenId) - } - - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC721Impl::balance_of(account) - } - - #[view] - fn balanceOf(account: ContractAddress) -> u256 { - ERC721CamelImpl::balanceOf(account) - } - - #[view] - fn owner_of(token_id: u256) -> ContractAddress { - ERC721Impl::owner_of(token_id) - } - - #[view] - fn ownerOf(tokenId: u256) -> ContractAddress { - ERC721CamelImpl::ownerOf(tokenId) - } - - #[view] - fn get_approved(token_id: u256) -> ContractAddress { - ERC721Impl::get_approved(token_id) - } - - #[view] - fn getApproved(tokenId: u256) -> ContractAddress { - ERC721CamelImpl::getApproved(tokenId) - } - - #[view] - fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool { - ERC721Impl::is_approved_for_all(owner, operator) - } - - #[view] - fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool { - ERC721CamelImpl::isApprovedForAll(owner, operator) - } - - // External - - #[external] - fn approve(to: ContractAddress, token_id: u256) { - ERC721Impl::approve(to, token_id) - } - - #[external] - fn set_approval_for_all(operator: ContractAddress, approved: bool) { - ERC721Impl::set_approval_for_all(operator, approved) - } - - #[external] - fn setApprovalForAll(operator: ContractAddress, approved: bool) { - ERC721CamelImpl::setApprovalForAll(operator, approved) - } - - #[external] - fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) { - ERC721Impl::transfer_from(from, to, token_id) - } - - #[external] - fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256) { - ERC721CamelImpl::transferFrom(from, to, tokenId) - } - - #[external] - fn safe_transfer_from( - from: ContractAddress, to: ContractAddress, token_id: u256, data: Span - ) { - ERC721Impl::safe_transfer_from(from, to, token_id, data) - } - - #[external] - fn safeTransferFrom( - from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span - ) { - ERC721CamelImpl::safeTransferFrom(from, to, tokenId, data) - } - + // // Internal - - #[internal] - fn initializer(name_: felt252, symbol_: felt252) { - _name::write(name_); - _symbol::write(symbol_); - src5::SRC5::register_interface(erc721::interface::IERC721_ID); - src5::SRC5::register_interface(erc721::interface::IERC721_METADATA_ID); - } - - #[internal] - fn _owner_of(token_id: u256) -> ContractAddress { - let owner = _owners::read(token_id); - match owner.is_zero() { - bool::False(()) => owner, - bool::True(()) => panic_with_felt252('ERC721: invalid token ID') + // + + #[generate_trait] + impl InternalImpl of InternalTrait { + fn initializer(ref self: ContractState, name_: felt252, symbol_: felt252) { + self._name.write(name_); + self._symbol.write(symbol_); + + let mut unsafe_state = src5::SRC5::unsafe_new_contract_state(); + src5::SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IERC721_ID); + src5::SRC5::InternalImpl::register_interface( + ref unsafe_state, interface::IERC721_METADATA_ID + ); } - } - #[internal] - fn _exists(token_id: u256) -> bool { - !_owners::read(token_id).is_zero() - } + fn _owner_of(self: @ContractState, token_id: u256) -> ContractAddress { + let owner = self._owners.read(token_id); + match owner.is_zero() { + bool::False(()) => owner, + bool::True(()) => panic_with_felt252('ERC721: invalid token ID') + } + } - #[internal] - fn _is_approved_or_owner(spender: ContractAddress, token_id: u256) -> bool { - let owner = _owner_of(token_id); - owner == spender | is_approved_for_all(owner, spender) | spender == get_approved(token_id) - } + fn _exists(self: @ContractState, token_id: u256) -> bool { + !self._owners.read(token_id).is_zero() + } - #[internal] - fn _approve(to: ContractAddress, token_id: u256) { - let owner = _owner_of(token_id); - assert(owner != to, 'ERC721: approval to owner'); - _token_approvals::write(token_id, to); - Approval(owner, to, token_id); - } + fn _is_approved_or_owner( + self: @ContractState, spender: ContractAddress, token_id: u256 + ) -> bool { + let owner = self._owner_of(token_id); + let is_approved_for_all = ERC721Impl::is_approved_for_all(self, owner, spender); + owner == spender + || is_approved_for_all + || spender == ERC721Impl::get_approved(self, token_id) + } - #[internal] - fn _set_approval_for_all(owner: ContractAddress, operator: ContractAddress, approved: bool) { - assert(owner != operator, 'ERC721: self approval'); - _operator_approvals::write((owner, operator), approved); - ApprovalForAll(owner, operator, approved); - } + fn _approve(ref self: ContractState, to: ContractAddress, token_id: u256) { + let owner = self._owner_of(token_id); + assert(owner != to, 'ERC721: approval to owner'); - #[internal] - fn _mint(to: ContractAddress, token_id: u256) { - assert(!to.is_zero(), 'ERC721: invalid receiver'); - assert(!_exists(token_id), 'ERC721: token already minted'); + self._token_approvals.write(token_id, to); + self.emit(Approval { owner, approved: to, token_id }); + } - // Update balances - _balances::write(to, _balances::read(to) + 1); + fn _set_approval_for_all( + ref self: ContractState, + owner: ContractAddress, + operator: ContractAddress, + approved: bool + ) { + assert(owner != operator, 'ERC721: self approval'); + self._operator_approvals.write((owner, operator), approved); + self.emit(ApprovalForAll { owner, operator, approved }); + } - // Update token_id owner - _owners::write(token_id, to); + fn _mint(ref self: ContractState, to: ContractAddress, token_id: u256) { + assert(!to.is_zero(), 'ERC721: invalid receiver'); + assert(!self._exists(token_id), 'ERC721: token already minted'); - // Emit event - Transfer(Zeroable::zero(), to, token_id); - } + self._balances.write(to, self._balances.read(to) + 1); + self._owners.write(token_id, to); - #[internal] - fn _transfer(from: ContractAddress, to: ContractAddress, token_id: u256) { - assert(!to.is_zero(), 'ERC721: invalid receiver'); - let owner = _owner_of(token_id); - assert(from == owner, 'ERC721: wrong sender'); + self.emit(Transfer { from: Zeroable::zero(), to, token_id }); + } - // Implicit clear approvals, no need to emit an event - _token_approvals::write(token_id, Zeroable::zero()); + fn _transfer( + ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ) { + assert(!to.is_zero(), 'ERC721: invalid receiver'); + let owner = self._owner_of(token_id); + assert(from == owner, 'ERC721: wrong sender'); - // Update balances - _balances::write(from, _balances::read(from) - 1); - _balances::write(to, _balances::read(to) + 1); + // Implicit clear approvals, no need to emit an event + self._token_approvals.write(token_id, Zeroable::zero()); - // Update token_id owner - _owners::write(token_id, to); + self._balances.write(from, self._balances.read(from) - 1); + self._balances.write(to, self._balances.read(to) + 1); + self._owners.write(token_id, to); - // Emit event - Transfer(from, to, token_id); - } + self.emit(Transfer { from, to, token_id }); + } - #[internal] - fn _burn(token_id: u256) { - let owner = _owner_of(token_id); + fn _burn(ref self: ContractState, token_id: u256) { + let owner = self._owner_of(token_id); - // Implicit clear approvals, no need to emit an event - _token_approvals::write(token_id, Zeroable::zero()); + // Implicit clear approvals, no need to emit an event + self._token_approvals.write(token_id, Zeroable::zero()); - // Update balances - _balances::write(owner, _balances::read(owner) - 1); + self._balances.write(owner, self._balances.read(owner) - 1); + self._owners.write(token_id, Zeroable::zero()); - // Delete owner - _owners::write(token_id, Zeroable::zero()); + self.emit(Transfer { from: owner, to: Zeroable::zero(), token_id }); + } - // Emit event - Transfer(owner, Zeroable::zero(), token_id); - } + fn _safe_mint( + ref self: ContractState, to: ContractAddress, token_id: u256, data: Span + ) { + self._mint(to, token_id); + assert( + _check_on_erc721_received(Zeroable::zero(), to, token_id, data), + 'ERC721: safe mint failed' + ); + } - #[internal] - fn _safe_mint(to: ContractAddress, token_id: u256, data: Span) { - _mint(to, token_id); - assert( - _check_on_erc721_received(Zeroable::zero(), to, token_id, data), - 'ERC721: safe mint failed' - ); - } + fn _safe_transfer( + ref self: ContractState, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span + ) { + self._transfer(from, to, token_id); + assert( + _check_on_erc721_received(from, to, token_id, data), 'ERC721: safe transfer failed' + ); + } - #[internal] - fn _safe_transfer( - from: ContractAddress, to: ContractAddress, token_id: u256, data: Span - ) { - _transfer(from, to, token_id); - assert(_check_on_erc721_received(from, to, token_id, data), 'ERC721: safe transfer failed'); + fn _set_token_uri(ref self: ContractState, token_id: u256, token_uri: felt252) { + assert(self._exists(token_id), 'ERC721: invalid token ID'); + self._token_uri.write(token_id, token_uri) + } } #[internal] - fn _set_token_uri(token_id: u256, token_uri: felt252) { - assert(_exists(token_id), 'ERC721: invalid token ID'); - _token_uri::write(token_id, token_uri) - } - - #[private] fn _check_on_erc721_received( from: ContractAddress, to: ContractAddress, token_id: u256, data: Span ) -> bool { if (DualCaseSRC5 { contract_address: to } - .supports_interface(erc721::interface::IERC721_RECEIVER_ID)) { + .supports_interface(interface::IERC721_RECEIVER_ID)) { DualCaseERC721Receiver { contract_address: to } .on_erc721_received( get_caller_address(), from, token_id, data - ) == erc721::interface::IERC721_RECEIVER_ID + ) == interface::IERC721_RECEIVER_ID } else { DualCaseSRC5 { contract_address: to }.supports_interface(account::interface::ISRC6_ID) } diff --git a/src/openzeppelin/token/erc721/interface.cairo b/src/openzeppelin/token/erc721/interface.cairo index aa0acc454..5e22d6f07 100644 --- a/src/openzeppelin/token/erc721/interface.cairo +++ b/src/openzeppelin/token/erc721/interface.cairo @@ -1,4 +1,3 @@ -use openzeppelin::utils::serde::SpanSerde; use starknet::ContractAddress; use array::SpanTrait; @@ -8,66 +7,81 @@ const IERC721_METADATA_ID: felt252 = const IERC721_RECEIVER_ID: felt252 = 0x3a0dff5f70d80458ad14ae37bb182a728e3c8cdda0402a5daa86620bdf910bc; -#[abi] -trait IERC721 { - fn balance_of(account: ContractAddress) -> u256; - fn owner_of(token_id: u256) -> ContractAddress; - fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256); +#[starknet::interface] +trait IERC721 { + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn owner_of(self: @TState, token_id: u256) -> ContractAddress; + fn transfer_from(ref self: TState, from: ContractAddress, to: ContractAddress, token_id: u256); fn safe_transfer_from( - from: ContractAddress, to: ContractAddress, token_id: u256, data: Span + ref self: TState, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span ); - fn approve(to: ContractAddress, token_id: u256); - fn set_approval_for_all(operator: ContractAddress, approved: bool); - fn get_approved(token_id: u256) -> ContractAddress; - fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool; - // IERC721Metadata - fn name() -> felt252; - fn symbol() -> felt252; - fn token_uri(token_id: u256) -> felt252; + fn approve(ref self: TState, to: ContractAddress, token_id: u256); + fn set_approval_for_all(ref self: TState, operator: ContractAddress, approved: bool); + fn get_approved(self: @TState, token_id: u256) -> ContractAddress; + fn is_approved_for_all( + self: @TState, owner: ContractAddress, operator: ContractAddress + ) -> bool; } -#[abi] -trait IERC721Camel { - fn balanceOf(account: ContractAddress) -> u256; - fn ownerOf(tokenId: u256) -> ContractAddress; - fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256); +#[starknet::interface] +trait IERC721CamelOnly { + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn ownerOf(self: @TState, tokenId: u256) -> ContractAddress; + fn transferFrom(ref self: TState, from: ContractAddress, to: ContractAddress, tokenId: u256); fn safeTransferFrom( - from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span + ref self: TState, + from: ContractAddress, + to: ContractAddress, + tokenId: u256, + data: Span ); - fn approve(to: ContractAddress, tokenId: u256); - fn setApprovalForAll(operator: ContractAddress, approved: bool); - fn getApproved(tokenId: u256) -> ContractAddress; - fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool; - // IERC721Metadata - fn name() -> felt252; - fn symbol() -> felt252; - fn tokenUri(tokenId: u256) -> felt252; + fn setApprovalForAll(ref self: TState, operator: ContractAddress, approved: bool); + fn getApproved(self: @TState, tokenId: u256) -> ContractAddress; + fn isApprovedForAll(self: @TState, owner: ContractAddress, operator: ContractAddress) -> bool; } // -// ERC721Receiver +// IERC721Metadata // -#[abi] -trait ERC721ReceiverABI { - fn on_erc721_received( - operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span - ) -> felt252; - fn onERC721Received( - operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span - ) -> felt252; +#[starknet::interface] +trait IERC721Metadata { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn token_uri(self: @TState, token_id: u256) -> felt252; } -#[abi] -trait IERC721Receiver { +#[starknet::interface] +trait IERC721MetadataCamelOnly { + fn tokenUri(self: @TState, tokenId: u256) -> felt252; +} + +// +// ERC721Receiver +// + +#[starknet::interface] +trait IERC721Receiver { fn on_erc721_received( - operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span + self: @TState, + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + data: Span ) -> felt252; } -#[abi] -trait IERC721ReceiverCamel { +#[starknet::interface] +trait IERC721ReceiverCamel { fn onERC721Received( - operator: ContractAddress, from: ContractAddress, tokenId: u256, data: Span + self: @TState, + operator: ContractAddress, + from: ContractAddress, + tokenId: u256, + data: Span ) -> felt252; } From a00a9d3e1ec7f734e9855216115f0e7539618aa3 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 21 Jul 2023 13:32:11 -0400 Subject: [PATCH 071/124] Migrate ownable to cairo2 (#665) * bump to cairo v2.0.2 * update Cargo * comment out mods * update initializable syntax * move security tests * update initializable tests * fix formatting * remove SpanSerde * update ownable syntax * add ownable_camel impl * update syntax in ownable mocks * update ownable tests * fix formatting * update cairo * update Cargo * simplify and clarify tests * fix formatting * simplify internal fns * add initializer * fix constructor, tidy up code * fix tests * Apply suggestions from code review Co-authored-by: Eric Nordelo * fix tests * change StorageTrait to InternalTrait * start refactor * change impls to external fns * use IOwnableCamelOnly * fix tests * remove unneeded mut * remove unneeded mut * Apply suggestions from code review Co-authored-by: Eric Nordelo * change to TState * fix formatting * remove Ownable prefix in fn calls * remove internal owner fn * use internal state trait to read owner --------- Co-authored-by: Eric Nordelo --- src/openzeppelin/access.cairo | 2 +- .../access/ownable/interface.cairo | 25 ++- src/openzeppelin/access/ownable/ownable.cairo | 110 ++++++------- src/openzeppelin/lib.cairo | 2 +- src/openzeppelin/tests.cairo | 2 +- src/openzeppelin/tests/access.cairo | 4 +- .../tests/access/test_dual_ownable.cairo | 17 +- .../tests/access/test_ownable.cairo | 145 ++++++++++++------ src/openzeppelin/tests/mocks.cairo | 2 +- .../tests/mocks/dual_ownable_mocks.cairo | 103 ++++++++----- 10 files changed, 235 insertions(+), 177 deletions(-) diff --git a/src/openzeppelin/access.cairo b/src/openzeppelin/access.cairo index 8f59b4ad1..55beac34c 100644 --- a/src/openzeppelin/access.cairo +++ b/src/openzeppelin/access.cairo @@ -1,2 +1,2 @@ -mod accesscontrol; +//mod accesscontrol; mod ownable; diff --git a/src/openzeppelin/access/ownable/interface.cairo b/src/openzeppelin/access/ownable/interface.cairo index 41cd27a69..4641093dc 100644 --- a/src/openzeppelin/access/ownable/interface.cairo +++ b/src/openzeppelin/access/ownable/interface.cairo @@ -1,21 +1,14 @@ use starknet::ContractAddress; -#[abi] -trait IOwnable { - #[view] - fn owner() -> ContractAddress; - #[external] - fn transfer_ownership(new_owner: ContractAddress); - #[external] - fn renounce_ownership(); +#[starknet::interface] +trait IOwnable { + fn owner(self: @TState) -> ContractAddress; + fn transfer_ownership(ref self: TState, new_owner: ContractAddress); + fn renounce_ownership(ref self: TState); } -#[abi] -trait IOwnableCamel { - #[view] - fn owner() -> ContractAddress; - #[external] - fn transferOwnership(newOwner: ContractAddress); - #[external] - fn renounceOwnership(); +#[starknet::interface] +trait IOwnableCamelOnly { + fn transferOwnership(ref self: TState, newOwner: ContractAddress); + fn renounceOwnership(ref self: TState); } diff --git a/src/openzeppelin/access/ownable/ownable.cairo b/src/openzeppelin/access/ownable/ownable.cairo index 29e21dde0..a7670a100 100644 --- a/src/openzeppelin/access/ownable/ownable.cairo +++ b/src/openzeppelin/access/ownable/ownable.cairo @@ -1,92 +1,76 @@ -#[contract] +#[starknet::contract] mod Ownable { use openzeppelin::access::ownable::interface; use starknet::ContractAddress; use starknet::get_caller_address; use zeroable::Zeroable; + #[storage] struct Storage { _owner: ContractAddress } #[event] - fn OwnershipTransferred(previous_owner: ContractAddress, new_owner: ContractAddress) {} + #[derive(Drop, starknet::Event)] + enum Event { + OwnershipTransferred: OwnershipTransferred + } + + #[derive(Drop, starknet::Event)] + struct OwnershipTransferred { + previous_owner: ContractAddress, + new_owner: ContractAddress, + } - impl OwnableImpl of interface::IOwnable { - fn owner() -> ContractAddress { - _owner::read() + #[generate_trait] + impl InternalImpl of InternalTrait { + fn initializer(ref self: ContractState, owner: ContractAddress) { + self._transfer_ownership(owner); } - fn transfer_ownership(new_owner: ContractAddress) { - assert(!new_owner.is_zero(), 'New owner is the zero address'); - assert_only_owner(); - _transfer_ownership(new_owner); + fn assert_only_owner(self: @ContractState) { + let owner: ContractAddress = self._owner.read(); + let caller: ContractAddress = get_caller_address(); + assert(!caller.is_zero(), 'Caller is the zero address'); + assert(caller == owner, 'Caller is not the owner'); } - fn renounce_ownership() { - assert_only_owner(); - _transfer_ownership(Zeroable::zero()); + fn _transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { + let previous_owner: ContractAddress = self._owner.read(); + self._owner.write(new_owner); + self + .emit( + OwnershipTransferred { previous_owner: previous_owner, new_owner: new_owner } + ); } } - impl OwnableCamelImpl of interface::IOwnableCamel { - fn owner() -> ContractAddress { - OwnableImpl::owner() + #[external(v0)] + impl OwnableImpl of interface::IOwnable { + fn owner(self: @ContractState) -> ContractAddress { + self._owner.read() } - fn transferOwnership(newOwner: ContractAddress) { - OwnableImpl::transfer_ownership(newOwner); + fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { + assert(!new_owner.is_zero(), 'New owner is the zero address'); + self.assert_only_owner(); + self._transfer_ownership(new_owner); } - fn renounceOwnership() { - OwnableImpl::renounce_ownership(); + fn renounce_ownership(ref self: ContractState) { + self.assert_only_owner(); + self._transfer_ownership(Zeroable::zero()); } } - #[view] - fn owner() -> ContractAddress { - OwnableImpl::owner() - } - - #[external] - fn transfer_ownership(new_owner: ContractAddress) { - OwnableImpl::transfer_ownership(new_owner); - } - - #[external] - fn transferOwnership(newOwner: ContractAddress) { - OwnableCamelImpl::transferOwnership(newOwner); - } - - #[external] - fn renounce_ownership() { - OwnableImpl::renounce_ownership(); - } - - #[external] - fn renounceOwnership() { - OwnableCamelImpl::renounceOwnership(); - } - - // Internals - - #[internal] - fn initializer(owner: ContractAddress) { - _transfer_ownership(owner); - } - - #[internal] - fn assert_only_owner() { - let owner: ContractAddress = _owner::read(); - let caller: ContractAddress = get_caller_address(); - assert(!caller.is_zero(), 'Caller is the zero address'); - assert(caller == owner, 'Caller is not the owner'); - } + #[external(v0)] + impl OwnableCamelOnlyImpl of interface::IOwnableCamelOnly { + fn transferOwnership(ref self: ContractState, newOwner: ContractAddress) { + OwnableImpl::transfer_ownership(ref self, newOwner); + } - #[internal] - fn _transfer_ownership(new_owner: ContractAddress) { - let previous_owner: ContractAddress = _owner::read(); - _owner::write(new_owner); - OwnershipTransferred(previous_owner, new_owner); + fn renounceOwnership(ref self: ContractState) { + OwnableImpl::renounce_ownership(ref self); + } } } diff --git a/src/openzeppelin/lib.cairo b/src/openzeppelin/lib.cairo index ef3dfb94f..e03376525 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/openzeppelin/lib.cairo @@ -1,4 +1,4 @@ -// mod access; +mod access; mod account; mod introspection; mod security; diff --git a/src/openzeppelin/tests.cairo b/src/openzeppelin/tests.cairo index d2a724b37..cc78a11ec 100644 --- a/src/openzeppelin/tests.cairo +++ b/src/openzeppelin/tests.cairo @@ -1,4 +1,4 @@ -// mod access; +mod access; mod account; mod introspection; mod mocks; diff --git a/src/openzeppelin/tests/access.cairo b/src/openzeppelin/tests/access.cairo index 149c62b59..b40958d1d 100644 --- a/src/openzeppelin/tests/access.cairo +++ b/src/openzeppelin/tests/access.cairo @@ -1,4 +1,4 @@ -mod test_accesscontrol; -mod test_dual_accesscontrol; +//mod test_accesscontrol; +//mod test_dual_accesscontrol; mod test_ownable; mod test_dual_ownable; diff --git a/src/openzeppelin/tests/access/test_dual_ownable.cairo b/src/openzeppelin/tests/access/test_dual_ownable.cairo index aa86d3874..672df30ce 100644 --- a/src/openzeppelin/tests/access/test_dual_ownable.cairo +++ b/src/openzeppelin/tests/access/test_dual_ownable.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing::set_caller_address; @@ -6,9 +5,9 @@ use starknet::testing::set_contract_address; use zeroable::Zeroable; use openzeppelin::access::ownable::interface::IOwnableDispatcher; -use openzeppelin::access::ownable::interface::IOwnableCamelDispatcher; +use openzeppelin::access::ownable::interface::IOwnableCamelOnlyDispatcher; use openzeppelin::access::ownable::interface::IOwnableDispatcherTrait; -use openzeppelin::access::ownable::interface::IOwnableCamelDispatcherTrait; +use openzeppelin::access::ownable::interface::IOwnableCamelOnlyDispatcherTrait; use openzeppelin::access::ownable::dual_ownable::DualCaseOwnableTrait; use openzeppelin::access::ownable::dual_ownable::DualCaseOwnable; use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnableMock; @@ -42,13 +41,13 @@ fn setup_snake() -> (DualCaseOwnable, IOwnableDispatcher) { (DualCaseOwnable { contract_address: target }, IOwnableDispatcher { contract_address: target }) } -fn setup_camel() -> (DualCaseOwnable, IOwnableCamelDispatcher) { +fn setup_camel() -> (DualCaseOwnable, IOwnableCamelOnlyDispatcher) { let mut calldata = ArrayTrait::new(); calldata.append_serde(OWNER()); let target = utils::deploy(CamelOwnableMock::TEST_CLASS_HASH, calldata); ( DualCaseOwnable { contract_address: target }, - IOwnableCamelDispatcher { contract_address: target } + IOwnableCamelOnlyDispatcher { contract_address: target } ) } @@ -158,10 +157,10 @@ fn test_dual_renounce_ownership_exists_and_panics() { #[test] #[available_gas(2000000)] fn test_dual_transferOwnership() { - let (dispatcher, target) = setup_camel(); + let (dispatcher, _) = setup_camel(); set_contract_address(OWNER()); dispatcher.transfer_ownership(NEW_OWNER()); - assert(target.owner() == NEW_OWNER(), 'Should be new owner'); + assert(dispatcher.owner() == NEW_OWNER(), 'Should be new owner'); } #[test] @@ -175,10 +174,10 @@ fn test_dual_transferOwnership_exists_and_panics() { #[test] #[available_gas(2000000)] fn test_dual_renounceOwnership() { - let (dispatcher, target) = setup_camel(); + let (dispatcher, _) = setup_camel(); set_contract_address(OWNER()); dispatcher.renounce_ownership(); - assert(target.owner().is_zero(), 'Should be zero'); + assert(dispatcher.owner().is_zero(), 'Should be zero'); } #[test] diff --git a/src/openzeppelin/tests/access/test_ownable.cairo b/src/openzeppelin/tests/access/test_ownable.cairo index a3a4f0af9..2b906dbed 100644 --- a/src/openzeppelin/tests/access/test_ownable.cairo +++ b/src/openzeppelin/tests/access/test_ownable.cairo @@ -1,25 +1,37 @@ -use openzeppelin::access::ownable::Ownable; - use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; use zeroable::Zeroable; +use openzeppelin::access::ownable::Ownable; +use openzeppelin::access::ownable::Ownable::OwnableImpl; +use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; +use openzeppelin::access::ownable::Ownable::InternalImpl; +use openzeppelin::access::ownable::Ownable::_owner::InternalContractStateTrait; fn ZERO() -> ContractAddress { contract_address_const::<0>() } fn OWNER() -> ContractAddress { - contract_address_const::<1>() + contract_address_const::<10>() } fn OTHER() -> ContractAddress { - contract_address_const::<2>() + contract_address_const::<20>() } -fn setup() { - testing::set_caller_address(OWNER()); - Ownable::initializer(OWNER()); +// +// Setup +// + +fn STATE() -> Ownable::ContractState { + Ownable::contract_state_for_testing() +} + +fn setup() -> Ownable::ContractState { + let mut state = STATE(); + InternalImpl::initializer(ref state, OWNER()); + state } // @@ -29,9 +41,51 @@ fn setup() { #[test] #[available_gas(2000000)] fn test_initializer() { - assert(Ownable::owner().is_zero(), 'Should be zero'); - setup(); - assert(Ownable::owner() == OWNER(), 'Owner should be set'); + let mut state = STATE(); + assert(state._owner.read().is_zero(), 'Should be zero'); + InternalImpl::initializer(ref state, OWNER()); + assert(state._owner.read() == OWNER(), 'Owner should be set'); +} + +// +// assert_only_owner +// + +#[test] +#[available_gas(2000000)] +fn test_assert_only_owner() { + let state = setup(); + testing::set_caller_address(OWNER()); + InternalImpl::assert_only_owner(@state); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is not the owner', ))] +fn test_assert_only_owner_when_not_owner() { + let state = setup(); + testing::set_caller_address(OTHER()); + InternalImpl::assert_only_owner(@state); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Caller is the zero address', ))] +fn test_assert_only_owner_when_caller_zero() { + let state = setup(); + InternalImpl::assert_only_owner(@state); +} + +// +// _transfer_ownership +// + +#[test] +#[available_gas(2000000)] +fn test__transfer_ownership() { + let mut state = setup(); + InternalImpl::_transfer_ownership(ref state, OTHER()); + assert(state._owner.read() == OTHER(), 'Owner should be OTHER'); } // @@ -41,65 +95,71 @@ fn test_initializer() { #[test] #[available_gas(2000000)] fn test_transfer_ownership() { - setup(); - Ownable::transfer_ownership(OTHER()); - assert(Ownable::owner() == OTHER(), 'Should transfer ownership'); + let mut state = setup(); + testing::set_caller_address(OWNER()); + OwnableImpl::transfer_ownership(ref state, OTHER()); + assert(OwnableImpl::owner(@state) == OTHER(), 'Should transfer ownership'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('New owner is the zero address', ))] fn test_transfer_ownership_to_zero() { - setup(); - Ownable::transfer_ownership(ZERO()); + let mut state = setup(); + testing::set_caller_address(OWNER()); + OwnableImpl::transfer_ownership(ref state, ZERO()); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address', ))] fn test_transfer_ownership_from_zero() { - Ownable::transfer_ownership(OTHER()); + let mut state = setup(); + OwnableImpl::transfer_ownership(ref state, OTHER()); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner', ))] fn test_transfer_ownership_from_nonowner() { - setup(); + let mut state = setup(); testing::set_caller_address(OTHER()); - Ownable::transfer_ownership(OTHER()); + OwnableImpl::transfer_ownership(ref state, OTHER()); } #[test] #[available_gas(2000000)] fn test_transferOwnership() { - setup(); - Ownable::transferOwnership(OTHER()); - assert(Ownable::owner() == OTHER(), 'Should transfer ownership'); + let mut state = setup(); + testing::set_caller_address(OWNER()); + OwnableCamelOnlyImpl::transferOwnership(ref state, OTHER()); + assert(OwnableImpl::owner(@state) == OTHER(), 'Should transfer ownership'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('New owner is the zero address', ))] fn test_transferOwnership_to_zero() { - setup(); - Ownable::transferOwnership(ZERO()); + let mut state = setup(); + testing::set_caller_address(OWNER()); + OwnableCamelOnlyImpl::transferOwnership(ref state, ZERO()); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address', ))] fn test_transferOwnership_from_zero() { - Ownable::transferOwnership(OTHER()); + let mut state = setup(); + OwnableCamelOnlyImpl::transferOwnership(ref state, OTHER()); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner', ))] fn test_transferOwnership_from_nonowner() { - setup(); + let mut state = setup(); testing::set_caller_address(OTHER()); - Ownable::transferOwnership(OTHER()); + OwnableCamelOnlyImpl::transferOwnership(ref state, OTHER()); } // @@ -109,52 +169,51 @@ fn test_transferOwnership_from_nonowner() { #[test] #[available_gas(2000000)] fn test_renounce_ownership() { - setup(); - Ownable::renounce_ownership(); - assert(Ownable::owner() == ZERO(), 'Should renounce ownership'); + let mut state = setup(); + testing::set_caller_address(OWNER()); + OwnableImpl::renounce_ownership(ref state); + assert(OwnableImpl::owner(@state) == ZERO(), 'Should renounce ownership'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address', ))] fn test_renounce_ownership_from_zero_address() { - setup(); - testing::set_caller_address(ZERO()); - Ownable::renounce_ownership(); + let mut state = setup(); + OwnableImpl::renounce_ownership(ref state); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner', ))] fn test_renounce_ownership_from_nonowner() { - setup(); + let mut state = setup(); testing::set_caller_address(OTHER()); - Ownable::renounce_ownership(); + OwnableImpl::renounce_ownership(ref state); } #[test] #[available_gas(2000000)] fn test_renounceOwnership() { - setup(); - Ownable::renounceOwnership(); - assert(Ownable::owner() == ZERO(), 'Should renounce ownership'); + let mut state = setup(); + testing::set_caller_address(OWNER()); + OwnableCamelOnlyImpl::renounceOwnership(ref state); + assert(OwnableImpl::owner(@state) == ZERO(), 'Should renounce ownership'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address', ))] fn test_renounceOwnership_from_zero_address() { - setup(); - testing::set_caller_address(ZERO()); - Ownable::renounceOwnership(); + let mut state = setup(); + OwnableCamelOnlyImpl::renounceOwnership(ref state); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner', ))] fn test_renounceOwnership_from_nonowner() { - setup(); + let mut state = setup(); testing::set_caller_address(OTHER()); - Ownable::renounceOwnership(); + OwnableCamelOnlyImpl::renounceOwnership(ref state); } - diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 0e838248e..4670b5c0c 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -12,7 +12,7 @@ mod account_panic_mock; mod camel_account_mock; // mod snake_accesscontrol_mock; mod snake_account_mock; -// mod dual_ownable_mocks; +mod dual_ownable_mocks; mod snake721_mock; mod camel721_mock; mod non_implementing_mock; diff --git a/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo b/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo index 407d63e3b..7826e859e 100644 --- a/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo +++ b/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo @@ -1,93 +1,116 @@ -#[contract] +use openzeppelin::access::ownable::Ownable; + +#[starknet::contract] mod SnakeOwnableMock { use starknet::ContractAddress; - use openzeppelin::access::ownable::Ownable; + use super::Ownable; + + #[storage] + struct Storage {} #[constructor] - fn constructor(owner: ContractAddress) { - Ownable::initializer(owner); + fn constructor(self: @ContractState, owner: ContractAddress) { + let mut unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::InternalImpl::initializer(ref unsafe_state, owner); } - #[view] - fn owner() -> ContractAddress { - Ownable::owner() + #[external(v0)] + fn owner(self: @ContractState) -> ContractAddress { + let unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::OwnableImpl::owner(@unsafe_state) } - #[external] - fn transfer_ownership(new_owner: ContractAddress) { - Ownable::transfer_ownership(new_owner); + #[external(v0)] + fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { + let mut unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::OwnableImpl::transfer_ownership(ref unsafe_state, new_owner); } - #[external] - fn renounce_ownership() { - Ownable::renounce_ownership(); + #[external(v0)] + fn renounce_ownership(ref self: ContractState) { + let mut unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::OwnableImpl::renounce_ownership(ref unsafe_state); } } -#[contract] +#[starknet::contract] mod CamelOwnableMock { use starknet::ContractAddress; - use openzeppelin::access::ownable::Ownable; + use super::Ownable; + + #[storage] + struct Storage {} #[constructor] - fn constructor(owner: ContractAddress) { - Ownable::initializer(owner); + fn constructor(self: @ContractState, owner: ContractAddress) { + let mut unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::InternalImpl::initializer(ref unsafe_state, owner); } - #[view] - fn owner() -> ContractAddress { - Ownable::owner() + #[external(v0)] + fn owner(self: @ContractState) -> ContractAddress { + let unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::OwnableImpl::owner(@unsafe_state) } - #[external] - fn transferOwnership(newOwner: ContractAddress) { - Ownable::transferOwnership(newOwner); + #[external(v0)] + fn transferOwnership(ref self: ContractState, newOwner: ContractAddress) { + let mut unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::OwnableCamelOnlyImpl::transferOwnership(ref unsafe_state, newOwner); } - #[external] - fn renounceOwnership() { - Ownable::renounceOwnership(); + #[external(v0)] + fn renounceOwnership(ref self: ContractState) { + let mut unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::OwnableCamelOnlyImpl::renounceOwnership(ref unsafe_state); } } -#[contract] +#[starknet::contract] mod SnakeOwnablePanicMock { use starknet::ContractAddress; + use zeroable::Zeroable; - #[view] - fn owner() -> ContractAddress { + #[storage] + struct Storage {} + + #[external(v0)] + fn owner(self: @ContractState) -> ContractAddress { panic_with_felt252('Some error'); Zeroable::zero() } - #[external] - fn transfer_ownership(new_owner: ContractAddress) { + #[external(v0)] + fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { panic_with_felt252('Some error'); } - #[external] - fn renounce_ownership() { + #[external(v0)] + fn renounce_ownership(ref self: ContractState) { panic_with_felt252('Some error'); } } -#[contract] +#[starknet::contract] mod CamelOwnablePanicMock { use starknet::ContractAddress; - #[view] - fn owner() -> ContractAddress { + #[storage] + struct Storage {} + + #[external(v0)] + fn owner(self: @ContractState) -> ContractAddress { panic_with_felt252('Some error'); Zeroable::zero() } - #[external] - fn transfer_ownership(new_owner: ContractAddress) { + #[external(v0)] + fn transferOwnership(ref self: ContractState, newOwner: ContractAddress) { panic_with_felt252('Some error'); } - #[external] - fn renounce_ownership() { + #[external(v0)] + fn renounceOwnership(ref self: ContractState) { panic_with_felt252('Some error'); } } From 0b40485b8e332af7ff5a0472171b05455648f0ad Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Sat, 22 Jul 2023 17:30:03 +0200 Subject: [PATCH 072/124] Migrate ERC20 to Cairo 2 (#669) * feat: fix tests * feat: apply review updates --- src/openzeppelin/account.cairo | 13 +- src/openzeppelin/account/account.cairo | 29 -- src/openzeppelin/account/interface.cairo | 29 ++ .../tests/account/test_account.cairo | 224 +++++----- src/openzeppelin/tests/mocks.cairo | 7 +- .../tests/mocks/camel20_mock.cairo | 81 ++-- .../tests/mocks/erc20_panic.cairo | 83 ++-- .../tests/mocks/mock_pausable.cairo | 34 -- .../tests/mocks/snake20_mock.cairo | 81 ++-- src/openzeppelin/tests/token.cairo | 5 +- .../tests/token/test_dual20.cairo | 10 +- src/openzeppelin/tests/token/test_erc20.cairo | 321 +++++++------- src/openzeppelin/token.cairo | 2 +- src/openzeppelin/token/erc20.cairo | 6 +- src/openzeppelin/token/erc20/dual20.cairo | 22 +- src/openzeppelin/token/erc20/erc20.cairo | 411 +++++++----------- src/openzeppelin/token/erc20/interface.cairo | 110 +++-- 17 files changed, 725 insertions(+), 743 deletions(-) delete mode 100644 src/openzeppelin/tests/mocks/mock_pausable.cairo diff --git a/src/openzeppelin/account.cairo b/src/openzeppelin/account.cairo index 47e57df8a..d8f6cab7a 100644 --- a/src/openzeppelin/account.cairo +++ b/src/openzeppelin/account.cairo @@ -1,8 +1,11 @@ mod account; -use account::{ - Account, AccountCamelABIDispatcher, AccountCamelABIDispatcherTrait, AccountABIDispatcher, - AccountABIDispatcherTrait, TRANSACTION_VERSION, QUERY_VERSION -}; - mod dual_account; mod interface; + +use account::Account; +use account::TRANSACTION_VERSION; +use account::QUERY_VERSION; +use interface::AccountCamelABIDispatcher; +use interface::AccountCamelABIDispatcherTrait; +use interface::AccountABIDispatcher; +use interface::AccountABIDispatcherTrait; diff --git a/src/openzeppelin/account/account.cairo b/src/openzeppelin/account/account.cairo index e1a3d57dd..21b2d79d7 100644 --- a/src/openzeppelin/account/account.cairo +++ b/src/openzeppelin/account/account.cairo @@ -10,35 +10,6 @@ const TRANSACTION_VERSION: felt252 = 1; // 2**128 + TRANSACTION_VERSION const QUERY_VERSION: felt252 = 340282366920938463463374607431768211457; -#[starknet::interface] -trait AccountABI { - fn __execute__(self: @TState, calls: Array) -> Array>; - fn __validate__(self: @TState, calls: Array) -> felt252; - fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252; - fn __validate_deploy__( - self: @TState, class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 - ) -> felt252; - fn set_public_key(ref self: TState, new_public_key: felt252); - fn get_public_key(self: @TState) -> felt252; - fn is_valid_signature(self: @TState, hash: felt252, signature: Array) -> felt252; - fn supports_interface(self: @TState, interface_id: felt252) -> bool; -} - -// Entry points case-convention is enforced by the protocol -#[starknet::interface] -trait AccountCamelABI { - fn __execute__(self: @TState, calls: Array) -> Array>; - fn __validate__(self: @TState, calls: Array) -> felt252; - fn __validate_declare__(self: @TState, classHash: felt252) -> felt252; - fn __validate_deploy__( - self: @TState, classHash: felt252, contractAddressSalt: felt252, _publicKey: felt252 - ) -> felt252; - fn setPublicKey(ref self: TState, newPublicKey: felt252); - fn getPublicKey(self: @TState) -> felt252; - fn isValidSignature(self: @TState, hash: felt252, signature: Array) -> felt252; - fn supportsInterface(self: @TState, interfaceId: felt252) -> bool; -} - trait PublicKeyTrait { fn set_public_key(ref self: TState, new_public_key: felt252); fn get_public_key(self: @TState) -> felt252; diff --git a/src/openzeppelin/account/interface.cairo b/src/openzeppelin/account/interface.cairo index 2027c0c99..e557b6dec 100644 --- a/src/openzeppelin/account/interface.cairo +++ b/src/openzeppelin/account/interface.cairo @@ -21,3 +21,32 @@ trait ISRC6CamelOnly { trait IDeclarer { fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252; } + +#[starknet::interface] +trait AccountABI { + fn __execute__(self: @TState, calls: Array) -> Array>; + fn __validate__(self: @TState, calls: Array) -> felt252; + fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252; + fn __validate_deploy__( + self: @TState, class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + ) -> felt252; + fn set_public_key(ref self: TState, new_public_key: felt252); + fn get_public_key(self: @TState) -> felt252; + fn is_valid_signature(self: @TState, hash: felt252, signature: Array) -> felt252; + fn supports_interface(self: @TState, interface_id: felt252) -> bool; +} + +// Entry points case-convention is enforced by the protocol +#[starknet::interface] +trait AccountCamelABI { + fn __execute__(self: @TState, calls: Array) -> Array>; + fn __validate__(self: @TState, calls: Array) -> felt252; + fn __validate_declare__(self: @TState, classHash: felt252) -> felt252; + fn __validate_deploy__( + self: @TState, classHash: felt252, contractAddressSalt: felt252, _publicKey: felt252 + ) -> felt252; + fn setPublicKey(ref self: TState, newPublicKey: felt252); + fn getPublicKey(self: @TState) -> felt252; + fn isValidSignature(self: @TState, hash: felt252, signature: Array) -> felt252; + fn supportsInterface(self: @TState, interfaceId: felt252) -> bool; +} diff --git a/src/openzeppelin/tests/account/test_account.cairo b/src/openzeppelin/tests/account/test_account.cairo index 48ab02685..b5d9828f7 100644 --- a/src/openzeppelin/tests/account/test_account.cairo +++ b/src/openzeppelin/tests/account/test_account.cairo @@ -15,9 +15,9 @@ use openzeppelin::account::QUERY_VERSION; use openzeppelin::account::TRANSACTION_VERSION; use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::utils; -// use openzeppelin::token::erc20::ERC20; -// use openzeppelin::token::erc20::interface::IERC20Dispatcher; -// use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; +use openzeppelin::token::erc20::ERC20; +use openzeppelin::token::erc20::interface::IERC20Dispatcher; +use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; @@ -78,19 +78,19 @@ fn setup_dispatcher(data: Option<@SignedTransactionData>) -> AccountABIDispatche AccountABIDispatcher { contract_address: address } } -// fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispatcher { -// let name = 0; -// let symbol = 0; -// let mut calldata = array![]; +fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispatcher { + let name = 0; + let symbol = 0; + let mut calldata = array![]; -// calldata.append_serde(name); -// calldata.append_serde(symbol); -// calldata.append_serde(initial_supply); -// calldata.append_serde(recipient); + calldata.append_serde(name); + calldata.append_serde(symbol); + calldata.append_serde(initial_supply); + calldata.append_serde(recipient); -// let address = utils::deploy(ERC20::TEST_CLASS_HASH, calldata); -// IERC20Dispatcher { contract_address: address } -// } + let address = utils::deploy(ERC20::TEST_CLASS_HASH, calldata); + IERC20Dispatcher { contract_address: address } +} // // constructor @@ -281,59 +281,59 @@ fn test_validate_declare_empty_signature() { account.__validate_declare__(CLASS_HASH()); } -// fn test_execute_with_version(version: Option) { -// let data = SIGNED_TX_DATA(); -// let account = setup_dispatcher(Option::Some(@data)); -// let erc20 = deploy_erc20(account.contract_address, 1000); -// let recipient = contract_address_const::<0x123>(); - -// // Craft call and add to calls array -// let mut calldata = array![]; -// let amount: u256 = 200; -// calldata.append_serde(recipient); -// calldata.append_serde(amount); -// let call = Call { -// to: erc20.contract_address, selector: selectors::transfer, calldata: calldata -// }; -// let mut calls = array![]; -// calls.append(call); - -// // Handle version for test -// if version.is_some() { -// testing::set_version(version.unwrap()); -// } - -// // Execute -// let ret = account.__execute__(calls); - -// // Assert that the transfer was successful -// assert(erc20.balance_of(account.contract_address) == 800, 'Should have remainder'); -// assert(erc20.balance_of(recipient) == amount, 'Should have transferred'); - -// // Test return value -// let mut call_serialized_retval = *ret.at(0); -// let call_retval = Serde::::deserialize(ref call_serialized_retval); -// assert(call_retval.unwrap(), 'Should have succeeded'); -// } - -// #[test] -// #[available_gas(2000000)] -// fn test_execute() { -// test_execute_with_version(Option::None(())); -// } - -// #[test] -// #[available_gas(2000000)] -// fn test_execute_query_version() { -// test_execute_with_version(Option::Some(QUERY_VERSION)); -// } - -// #[test] -// #[available_gas(2000000)] -// #[should_panic(expected: ('Account: invalid tx version', 'ENTRYPOINT_FAILED'))] -// fn test_execute_invalid_version() { -// test_execute_with_version(Option::Some(TRANSACTION_VERSION - 1)); -// } +fn test_execute_with_version(version: Option) { + let data = SIGNED_TX_DATA(); + let account = setup_dispatcher(Option::Some(@data)); + let erc20 = deploy_erc20(account.contract_address, 1000); + let recipient = contract_address_const::<0x123>(); + + // Craft call and add to calls array + let mut calldata = array![]; + let amount: u256 = 200; + calldata.append_serde(recipient); + calldata.append_serde(amount); + let call = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata + }; + let mut calls = array![]; + calls.append(call); + + // Handle version for test + if version.is_some() { + testing::set_version(version.unwrap()); + } + + // Execute + let ret = account.__execute__(calls); + + // Assert that the transfer was successful + assert(erc20.balance_of(account.contract_address) == 800, 'Should have remainder'); + assert(erc20.balance_of(recipient) == amount, 'Should have transferred'); + + // Test return value + let mut call_serialized_retval = *ret.at(0); + let call_retval = Serde::::deserialize(ref call_serialized_retval); + assert(call_retval.unwrap(), 'Should have succeeded'); +} + +#[test] +#[available_gas(2000000)] +fn test_execute() { + test_execute_with_version(Option::None(())); +} + +#[test] +#[available_gas(2000000)] +fn test_execute_query_version() { + test_execute_with_version(Option::Some(QUERY_VERSION)); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Account: invalid tx version', 'ENTRYPOINT_FAILED'))] +fn test_execute_invalid_version() { + test_execute_with_version(Option::Some(TRANSACTION_VERSION - 1)); +} #[test] #[available_gas(2000000)] @@ -356,51 +356,51 @@ fn test_validate_invalid() { account.__validate__(calls); } -// #[test] -// #[available_gas(2000000)] -// fn test_multicall() { -// let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); -// let erc20 = deploy_erc20(account.contract_address, 1000); -// let recipient1 = contract_address_const::<0x123>(); -// let recipient2 = contract_address_const::<0x456>(); -// let mut calls = array![]; - -// // Craft call1 -// let mut calldata1 = array![]; -// let amount1: u256 = 300; -// calldata1.append_serde(recipient1); -// calldata1.append_serde(amount1); -// let call1 = Call { -// to: erc20.contract_address, selector: selectors::transfer, calldata: calldata1 -// }; - -// // Craft call2 -// let mut calldata2 = array![]; -// let amount2: u256 = 500; -// calldata2.append_serde(recipient2); -// calldata2.append_serde(amount2); -// let call2 = Call { -// to: erc20.contract_address, selector: selectors::transfer, calldata: calldata2 -// }; - -// // Bundle calls and exeute -// calls.append(call1); -// calls.append(call2); -// let ret = account.__execute__(calls); - -// // Assert that the transfers were successful -// assert(erc20.balance_of(account.contract_address) == 200, 'Should have remainder'); -// assert(erc20.balance_of(recipient1) == 300, 'Should have transferred'); -// assert(erc20.balance_of(recipient2) == 500, 'Should have transferred'); - -// // Test return value -// let mut call1_serialized_retval = *ret.at(0); -// let mut call2_serialized_retval = *ret.at(1); -// let call1_retval = Serde::::deserialize(ref call1_serialized_retval); -// let call2_retval = Serde::::deserialize(ref call2_serialized_retval); -// assert(call1_retval.unwrap(), 'Should have succeeded'); -// assert(call2_retval.unwrap(), 'Should have succeeded'); -// } +#[test] +#[available_gas(20000000)] +fn test_multicall() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let erc20 = deploy_erc20(account.contract_address, 1000); + let recipient1 = contract_address_const::<0x123>(); + let recipient2 = contract_address_const::<0x456>(); + let mut calls = array![]; + + // Craft call1 + let mut calldata1 = array![]; + let amount1: u256 = 300; + calldata1.append_serde(recipient1); + calldata1.append_serde(amount1); + let call1 = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata1 + }; + + // Craft call2 + let mut calldata2 = array![]; + let amount2: u256 = 500; + calldata2.append_serde(recipient2); + calldata2.append_serde(amount2); + let call2 = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata2 + }; + + // Bundle calls and exeute + calls.append(call1); + calls.append(call2); + let ret = account.__execute__(calls); + + // Assert that the transfers were successful + assert(erc20.balance_of(account.contract_address) == 200, 'Should have remainder'); + assert(erc20.balance_of(recipient1) == 300, 'Should have transferred'); + assert(erc20.balance_of(recipient2) == 500, 'Should have transferred'); + + // Test return value + let mut call1_serialized_retval = *ret.at(0); + let mut call2_serialized_retval = *ret.at(1); + let call1_retval = Serde::::deserialize(ref call1_serialized_retval); + let call2_retval = Serde::::deserialize(ref call2_serialized_retval); + assert(call1_retval.unwrap(), 'Should have succeeded'); + assert(call2_retval.unwrap(), 'Should have succeeded'); +} #[test] #[available_gas(2000000)] diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 4670b5c0c..4a8530b24 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -2,10 +2,9 @@ mod reentrancy_attacker_mock; mod reentrancy_mock; mod erc721_receiver; mod erc721_panic_mock; -// mod mock_pausable; -// mod camel20_mock; -// mod snake20_mock; -// mod erc20_panic; +mod camel20_mock; +mod snake20_mock; +mod erc20_panic; // mod accesscontrol_panic_mock; mod account_panic_mock; // mod camel_accesscontrol_mock; diff --git a/src/openzeppelin/tests/mocks/camel20_mock.cairo b/src/openzeppelin/tests/mocks/camel20_mock.cairo index 3b9bd1048..6eab0e06f 100644 --- a/src/openzeppelin/tests/mocks/camel20_mock.cairo +++ b/src/openzeppelin/tests/mocks/camel20_mock.cairo @@ -1,58 +1,77 @@ -#[contract] +#[starknet::contract] mod CamelERC20Mock { use starknet::ContractAddress; use openzeppelin::token::erc20::ERC20; + #[storage] + struct Storage {} + #[constructor] fn constructor( - name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress + ref self: ContractState, + name: felt252, + symbol: felt252, + initial_supply: u256, + recipient: ContractAddress ) { - ERC20::initializer(name, symbol); - ERC20::_mint(recipient, initial_supply); + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::InternalImpl::initializer(ref unsafe_state, name, symbol); + ERC20::InternalImpl::_mint(ref unsafe_state, recipient, initial_supply); } - #[view] - fn name() -> felt252 { - ERC20::name() + #[external(v0)] + fn name(self: @ContractState) -> felt252 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::name(@unsafe_state) } - #[view] - fn symbol() -> felt252 { - ERC20::symbol() + #[external(v0)] + fn symbol(self: @ContractState) -> felt252 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::symbol(@unsafe_state) } - #[view] - fn decimals() -> u8 { - ERC20::decimals() + #[external(v0)] + fn decimals(self: @ContractState) -> u8 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::decimals(@unsafe_state) } - #[view] - fn totalSupply() -> u256 { - ERC20::totalSupply() + #[external(v0)] + fn totalSupply(self: @ContractState) -> u256 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20CamelOnlyImpl::totalSupply(@unsafe_state) } - #[view] - fn balanceOf(account: ContractAddress) -> u256 { - ERC20::balanceOf(account) + #[external(v0)] + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20CamelOnlyImpl::balanceOf(@unsafe_state, account) } - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20::allowance(owner, spender) + #[external(v0)] + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::allowance(@unsafe_state, owner, spender) } - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20::transfer(recipient, amount) + #[external(v0)] + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::transfer(ref unsafe_state, recipient, amount) } - #[external] - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20::transferFrom(sender, recipient, amount) + #[external(v0)] + fn transferFrom( + ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool { + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20CamelOnlyImpl::transferFrom(ref unsafe_state, sender, recipient, amount) } - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20::approve(spender, amount) + #[external(v0)] + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool { + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::approve(ref unsafe_state, spender, amount) } } diff --git a/src/openzeppelin/tests/mocks/erc20_panic.cairo b/src/openzeppelin/tests/mocks/erc20_panic.cairo index 89389bc74..c2a4fa9d2 100644 --- a/src/openzeppelin/tests/mocks/erc20_panic.cairo +++ b/src/openzeppelin/tests/mocks/erc20_panic.cairo @@ -1,96 +1,97 @@ // Although these modules are designed to panic, functions // still need a valid return value. We chose: // -// 3 for felt252 and u8 +// 3 for felt252, u8, and u256 // zero for ContractAddress // false for bool -// u256 { 3, 3 } for u256 -#[contract] +#[starknet::contract] mod SnakeERC20Panic { use starknet::ContractAddress; - /// - /// Agnostic - /// + #[storage] + struct Storage {} - #[view] - fn name() -> felt252 { + #[external(v0)] + fn name(self: @ContractState) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn symbol() -> felt252 { + #[external(v0)] + fn symbol(self: @ContractState) -> felt252 { panic_with_felt252('Some error'); 3 } - #[view] - fn decimals() -> u8 { + #[external(v0)] + fn decimals(self: @ContractState) -> u8 { panic_with_felt252('Some error'); - 3_u8 + 3 } - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { + #[external(v0)] + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 { panic_with_felt252('Some error'); - u256 { low: 3, high: 3 } + 3 } - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { + #[external(v0)] + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { panic_with_felt252('Some error'); false } - #[external] - fn approve(to: ContractAddress, token_id: u256) -> bool { + #[external(v0)] + fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) -> bool { panic_with_felt252('Some error'); false } - /// - /// Snake - /// - - #[view] - fn total_supply() -> u256 { + #[external(v0)] + fn total_supply(self: @ContractState) -> u256 { panic_with_felt252('Some error'); - u256 { low: 3, high: 3 } + 3 } - #[view] - fn balance_of(account: ContractAddress) -> u256 { + #[external(v0)] + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { panic_with_felt252('Some error'); - u256 { low: 3, high: 3 } + 3 } - #[external] - fn transfer_from(from: ContractAddress, to: ContractAddress, amount: u256) -> bool { + #[external(v0)] + fn transfer_from( + ref self: ContractState, from: ContractAddress, to: ContractAddress, amount: u256 + ) -> bool { panic_with_felt252('Some error'); false } } -#[contract] +#[starknet::contract] mod CamelERC20Panic { use starknet::ContractAddress; - #[view] - fn totalSupply() -> u256 { + #[storage] + struct Storage {} + + #[external(v0)] + fn totalSupply(self: @ContractState) -> u256 { panic_with_felt252('Some error'); - u256 { low: 3, high: 3 } + 3 } - #[view] - fn balanceOf(account: ContractAddress) -> u256 { + #[external(v0)] + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { panic_with_felt252('Some error'); - u256 { low: 3, high: 3 } + 3 } - #[external] - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) { + #[external(v0)] + fn transferFrom( + ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) { panic_with_felt252('Some error'); } } diff --git a/src/openzeppelin/tests/mocks/mock_pausable.cairo b/src/openzeppelin/tests/mocks/mock_pausable.cairo deleted file mode 100644 index 799449b4a..000000000 --- a/src/openzeppelin/tests/mocks/mock_pausable.cairo +++ /dev/null @@ -1,34 +0,0 @@ -#[contract] -mod MockPausable { - use openzeppelin::security::pausable::Pausable; - - struct Storage { - counter: felt252 - } - - #[view] - fn is_paused() -> bool { - Pausable::is_paused() - } - - #[view] - fn get_count() -> felt252 { - counter::read() - } - - #[external] - fn assert_unpaused_and_increment() { - Pausable::assert_not_paused(); - counter::write(counter::read() + 1); - } - - #[external] - fn pause() { - Pausable::pause(); - } - - #[external] - fn unpause() { - Pausable::unpause(); - } -} diff --git a/src/openzeppelin/tests/mocks/snake20_mock.cairo b/src/openzeppelin/tests/mocks/snake20_mock.cairo index dd5a034f7..ba20d54b1 100644 --- a/src/openzeppelin/tests/mocks/snake20_mock.cairo +++ b/src/openzeppelin/tests/mocks/snake20_mock.cairo @@ -1,58 +1,77 @@ -#[contract] +#[starknet::contract] mod SnakeERC20Mock { use starknet::ContractAddress; use openzeppelin::token::erc20::ERC20; + #[storage] + struct Storage {} + #[constructor] fn constructor( - name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress + ref self: ContractState, + name: felt252, + symbol: felt252, + initial_supply: u256, + recipient: ContractAddress ) { - ERC20::initializer(name, symbol); - ERC20::_mint(recipient, initial_supply); + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::InternalImpl::initializer(ref unsafe_state, name, symbol); + ERC20::InternalImpl::_mint(ref unsafe_state, recipient, initial_supply); } - #[view] - fn name() -> felt252 { - ERC20::name() + #[external(v0)] + fn name(self: @ContractState) -> felt252 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::name(@unsafe_state) } - #[view] - fn symbol() -> felt252 { - ERC20::symbol() + #[external(v0)] + fn symbol(self: @ContractState) -> felt252 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::symbol(@unsafe_state) } - #[view] - fn decimals() -> u8 { - ERC20::decimals() + #[external(v0)] + fn decimals(self: @ContractState) -> u8 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::decimals(@unsafe_state) } - #[view] - fn total_supply() -> u256 { - ERC20::total_supply() + #[external(v0)] + fn total_supply(self: @ContractState) -> u256 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::total_supply(@unsafe_state) } - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC20::balance_of(account) + #[external(v0)] + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::balance_of(@unsafe_state, account) } - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20::allowance(owner, spender) + #[external(v0)] + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::allowance(@unsafe_state, owner, spender) } - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20::transfer(recipient, amount) + #[external(v0)] + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::transfer(ref unsafe_state, recipient, amount) } - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20::transfer_from(sender, recipient, amount) + #[external(v0)] + fn transfer_from( + ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool { + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::transfer_from(ref unsafe_state, sender, recipient, amount) } - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20::approve(spender, amount) + #[external(v0)] + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool { + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::approve(ref unsafe_state, spender, amount) } } diff --git a/src/openzeppelin/tests/token.cairo b/src/openzeppelin/tests/token.cairo index ffee08cb1..fa678fb9c 100644 --- a/src/openzeppelin/tests/token.cairo +++ b/src/openzeppelin/tests/token.cairo @@ -1,5 +1,6 @@ -// mod test_dual20; +mod test_dual20; mod test_dual721; -// mod test_erc20; +mod test_erc20; mod test_erc721; mod test_dual721_receiver; + diff --git a/src/openzeppelin/tests/token/test_dual20.cairo b/src/openzeppelin/tests/token/test_dual20.cairo index 52d0f0906..d8b56c5fa 100644 --- a/src/openzeppelin/tests/token/test_dual20.cairo +++ b/src/openzeppelin/tests/token/test_dual20.cairo @@ -45,7 +45,7 @@ fn OPERATOR() -> ContractAddress { // fn setup_snake() -> (DualERC20, IERC20Dispatcher) { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; calldata.append_serde(NAME); calldata.append_serde(SYMBOL); calldata.append_serde(SUPPLY); @@ -55,7 +55,7 @@ fn setup_snake() -> (DualERC20, IERC20Dispatcher) { } fn setup_camel() -> (DualERC20, IERC20CamelDispatcher) { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; calldata.append_serde(NAME); calldata.append_serde(SYMBOL); calldata.append_serde(SUPPLY); @@ -65,14 +65,14 @@ fn setup_camel() -> (DualERC20, IERC20CamelDispatcher) { } fn setup_non_erc20() -> DualERC20 { - let calldata = ArrayTrait::new(); + let calldata = array![]; let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); DualERC20 { contract_address: target } } fn setup_erc20_panic() -> (DualERC20, DualERC20) { - let snake_target = utils::deploy(SnakeERC20Panic::TEST_CLASS_HASH, ArrayTrait::new()); - let camel_target = utils::deploy(CamelERC20Panic::TEST_CLASS_HASH, ArrayTrait::new()); + let snake_target = utils::deploy(SnakeERC20Panic::TEST_CLASS_HASH, array![]); + let camel_target = utils::deploy(CamelERC20Panic::TEST_CLASS_HASH, array![]); (DualERC20 { contract_address: snake_target }, DualERC20 { contract_address: camel_target }) } diff --git a/src/openzeppelin/tests/token/test_erc20.cairo b/src/openzeppelin/tests/token/test_erc20.cairo index 775c974fa..55945c0e2 100644 --- a/src/openzeppelin/tests/token/test_erc20.cairo +++ b/src/openzeppelin/tests/token/test_erc20.cairo @@ -1,4 +1,3 @@ -use openzeppelin::token::erc20::ERC20; use integer::BoundedInt; use integer::u256; use integer::u256_from_felt252; @@ -8,6 +7,11 @@ use starknet::testing::set_caller_address; use traits::Into; use zeroable::Zeroable; +use openzeppelin::token::erc20::ERC20; +use openzeppelin::token::erc20::ERC20::ERC20CamelOnlyImpl; +use openzeppelin::token::erc20::ERC20::ERC20Impl; +use openzeppelin::token::erc20::ERC20::InternalImpl; + // // Constants // @@ -18,14 +22,15 @@ const DECIMALS: u8 = 18_u8; const SUPPLY: u256 = 2000; const VALUE: u256 = 300; +fn STATE() -> ERC20::ContractState { + ERC20::contract_state_for_testing() +} fn OWNER() -> ContractAddress { contract_address_const::<1>() } - fn SPENDER() -> ContractAddress { contract_address_const::<2>() } - fn RECIPIENT() -> ContractAddress { contract_address_const::<3>() } @@ -34,8 +39,10 @@ fn RECIPIENT() -> ContractAddress { // Setup // -fn setup() { - ERC20::constructor(NAME, SYMBOL, SUPPLY, OWNER()); +fn setup() -> ERC20::ContractState { + let mut state = STATE(); + ERC20::constructor(ref state, NAME, SYMBOL, SUPPLY, OWNER()); + state } // @@ -45,25 +52,27 @@ fn setup() { #[test] #[available_gas(2000000)] fn test_initializer() { - ERC20::initializer(NAME, SYMBOL); + let mut state = STATE(); + InternalImpl::initializer(ref state, NAME, SYMBOL); - assert(ERC20::name() == NAME, 'Name should be NAME'); - assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20::decimals() == DECIMALS, 'Decimals should be 18'); - assert(ERC20::total_supply() == 0, 'Supply should eq 0'); + assert(ERC20Impl::name(@state) == NAME, 'Name should be NAME'); + assert(ERC20Impl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20Impl::decimals(@state) == DECIMALS, 'Decimals should be 18'); + assert(ERC20Impl::total_supply(@state) == 0, 'Supply should eq 0'); } #[test] #[available_gas(2000000)] fn test_constructor() { - ERC20::constructor(NAME, SYMBOL, SUPPLY, OWNER()); + let mut state = STATE(); + ERC20::constructor(ref state, NAME, SYMBOL, SUPPLY, OWNER()); - assert(ERC20::balance_of(OWNER()) == SUPPLY, 'Should eq inital_supply'); - assert(ERC20::total_supply() == SUPPLY, 'Should eq inital_supply'); - assert(ERC20::name() == NAME, 'Name should be NAME'); - assert(ERC20::symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20::decimals() == DECIMALS, 'Decimals should be 18'); + assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY, 'Should eq inital_supply'); + assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Should eq inital_supply'); + assert(ERC20Impl::name(@state) == NAME, 'Name should be NAME'); + assert(ERC20Impl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20Impl::decimals(@state) == DECIMALS, 'Decimals should be 18'); } // @@ -73,39 +82,43 @@ fn test_constructor() { #[test] #[available_gas(2000000)] fn test_total_supply() { - ERC20::_mint(OWNER(), SUPPLY); - assert(ERC20::total_supply() == SUPPLY, 'Should eq SUPPLY'); + let mut state = STATE(); + InternalImpl::_mint(ref state, OWNER(), SUPPLY); + assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Should eq SUPPLY'); } #[test] #[available_gas(2000000)] fn test_totalSupply() { - ERC20::_mint(OWNER(), SUPPLY); - assert(ERC20::totalSupply() == SUPPLY, 'Should eq SUPPLY'); + let mut state = STATE(); + InternalImpl::_mint(ref state, OWNER(), SUPPLY); + assert(ERC20CamelOnlyImpl::totalSupply(@state) == SUPPLY, 'Should eq SUPPLY'); } #[test] #[available_gas(2000000)] fn test_balance_of() { - ERC20::_mint(OWNER(), SUPPLY); - assert(ERC20::balance_of(OWNER()) == SUPPLY, 'Should eq SUPPLY'); + let mut state = STATE(); + InternalImpl::_mint(ref state, OWNER(), SUPPLY); + assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY, 'Should eq SUPPLY'); } #[test] #[available_gas(2000000)] fn test_balanceOf() { - ERC20::_mint(OWNER(), SUPPLY); - assert(ERC20::balanceOf(OWNER()) == SUPPLY, 'Should eq SUPPLY'); + let mut state = STATE(); + InternalImpl::_mint(ref state, OWNER(), SUPPLY); + assert(ERC20CamelOnlyImpl::balanceOf(@state, OWNER()) == SUPPLY, 'Should eq SUPPLY'); } #[test] #[available_gas(2000000)] fn test_allowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); - assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE, 'Should eq VALUE'); + assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE, 'Should eq VALUE'); } // @@ -115,55 +128,58 @@ fn test_allowance() { #[test] #[available_gas(2000000)] fn test_approve() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - assert(ERC20::approve(SPENDER(), VALUE), 'Should return true'); - - assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly'); + assert(ERC20Impl::approve(ref state, SPENDER(), VALUE), 'Should return true'); + assert( + ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly' + ); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0', ))] fn test_approve_from_zero() { - setup(); - ERC20::approve(SPENDER(), VALUE); + let mut state = setup(); + ERC20Impl::approve(ref state, SPENDER(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0', ))] fn test_approve_to_zero() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(Zeroable::zero(), VALUE); + ERC20Impl::approve(ref state, Zeroable::zero(), VALUE); } #[test] #[available_gas(2000000)] fn test__approve() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::_approve(OWNER(), SPENDER(), VALUE); + InternalImpl::_approve(ref state, OWNER(), SPENDER(), VALUE); - assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly'); + assert( + ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly' + ); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0', ))] fn test__approve_from_zero() { - setup(); - ERC20::_approve(Zeroable::zero(), SPENDER(), VALUE); + let mut state = setup(); + InternalImpl::_approve(ref state, Zeroable::zero(), SPENDER(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0', ))] fn test__approve_to_zero() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::_approve(OWNER(), Zeroable::zero(), VALUE); + InternalImpl::_approve(ref state, OWNER(), Zeroable::zero(), VALUE); } // @@ -173,51 +189,51 @@ fn test__approve_to_zero() { #[test] #[available_gas(2000000)] fn test_transfer() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - assert(ERC20::transfer(RECIPIENT(), VALUE), 'Should return true'); + assert(ERC20Impl::transfer(ref state, RECIPIENT(), VALUE), 'Should return true'); - assert(ERC20::balance_of(RECIPIENT()) == VALUE, 'Balance should eq VALUE'); - assert(ERC20::balance_of(OWNER()) == SUPPLY - VALUE, 'Should eq supply - VALUE'); - assert(ERC20::total_supply() == SUPPLY, 'Total supply should not change'); + assert(ERC20Impl::balance_of(@state, RECIPIENT()) == VALUE, 'Balance should eq VALUE'); + assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY - VALUE, 'Should eq supply - VALUE'); + assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Total supply should not change'); } #[test] #[available_gas(2000000)] fn test__transfer() { - setup(); + let mut state = setup(); - ERC20::_transfer(OWNER(), RECIPIENT(), VALUE); - assert(ERC20::balance_of(RECIPIENT()) == VALUE, 'Balance should eq amount'); - assert(ERC20::balance_of(OWNER()) == SUPPLY - VALUE, 'Should eq supply - amount'); - assert(ERC20::total_supply() == SUPPLY, 'Total supply should not change'); + InternalImpl::_transfer(ref state, OWNER(), RECIPIENT(), VALUE); + assert(ERC20Impl::balance_of(@state, RECIPIENT()) == VALUE, 'Balance should eq amount'); + assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY - VALUE, 'Should eq supply - amount'); + assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Total supply should not change'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test__transfer_not_enough_balance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); let balance_plus_one = SUPPLY + 1; - ERC20::_transfer(OWNER(), RECIPIENT(), balance_plus_one); + InternalImpl::_transfer(ref state, OWNER(), RECIPIENT(), balance_plus_one); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer from 0', ))] fn test__transfer_from_zero() { - setup(); - ERC20::_transfer(Zeroable::zero(), RECIPIENT(), VALUE); + let mut state = setup(); + InternalImpl::_transfer(ref state, Zeroable::zero(), RECIPIENT(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0', ))] fn test__transfer_to_zero() { - setup(); - ERC20::_transfer(OWNER(), Zeroable::zero(), VALUE); + let mut state = setup(); + InternalImpl::_transfer(ref state, OWNER(), Zeroable::zero(), VALUE); } // @@ -227,31 +243,32 @@ fn test__transfer_to_zero() { #[test] #[available_gas(2000000)] fn test_transfer_from() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); set_caller_address(SPENDER()); - assert(ERC20::transfer_from(OWNER(), RECIPIENT(), VALUE), 'Should return true'); + assert(ERC20Impl::transfer_from(ref state, OWNER(), RECIPIENT(), VALUE), 'Should return true'); - assert(ERC20::balance_of(RECIPIENT()) == VALUE, 'Should eq amount'); - assert(ERC20::balance_of(OWNER()) == SUPPLY - VALUE, 'Should eq suppy - amount'); - assert(ERC20::allowance(OWNER(), SPENDER()) == 0, 'Should eq 0'); - assert(ERC20::total_supply() == SUPPLY, 'Total supply should not change'); + assert(ERC20Impl::balance_of(@state, RECIPIENT()) == VALUE, 'Should eq amount'); + assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY - VALUE, 'Should eq suppy - amount'); + assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == 0, 'Should eq 0'); + assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Total supply should not change'); } #[test] #[available_gas(2000000)] fn test_transfer_from_doesnt_consume_infinite_allowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), BoundedInt::max()); + ERC20Impl::approve(ref state, SPENDER(), BoundedInt::max()); set_caller_address(SPENDER()); - ERC20::transfer_from(OWNER(), RECIPIENT(), VALUE); + ERC20Impl::transfer_from(ref state, OWNER(), RECIPIENT(), VALUE); assert( - ERC20::allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change' + ERC20Impl::allowance(@state, OWNER(), SPENDER()) == BoundedInt::max(), + 'Allowance should not change' ); } @@ -259,63 +276,69 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test_transfer_from_greater_than_allowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); set_caller_address(SPENDER()); let allowance_plus_one = VALUE + 1; - ERC20::transfer_from(OWNER(), RECIPIENT(), allowance_plus_one); + ERC20Impl::transfer_from(ref state, OWNER(), RECIPIENT(), allowance_plus_one); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0', ))] fn test_transfer_from_to_zero_address() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); set_caller_address(SPENDER()); - ERC20::transfer_from(OWNER(), Zeroable::zero(), VALUE); + ERC20Impl::transfer_from(ref state, OWNER(), Zeroable::zero(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test_transfer_from_from_zero_address() { - setup(); - ERC20::transfer_from(Zeroable::zero(), RECIPIENT(), VALUE); + let mut state = setup(); + ERC20Impl::transfer_from(ref state, Zeroable::zero(), RECIPIENT(), VALUE); } #[test] #[available_gas(2000000)] fn test_transferFrom() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); set_caller_address(SPENDER()); - assert(ERC20::transferFrom(OWNER(), RECIPIENT(), VALUE), 'Should return true'); - assert(ERC20::balanceOf(RECIPIENT()) == VALUE, 'Should eq amount'); - assert(ERC20::balanceOf(OWNER()) == SUPPLY - VALUE, 'Should eq suppy - amount'); - assert(ERC20::allowance(OWNER(), SPENDER()) == 0, 'Should eq 0'); - assert(ERC20::totalSupply() == SUPPLY, 'Total supply should not change'); + assert( + ERC20CamelOnlyImpl::transferFrom(ref state, OWNER(), RECIPIENT(), VALUE), + 'Should return true' + ); + assert(ERC20CamelOnlyImpl::balanceOf(@state, RECIPIENT()) == VALUE, 'Should eq amount'); + assert( + ERC20CamelOnlyImpl::balanceOf(@state, OWNER()) == SUPPLY - VALUE, 'Should eq suppy - amount' + ); + assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == 0, 'Should eq 0'); + assert(ERC20CamelOnlyImpl::totalSupply(@state) == SUPPLY, 'Total supply should not change'); } #[test] #[available_gas(2000000)] fn test_transferFrom_doesnt_consume_infinite_allowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), BoundedInt::max()); + ERC20Impl::approve(ref state, SPENDER(), BoundedInt::max()); set_caller_address(SPENDER()); - ERC20::transferFrom(OWNER(), RECIPIENT(), VALUE); + ERC20CamelOnlyImpl::transferFrom(ref state, OWNER(), RECIPIENT(), VALUE); assert( - ERC20::allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change' + ERC20Impl::allowance(@state, OWNER(), SPENDER()) == BoundedInt::max(), + 'Allowance should not change' ); } @@ -323,33 +346,33 @@ fn test_transferFrom_doesnt_consume_infinite_allowance() { #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test_transferFrom_greater_than_allowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); set_caller_address(SPENDER()); let allowance_plus_one = VALUE + 1; - ERC20::transferFrom(OWNER(), RECIPIENT(), allowance_plus_one); + ERC20CamelOnlyImpl::transferFrom(ref state, OWNER(), RECIPIENT(), allowance_plus_one); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0', ))] fn test_transferFrom_to_zero_address() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); set_caller_address(SPENDER()); - ERC20::transferFrom(OWNER(), Zeroable::zero(), VALUE); + ERC20CamelOnlyImpl::transferFrom(ref state, OWNER(), Zeroable::zero(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test_transferFrom_from_zero_address() { - setup(); - ERC20::transferFrom(Zeroable::zero(), RECIPIENT(), VALUE); + let mut state = setup(); + ERC20CamelOnlyImpl::transferFrom(ref state, Zeroable::zero(), RECIPIENT(), VALUE); } // @@ -359,57 +382,57 @@ fn test_transferFrom_from_zero_address() { #[test] #[available_gas(2000000)] fn test_increase_allowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); - assert(ERC20::increase_allowance(SPENDER(), VALUE), 'Should return true'); - assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); + assert(ERC20::increase_allowance(ref state, SPENDER(), VALUE), 'Should return true'); + assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0', ))] fn test_increase_allowance_to_zero_address() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::increase_allowance(Zeroable::zero(), VALUE); + ERC20::increase_allowance(ref state, Zeroable::zero(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0', ))] fn test_increase_allowance_from_zero_address() { - setup(); - ERC20::increase_allowance(SPENDER(), VALUE); + let mut state = setup(); + ERC20::increase_allowance(ref state, SPENDER(), VALUE); } #[test] #[available_gas(2000000)] fn test_increaseAllowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); - assert(ERC20::increaseAllowance(SPENDER(), VALUE), 'Should return true'); - assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); + assert(ERC20::increaseAllowance(ref state, SPENDER(), VALUE), 'Should return true'); + assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0', ))] fn test_increaseAllowance_to_zero_address() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::increaseAllowance(Zeroable::zero(), VALUE); + ERC20::increaseAllowance(ref state, Zeroable::zero(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0', ))] fn test_increaseAllowance_from_zero_address() { - setup(); - ERC20::increaseAllowance(SPENDER(), VALUE); + let mut state = setup(); + ERC20::increaseAllowance(ref state, SPENDER(), VALUE); } // @@ -419,57 +442,57 @@ fn test_increaseAllowance_from_zero_address() { #[test] #[available_gas(2000000)] fn test_decrease_allowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); - assert(ERC20::decrease_allowance(SPENDER(), VALUE), 'Should return true'); - assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); + assert(ERC20::decrease_allowance(ref state, SPENDER(), VALUE), 'Should return true'); + assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test_decrease_allowance_to_zero_address() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::decrease_allowance(Zeroable::zero(), VALUE); + ERC20::decrease_allowance(ref state, Zeroable::zero(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test_decrease_allowance_from_zero_address() { - setup(); - ERC20::decrease_allowance(SPENDER(), VALUE); + let mut state = setup(); + ERC20::decrease_allowance(ref state, SPENDER(), VALUE); } #[test] #[available_gas(2000000)] fn test_decreaseAllowance() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::approve(SPENDER(), VALUE); + ERC20Impl::approve(ref state, SPENDER(), VALUE); - assert(ERC20::decreaseAllowance(SPENDER(), VALUE), 'Should return true'); - assert(ERC20::allowance(OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); + assert(ERC20::decreaseAllowance(ref state, SPENDER(), VALUE), 'Should return true'); + assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test_decreaseAllowance_to_zero_address() { - setup(); + let mut state = setup(); set_caller_address(OWNER()); - ERC20::decreaseAllowance(Zeroable::zero(), VALUE); + ERC20::decreaseAllowance(ref state, Zeroable::zero(), VALUE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', ))] fn test_decreaseAllowance_from_zero_address() { - setup(); - ERC20::decreaseAllowance(SPENDER(), VALUE); + let mut state = setup(); + ERC20::decreaseAllowance(ref state, SPENDER(), VALUE); } // @@ -479,24 +502,28 @@ fn test_decreaseAllowance_from_zero_address() { #[test] #[available_gas(2000000)] fn test__spend_allowance_not_unlimited() { - setup(); + let mut state = setup(); - ERC20::_approve(OWNER(), SPENDER(), SUPPLY); - ERC20::_spend_allowance(OWNER(), SPENDER(), VALUE); - assert(ERC20::allowance(OWNER(), SPENDER()) == SUPPLY - VALUE, 'Should eq supply - amount'); + InternalImpl::_approve(ref state, OWNER(), SPENDER(), SUPPLY); + InternalImpl::_spend_allowance(ref state, OWNER(), SPENDER(), VALUE); + assert( + ERC20Impl::allowance(@state, OWNER(), SPENDER()) == SUPPLY - VALUE, + 'Should eq supply - amount' + ); } #[test] #[available_gas(2000000)] fn test__spend_allowance_unlimited() { - setup(); - ERC20::_approve(OWNER(), SPENDER(), BoundedInt::max()); + let mut state = setup(); + InternalImpl::_approve(ref state, OWNER(), SPENDER(), BoundedInt::max()); let max_minus_one: u256 = BoundedInt::max() - 1; - ERC20::_spend_allowance(OWNER(), SPENDER(), max_minus_one); + InternalImpl::_spend_allowance(ref state, OWNER(), SPENDER(), max_minus_one); assert( - ERC20::allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change' + ERC20Impl::allowance(@state, OWNER(), SPENDER()) == BoundedInt::max(), + 'Allowance should not change' ); } @@ -507,17 +534,19 @@ fn test__spend_allowance_unlimited() { #[test] #[available_gas(2000000)] fn test__mint() { - ERC20::_mint(OWNER(), VALUE); + let mut state = STATE(); + InternalImpl::_mint(ref state, OWNER(), VALUE); - assert(ERC20::balance_of(OWNER()) == VALUE, 'Should eq amount'); - assert(ERC20::total_supply() == VALUE, 'Should eq total supply'); + assert(ERC20Impl::balance_of(@state, OWNER()) == VALUE, 'Should eq amount'); + assert(ERC20Impl::total_supply(@state) == VALUE, 'Should eq total supply'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: mint to 0', ))] fn test__mint_to_zero() { - ERC20::_mint(Zeroable::zero(), VALUE); + let mut state = STATE(); + InternalImpl::_mint(ref state, Zeroable::zero(), VALUE); } // @@ -527,17 +556,17 @@ fn test__mint_to_zero() { #[test] #[available_gas(2000000)] fn test__burn() { - setup(); - ERC20::_burn(OWNER(), VALUE); + let mut state = setup(); + InternalImpl::_burn(ref state, OWNER(), VALUE); - assert(ERC20::total_supply() == SUPPLY - VALUE, 'Should eq supply - amount'); - assert(ERC20::balance_of(OWNER()) == SUPPLY - VALUE, 'Should eq supply - amount'); + assert(ERC20Impl::total_supply(@state) == SUPPLY - VALUE, 'Should eq supply - amount'); + assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY - VALUE, 'Should eq supply - amount'); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('ERC20: burn from 0', ))] fn test__burn_from_zero() { - setup(); - ERC20::_burn(Zeroable::zero(), VALUE); + let mut state = setup(); + InternalImpl::_burn(ref state, Zeroable::zero(), VALUE); } diff --git a/src/openzeppelin/token.cairo b/src/openzeppelin/token.cairo index 51f2f6d68..f9a848d01 100644 --- a/src/openzeppelin/token.cairo +++ b/src/openzeppelin/token.cairo @@ -1,2 +1,2 @@ -// mod erc20; +mod erc20; mod erc721; diff --git a/src/openzeppelin/token/erc20.cairo b/src/openzeppelin/token/erc20.cairo index bd33b3953..6784045a0 100644 --- a/src/openzeppelin/token/erc20.cairo +++ b/src/openzeppelin/token/erc20.cairo @@ -1,7 +1,7 @@ mod erc20; -mod interface; mod dual20; +mod interface; use erc20::ERC20; -use erc20::ERC20ABIDispatcher; -use erc20::ERC20ABIDispatcherTrait; +use interface::ERC20ABIDispatcher; +use interface::ERC20ABIDispatcherTrait; diff --git a/src/openzeppelin/token/erc20/dual20.cairo b/src/openzeppelin/token/erc20/dual20.cairo index 99a5045a4..848f53363 100644 --- a/src/openzeppelin/token/erc20/dual20.cairo +++ b/src/openzeppelin/token/erc20/dual20.cairo @@ -29,29 +29,25 @@ trait DualERC20Trait { impl DualERC20Impl of DualERC20Trait { fn name(self: @DualERC20) -> felt252 { - let args = ArrayTrait::new(); - + let args = array![]; call_contract_syscall(*self.contract_address, selectors::name, args.span()) .unwrap_and_cast() } fn symbol(self: @DualERC20) -> felt252 { - let args = ArrayTrait::new(); - + let args = array![]; call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) .unwrap_and_cast() } fn decimals(self: @DualERC20) -> u8 { - let args = ArrayTrait::new(); - + let args = array![]; call_contract_syscall(*self.contract_address, selectors::decimals, args.span()) .unwrap_and_cast() } fn total_supply(self: @DualERC20) -> u256 { - let mut args = ArrayTrait::new(); - + let mut args = array![]; try_selector_with_fallback( *self.contract_address, selectors::total_supply, selectors::totalSupply, args.span() ) @@ -59,7 +55,7 @@ impl DualERC20Impl of DualERC20Trait { } fn balance_of(self: @DualERC20, account: ContractAddress) -> u256 { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(account); try_selector_with_fallback( @@ -69,7 +65,7 @@ impl DualERC20Impl of DualERC20Trait { } fn allowance(self: @DualERC20, owner: ContractAddress, spender: ContractAddress) -> u256 { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(owner); args.append_serde(spender); @@ -78,7 +74,7 @@ impl DualERC20Impl of DualERC20Trait { } fn transfer(self: @DualERC20, recipient: ContractAddress, amount: u256) -> bool { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(recipient); args.append_serde(amount); @@ -89,7 +85,7 @@ impl DualERC20Impl of DualERC20Trait { fn transfer_from( self: @DualERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256 ) -> bool { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(sender); args.append_serde(recipient); args.append_serde(amount); @@ -101,7 +97,7 @@ impl DualERC20Impl of DualERC20Trait { } fn approve(self: @DualERC20, spender: ContractAddress, amount: u256) -> bool { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(spender); args.append_serde(amount); diff --git a/src/openzeppelin/token/erc20/erc20.cairo b/src/openzeppelin/token/erc20/erc20.cairo index f778a0d47..f83a965a8 100644 --- a/src/openzeppelin/token/erc20/erc20.cairo +++ b/src/openzeppelin/token/erc20/erc20.cairo @@ -1,65 +1,14 @@ -use starknet::ContractAddress; - -#[abi] -trait ERC20ABI { - #[view] - fn name() -> felt252; - #[view] - fn symbol() -> felt252; - #[view] - fn decimals() -> u8; - #[view] - fn total_supply() -> u256; - #[view] - fn balance_of(account: ContractAddress) -> u256; - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; - #[external] - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool; - #[external] - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool; -} - -#[abi] -trait ERC20CamelABI { - #[view] - fn name() -> felt252; - #[view] - fn symbol() -> felt252; - #[view] - fn decimals() -> u8; - #[view] - fn totalSupply() -> u256; - #[view] - fn balanceOf(account: ContractAddress) -> u256; - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; - #[external] - fn increaseAllowance(spender: ContractAddress, addedValue: u256) -> bool; - #[external] - fn decreaseAllowance(spender: ContractAddress, subtractedValue: u256) -> bool; -} - -#[contract] +#[starknet::contract] mod ERC20 { - use openzeppelin::token::erc20::interface::{IERC20, IERC20Camel}; use integer::BoundedInt; use starknet::ContractAddress; use starknet::get_caller_address; use zeroable::Zeroable; + use openzeppelin::token::erc20::interface::IERC20; + use openzeppelin::token::erc20::interface::IERC20CamelOnly; + + #[storage] struct Storage { _name: felt252, _symbol: felt252, @@ -69,246 +18,216 @@ mod ERC20 { } #[event] - fn Transfer(from: ContractAddress, to: ContractAddress, value: u256) {} + #[derive(Drop, starknet::Event)] + enum Event { + Transfer: Transfer, + Approval: Approval, + } - #[event] - fn Approval(owner: ContractAddress, spender: ContractAddress, value: u256) {} + #[derive(Drop, starknet::Event)] + struct Transfer { + from: ContractAddress, + to: ContractAddress, + value: u256 + } + + #[derive(Drop, starknet::Event)] + struct Approval { + owner: ContractAddress, + spender: ContractAddress, + value: u256 + } - impl ERC20Impl of IERC20 { - fn name() -> felt252 { - _name::read() + #[constructor] + fn constructor( + ref self: ContractState, + name: felt252, + symbol: felt252, + initial_supply: u256, + recipient: ContractAddress + ) { + self.initializer(name, symbol); + self._mint(recipient, initial_supply); + } + + // + // External + // + + #[external(v0)] + impl ERC20Impl of IERC20 { + fn name(self: @ContractState) -> felt252 { + self._name.read() } - fn symbol() -> felt252 { - _symbol::read() + fn symbol(self: @ContractState) -> felt252 { + self._symbol.read() } - fn decimals() -> u8 { - 18_u8 + fn decimals(self: @ContractState) -> u8 { + 18 } - fn total_supply() -> u256 { - _total_supply::read() + fn total_supply(self: @ContractState) -> u256 { + self._total_supply.read() } - fn balance_of(account: ContractAddress) -> u256 { - _balances::read(account) + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { + self._balances.read(account) } - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - _allowances::read((owner, spender)) + fn allowance( + self: @ContractState, owner: ContractAddress, spender: ContractAddress + ) -> u256 { + self._allowances.read((owner, spender)) } - fn transfer(recipient: ContractAddress, amount: u256) -> bool { + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { let sender = get_caller_address(); - _transfer(sender, recipient, amount); + self._transfer(sender, recipient, amount); true } fn transfer_from( - sender: ContractAddress, recipient: ContractAddress, amount: u256 + ref self: ContractState, + sender: ContractAddress, + recipient: ContractAddress, + amount: u256 ) -> bool { let caller = get_caller_address(); - _spend_allowance(sender, caller, amount); - _transfer(sender, recipient, amount); + self._spend_allowance(sender, caller, amount); + self._transfer(sender, recipient, amount); true } - fn approve(spender: ContractAddress, amount: u256) -> bool { + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool { let caller = get_caller_address(); - _approve(caller, spender, amount); + self._approve(caller, spender, amount); true } } - impl ERC20CamelImpl of IERC20Camel { - fn name() -> felt252 { - ERC20Impl::name() - } - - fn symbol() -> felt252 { - ERC20Impl::symbol() + #[external(v0)] + impl ERC20CamelOnlyImpl of IERC20CamelOnly { + fn totalSupply(self: @ContractState) -> u256 { + ERC20Impl::total_supply(self) } - fn decimals() -> u8 { - ERC20Impl::decimals() + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { + ERC20Impl::balance_of(self, account) } - fn totalSupply() -> u256 { - ERC20Impl::total_supply() - } - - fn balanceOf(account: ContractAddress) -> u256 { - ERC20Impl::balance_of(account) - } - - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20Impl::allowance(owner, spender) - } - - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20Impl::transfer(recipient, amount) - } - - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20Impl::transfer_from(sender, recipient, amount) - } - - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20Impl::approve(spender, amount) + fn transferFrom( + ref self: ContractState, + sender: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) -> bool { + ERC20Impl::transfer_from(ref self, sender, recipient, amount) } } - #[constructor] - fn constructor( - name: felt252, symbol: felt252, initial_supply: u256, recipient: ContractAddress - ) { - initializer(name, symbol); - _mint(recipient, initial_supply); - } - - #[view] - fn name() -> felt252 { - ERC20Impl::name() - } - - #[view] - fn symbol() -> felt252 { - ERC20Impl::symbol() - } - - #[view] - fn decimals() -> u8 { - ERC20Impl::decimals() + #[external(v0)] + fn increase_allowance( + ref self: ContractState, spender: ContractAddress, added_value: u256 + ) -> bool { + self._increase_allowance(spender, added_value) } - #[view] - fn total_supply() -> u256 { - ERC20Impl::total_supply() + #[external(v0)] + fn increaseAllowance( + ref self: ContractState, spender: ContractAddress, addedValue: u256 + ) -> bool { + increase_allowance(ref self, spender, addedValue) } - #[view] - fn totalSupply() -> u256 { - ERC20CamelImpl::totalSupply() + #[external(v0)] + fn decrease_allowance( + ref self: ContractState, spender: ContractAddress, subtracted_value: u256 + ) -> bool { + self._decrease_allowance(spender, subtracted_value) } - #[view] - fn balance_of(account: ContractAddress) -> u256 { - ERC20Impl::balance_of(account) - } - - #[view] - fn balanceOf(account: ContractAddress) -> u256 { - ERC20CamelImpl::balanceOf(account) - } - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256 { - ERC20Impl::allowance(owner, spender) - } - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool { - ERC20Impl::transfer(recipient, amount) - } - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20Impl::transfer_from(sender, recipient, amount) - } - - #[external] - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { - ERC20CamelImpl::transferFrom(sender, recipient, amount) - } - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool { - ERC20Impl::approve(spender, amount) - } - - #[external] - fn increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - _increase_allowance(spender, added_value) - } - - #[external] - fn increaseAllowance(spender: ContractAddress, addedValue: u256) -> bool { - increase_allowance(spender, addedValue) - } - - #[external] - fn decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - _decrease_allowance(spender, subtracted_value) - } - - #[external] - fn decreaseAllowance(spender: ContractAddress, subtractedValue: u256) -> bool { - decrease_allowance(spender, subtractedValue) + #[external(v0)] + fn decreaseAllowance( + ref self: ContractState, spender: ContractAddress, subtractedValue: u256 + ) -> bool { + decrease_allowance(ref self, spender, subtractedValue) } // - // Internals + // Internal // - #[internal] - fn initializer(name_: felt252, symbol_: felt252) { - _name::write(name_); - _symbol::write(symbol_); - } - - #[internal] - fn _increase_allowance(spender: ContractAddress, added_value: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, _allowances::read((caller, spender)) + added_value); - true - } - - #[internal] - fn _decrease_allowance(spender: ContractAddress, subtracted_value: u256) -> bool { - let caller = get_caller_address(); - _approve(caller, spender, _allowances::read((caller, spender)) - subtracted_value); - true - } - - #[internal] - fn _mint(recipient: ContractAddress, amount: u256) { - assert(!recipient.is_zero(), 'ERC20: mint to 0'); - _total_supply::write(_total_supply::read() + amount); - _balances::write(recipient, _balances::read(recipient) + amount); - Transfer(Zeroable::zero(), recipient, amount); - } - - #[internal] - fn _burn(account: ContractAddress, amount: u256) { - assert(!account.is_zero(), 'ERC20: burn from 0'); - _total_supply::write(_total_supply::read() - amount); - _balances::write(account, _balances::read(account) - amount); - Transfer(account, Zeroable::zero(), amount); - } + #[generate_trait] + impl InternalImpl of InternalTrait { + fn initializer(ref self: ContractState, name_: felt252, symbol_: felt252) { + self._name.write(name_); + self._symbol.write(symbol_); + } - #[internal] - fn _approve(owner: ContractAddress, spender: ContractAddress, amount: u256) { - assert(!owner.is_zero(), 'ERC20: approve from 0'); - assert(!spender.is_zero(), 'ERC20: approve to 0'); - _allowances::write((owner, spender), amount); - Approval(owner, spender, amount); - } + fn _increase_allowance( + ref self: ContractState, spender: ContractAddress, added_value: u256 + ) -> bool { + let caller = get_caller_address(); + self._approve(caller, spender, self._allowances.read((caller, spender)) + added_value); + true + } - #[internal] - fn _transfer(sender: ContractAddress, recipient: ContractAddress, amount: u256) { - assert(!sender.is_zero(), 'ERC20: transfer from 0'); - assert(!recipient.is_zero(), 'ERC20: transfer to 0'); - _balances::write(sender, _balances::read(sender) - amount); - _balances::write(recipient, _balances::read(recipient) + amount); - Transfer(sender, recipient, amount); - } + fn _decrease_allowance( + ref self: ContractState, spender: ContractAddress, subtracted_value: u256 + ) -> bool { + let caller = get_caller_address(); + self + ._approve( + caller, spender, self._allowances.read((caller, spender)) - subtracted_value + ); + true + } - #[internal] - fn _spend_allowance(owner: ContractAddress, spender: ContractAddress, amount: u256) { - let current_allowance = _allowances::read((owner, spender)); - if current_allowance != BoundedInt::max() { - _approve(owner, spender, current_allowance - amount); + fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { + assert(!recipient.is_zero(), 'ERC20: mint to 0'); + self._total_supply.write(self._total_supply.read() + amount); + self._balances.write(recipient, self._balances.read(recipient) + amount); + self.emit(Transfer { from: Zeroable::zero(), to: recipient, value: amount }); + } + + fn _burn(ref self: ContractState, account: ContractAddress, amount: u256) { + assert(!account.is_zero(), 'ERC20: burn from 0'); + self._total_supply.write(self._total_supply.read() - amount); + self._balances.write(account, self._balances.read(account) - amount); + self.emit(Transfer { from: account, to: Zeroable::zero(), value: amount }); + } + + fn _approve( + ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256 + ) { + assert(!owner.is_zero(), 'ERC20: approve from 0'); + assert(!spender.is_zero(), 'ERC20: approve to 0'); + self._allowances.write((owner, spender), amount); + self.emit(Approval { owner, spender, value: amount }); + } + + fn _transfer( + ref self: ContractState, + sender: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) { + assert(!sender.is_zero(), 'ERC20: transfer from 0'); + assert(!recipient.is_zero(), 'ERC20: transfer to 0'); + self._balances.write(sender, self._balances.read(sender) - amount); + self._balances.write(recipient, self._balances.read(recipient) + amount); + self.emit(Transfer { from: sender, to: recipient, value: amount }); + } + + fn _spend_allowance( + ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256 + ) { + let current_allowance = self._allowances.read((owner, spender)); + if current_allowance != BoundedInt::max() { + self._approve(owner, spender, current_allowance - amount); + } } } } diff --git a/src/openzeppelin/token/erc20/interface.cairo b/src/openzeppelin/token/erc20/interface.cairo index 26b00e63b..8f86d6d75 100644 --- a/src/openzeppelin/token/erc20/interface.cairo +++ b/src/openzeppelin/token/erc20/interface.cairo @@ -1,45 +1,75 @@ use starknet::ContractAddress; -#[abi] -trait IERC20 { - #[view] - fn name() -> felt252; - #[view] - fn symbol() -> felt252; - #[view] - fn decimals() -> u8; - #[view] - fn total_supply() -> u256; - #[view] - fn balance_of(account: ContractAddress) -> u256; - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; +#[starknet::interface] +trait IERC20 { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn total_supply(self: @TState) -> u256; + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; } -#[abi] -trait IERC20Camel { - #[view] - fn name() -> felt252; - #[view] - fn symbol() -> felt252; - #[view] - fn decimals() -> u8; - #[view] - fn totalSupply() -> u256; - #[view] - fn balanceOf(account: ContractAddress) -> u256; - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn transferFrom(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; +#[starknet::interface] +trait IERC20Camel { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn totalSupply(self: @TState) -> u256; + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transferFrom( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; +} + +trait IERC20CamelOnly { + fn totalSupply(self: @TState) -> u256; + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn transferFrom( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; +} + +#[starknet::interface] +trait ERC20ABI { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn total_supply(self: @TState) -> u256; + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; + fn increase_allowance(ref self: TState, spender: ContractAddress, added_value: u256) -> bool; + fn decrease_allowance( + ref self: TState, spender: ContractAddress, subtracted_value: u256 + ) -> bool; +} + +#[starknet::interface] +trait ERC20CamelABI { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn totalSupply(self: @TState) -> u256; + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transferFrom( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; + fn increaseAllowance(ref self: TState, spender: ContractAddress, addedValue: u256) -> bool; + fn decreaseAllowance(ref self: TState, spender: ContractAddress, subtractedValue: u256) -> bool; } From 4e64434d5595050547327a6125f129df5a77cc52 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Sat, 22 Jul 2023 15:38:41 -0400 Subject: [PATCH 073/124] Migrate access control to cairo2 (#668) * bump to cairo v2.0.2 * update Cargo * comment out mods * update initializable syntax * move security tests * update initializable tests * fix formatting * remove SpanSerde * update ownable syntax * add ownable_camel impl * update syntax in ownable mocks * update ownable tests * fix formatting * update cairo * update Cargo * simplify and clarify tests * fix formatting * simplify internal fns * add initializer * fix constructor, tidy up code * fix tests * Apply suggestions from code review Co-authored-by: Eric Nordelo * fix tests * change StorageTrait to InternalTrait * update syntax * update mocks * start updating tests * start refactor * change impls to external fns * use IOwnableCamelOnly * fix tests * remove unneeded mut * remove unneeded mut * fix mocks * simplify events * change array syntax * update syntax in tests * fix formatting * Apply suggestions from code review Co-authored-by: Eric Nordelo * add space between events * fix generic state * add space between events * fix formatting --------- Co-authored-by: Eric Nordelo --- src/openzeppelin/access.cairo | 2 +- .../access/accesscontrol/accesscontrol.cairo | 246 +++++------ .../accesscontrol/dual_accesscontrol.cairo | 12 +- .../access/accesscontrol/interface.cairo | 38 +- src/openzeppelin/tests/access.cairo | 4 +- .../tests/access/test_accesscontrol.cairo | 387 ++++++++++-------- .../access/test_dual_accesscontrol.cairo | 15 +- src/openzeppelin/tests/mocks.cairo | 6 +- .../mocks/accesscontrol_panic_mock.cairo | 66 +-- .../mocks/camel_accesscontrol_mock.cairo | 55 ++- .../mocks/snake_accesscontrol_mock.cairo | 56 +-- 11 files changed, 460 insertions(+), 427 deletions(-) diff --git a/src/openzeppelin/access.cairo b/src/openzeppelin/access.cairo index 55beac34c..8f59b4ad1 100644 --- a/src/openzeppelin/access.cairo +++ b/src/openzeppelin/access.cairo @@ -1,2 +1,2 @@ -//mod accesscontrol; +mod accesscontrol; mod ownable; diff --git a/src/openzeppelin/access/accesscontrol/accesscontrol.cairo b/src/openzeppelin/access/accesscontrol/accesscontrol.cairo index fd7dbf36c..78d245945 100644 --- a/src/openzeppelin/access/accesscontrol/accesscontrol.cairo +++ b/src/openzeppelin/access/accesscontrol/accesscontrol.cairo @@ -1,211 +1,165 @@ -#[contract] +#[starknet::contract] mod AccessControl { - use openzeppelin::access::accesscontrol::interface; - use openzeppelin::introspection::src5; use starknet::ContractAddress; use starknet::get_caller_address; + use openzeppelin::access::accesscontrol::interface; + use openzeppelin::introspection::interface::ISRC5; + use openzeppelin::introspection::interface::ISRC5Camel; + use openzeppelin::introspection::src5::SRC5; + #[storage] struct Storage { role_admin: LegacyMap, role_members: LegacyMap<(felt252, ContractAddress), bool>, } + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + RoleGranted: RoleGranted, + RoleRevoked: RoleRevoked, + RoleAdminChanged: RoleAdminChanged, + } + /// Emitted when `account` is granted `role`. /// /// `sender` is the account that originated the contract call, an admin role /// bearer (except if `_grant_role` is called during initialization from the constructor). - #[event] - fn RoleGranted(role: felt252, account: ContractAddress, sender: ContractAddress) {} + #[derive(Drop, starknet::Event)] + struct RoleGranted { + role: felt252, + account: ContractAddress, + sender: ContractAddress + } /// Emitted when `account` is revoked `role`. /// /// `sender` is the account that originated the contract call: /// - If using `revoke_role`, it is the admin role bearer. /// - If using `renounce_role`, it is the role bearer (i.e. `account`). - #[event] - fn RoleRevoked(role: felt252, account: ContractAddress, sender: ContractAddress) {} + #[derive(Drop, starknet::Event)] + struct RoleRevoked { + role: felt252, + account: ContractAddress, + sender: ContractAddress + } /// Emitted when `new_admin_role` is set as `role`'s admin role, replacing `previous_admin_role` /// /// `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite /// {RoleAdminChanged} not being emitted signaling this. - #[event] - fn RoleAdminChanged(role: felt252, previous_admin_role: felt252, new_admin_role: felt252) {} - - impl ISRC5Impl of src5::ISRC5 { - fn supports_interface(interface_id: felt252) -> bool { - src5::SRC5::supports_interface(interface_id) + #[derive(Drop, starknet::Event)] + struct RoleAdminChanged { + role: felt252, + previous_admin_role: felt252, + new_admin_role: felt252 + } + + #[external(v0)] + impl SRC5Impl of ISRC5 { + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) } } - impl ISRC5CamelImpl of src5::ISRC5Camel { - fn supportsInterface(interfaceId: felt252) -> bool { - src5::SRC5::supportsInterface(interfaceId) + #[external(v0)] + impl SRC5CamelImpl of ISRC5Camel { + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) } } - impl AccessControlImpl of interface::IAccessControl { - fn has_role(role: felt252, account: ContractAddress) -> bool { - role_members::read((role, account)) + #[external(v0)] + impl AccessControlImpl of interface::IAccessControl { + fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + self.role_members.read((role, account)) } - fn get_role_admin(role: felt252) -> felt252 { - role_admin::read(role) + fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { + self.role_admin.read(role) } - fn grant_role(role: felt252, account: ContractAddress) { - let admin = get_role_admin(role); - assert_only_role(admin); - _grant_role(role, account); + fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { + let admin = AccessControlImpl::get_role_admin(@self, role); + self.assert_only_role(admin); + self._grant_role(role, account); } - fn revoke_role(role: felt252, account: ContractAddress) { - let admin: felt252 = get_role_admin(role); - assert_only_role(admin); - _revoke_role(role, account); + fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { + let admin = AccessControlImpl::get_role_admin(@self, role); + self.assert_only_role(admin); + self._revoke_role(role, account); } - fn renounce_role(role: felt252, account: ContractAddress) { + fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { let caller: ContractAddress = get_caller_address(); assert(caller == account, 'Can only renounce role for self'); - _revoke_role(role, account); + self._revoke_role(role, account); } } - impl AccessControlCamelImpl of interface::IAccessControlCamel { - fn hasRole(role: felt252, account: ContractAddress) -> bool { - AccessControlImpl::has_role(role, account) + #[external(v0)] + impl AccessControlCamelImpl of interface::IAccessControlCamel { + fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + AccessControlImpl::has_role(self, role, account) } - fn getRoleAdmin(role: felt252) -> felt252 { - AccessControlImpl::get_role_admin(role) + fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { + AccessControlImpl::get_role_admin(self, role) } - fn grantRole(role: felt252, account: ContractAddress) { - AccessControlImpl::grant_role(role, account); + fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { + AccessControlImpl::grant_role(ref self, role, account); } - fn revokeRole(role: felt252, account: ContractAddress) { - AccessControlImpl::revoke_role(role, account); + fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { + AccessControlImpl::revoke_role(ref self, role, account); } - fn renounceRole(role: felt252, account: ContractAddress) { - AccessControlImpl::renounce_role(role, account); + fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { + AccessControlImpl::renounce_role(ref self, role, account); } } // - // View - // - - #[view] - fn supports_interface(interface_id: felt252) -> bool { - ISRC5Impl::supports_interface(interface_id) - } - - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - ISRC5CamelImpl::supportsInterface(interfaceId) - } - - #[view] - fn has_role(role: felt252, account: ContractAddress) -> bool { - AccessControlImpl::has_role(role, account) - } - - #[view] - fn hasRole(role: felt252, account: ContractAddress) -> bool { - AccessControlCamelImpl::hasRole(role, account) - } - - #[view] - fn get_role_admin(role: felt252) -> felt252 { - AccessControlImpl::get_role_admin(role) - } - - #[view] - fn getRoleAdmin(role: felt252) -> felt252 { - AccessControlCamelImpl::getRoleAdmin(role) - } - - // - // External - // - - #[external] - fn grant_role(role: felt252, account: ContractAddress) { - AccessControlImpl::grant_role(role, account); - } - - #[external] - fn grantRole(role: felt252, account: ContractAddress) { - AccessControlCamelImpl::grantRole(role, account); - } - - #[external] - fn revoke_role(role: felt252, account: ContractAddress) { - AccessControlImpl::revoke_role(role, account); - } - - #[external] - fn revokeRole(role: felt252, account: ContractAddress) { - AccessControlCamelImpl::revokeRole(role, account); - } - - #[external] - fn renounce_role(role: felt252, account: ContractAddress) { - AccessControlImpl::renounce_role(role, account); - } - - #[external] - fn renounceRole(role: felt252, account: ContractAddress) { - AccessControlCamelImpl::renounceRole(role, account); - } - - // - // Internals + // Internal // - #[internal] - fn initializer() { - src5::SRC5::register_interface(interface::IACCESSCONTROL_ID); - } - - #[internal] - fn assert_only_role(role: felt252) { - let caller: ContractAddress = get_caller_address(); - let authorized: bool = has_role(role, caller); - assert(authorized, 'Caller is missing role'); - } - - // - // WARNING - // The following internal methods are unprotected and should not be used - // outside of a contract's constructor. - // + #[generate_trait] + impl InternalImpl of InternalTrait { + fn initializer(ref self: ContractState) { + let mut unsafe_state = SRC5::unsafe_new_contract_state(); + SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IACCESSCONTROL_ID); + } - #[internal] - fn _grant_role(role: felt252, account: ContractAddress) { - if !has_role(role, account) { + fn assert_only_role(self: @ContractState, role: felt252) { let caller: ContractAddress = get_caller_address(); - role_members::write((role, account), true); - RoleGranted(role, account, caller); + let authorized: bool = AccessControlImpl::has_role(self, role, caller); + assert(authorized, 'Caller is missing role'); } - } - #[internal] - fn _revoke_role(role: felt252, account: ContractAddress) { - if has_role(role, account) { - let caller: ContractAddress = get_caller_address(); - role_members::write((role, account), false); - RoleRevoked(role, account, caller); + fn _grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { + if !AccessControlImpl::has_role(@self, role, account) { + let caller: ContractAddress = get_caller_address(); + self.role_members.write((role, account), true); + self.emit(RoleGranted { role, account, sender: caller }); + } } - } - #[internal] - fn _set_role_admin(role: felt252, admin_role: felt252) { - let previous_admin_role: felt252 = get_role_admin(role); - role_admin::write(role, admin_role); - RoleAdminChanged(role, previous_admin_role, admin_role); + fn _revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { + if AccessControlImpl::has_role(@self, role, account) { + let caller: ContractAddress = get_caller_address(); + self.role_members.write((role, account), false); + self.emit(RoleRevoked { role, account, sender: caller }); + } + } + + fn _set_role_admin(ref self: ContractState, role: felt252, admin_role: felt252) { + let previous_admin_role: felt252 = AccessControlImpl::get_role_admin(@self, role); + self.role_admin.write(role, admin_role); + self.emit(RoleAdminChanged { role, previous_admin_role, new_admin_role: admin_role }); + } } } diff --git a/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo b/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo index e4955afd3..49367b2e5 100644 --- a/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo +++ b/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo @@ -24,7 +24,7 @@ trait DualCaseAccessControlTrait { impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { fn has_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) -> bool { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(role); args.append_serde(account); @@ -35,7 +35,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { } fn get_role_admin(self: @DualCaseAccessControl, role: felt252) -> felt252 { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(role); try_selector_with_fallback( @@ -45,7 +45,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { } fn grant_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(role); args.append_serde(account); @@ -56,7 +56,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { } fn revoke_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(role); args.append_serde(account); @@ -67,7 +67,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { } fn renounce_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(role); args.append_serde(account); @@ -78,7 +78,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait { } fn supports_interface(self: @DualCaseAccessControl, interface_id: felt252) -> bool { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(interface_id); try_selector_with_fallback( diff --git a/src/openzeppelin/access/accesscontrol/interface.cairo b/src/openzeppelin/access/accesscontrol/interface.cairo index 9f333dc0f..50adbddf7 100644 --- a/src/openzeppelin/access/accesscontrol/interface.cairo +++ b/src/openzeppelin/access/accesscontrol/interface.cairo @@ -3,30 +3,20 @@ use starknet::ContractAddress; const IACCESSCONTROL_ID: felt252 = 0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751; -#[abi] -trait IAccessControl { - #[view] - fn has_role(role: felt252, account: ContractAddress) -> bool; - #[view] - fn get_role_admin(role: felt252) -> felt252; - #[external] - fn grant_role(role: felt252, account: ContractAddress); - #[external] - fn revoke_role(role: felt252, account: ContractAddress); - #[external] - fn renounce_role(role: felt252, account: ContractAddress); +#[starknet::interface] +trait IAccessControl { + fn has_role(self: @TState, role: felt252, account: ContractAddress) -> bool; + fn get_role_admin(self: @TState, role: felt252) -> felt252; + fn grant_role(ref self: TState, role: felt252, account: ContractAddress); + fn revoke_role(ref self: TState, role: felt252, account: ContractAddress); + fn renounce_role(ref self: TState, role: felt252, account: ContractAddress); } -#[abi] -trait IAccessControlCamel { - #[view] - fn hasRole(role: felt252, account: ContractAddress) -> bool; - #[view] - fn getRoleAdmin(role: felt252) -> felt252; - #[external] - fn grantRole(role: felt252, account: ContractAddress); - #[external] - fn revokeRole(role: felt252, account: ContractAddress); - #[external] - fn renounceRole(role: felt252, account: ContractAddress); +#[starknet::interface] +trait IAccessControlCamel { + fn hasRole(self: @TState, role: felt252, account: ContractAddress) -> bool; + fn getRoleAdmin(self: @TState, role: felt252) -> felt252; + fn grantRole(ref self: TState, role: felt252, account: ContractAddress); + fn revokeRole(ref self: TState, role: felt252, account: ContractAddress); + fn renounceRole(ref self: TState, role: felt252, account: ContractAddress); } diff --git a/src/openzeppelin/tests/access.cairo b/src/openzeppelin/tests/access.cairo index b40958d1d..149c62b59 100644 --- a/src/openzeppelin/tests/access.cairo +++ b/src/openzeppelin/tests/access.cairo @@ -1,4 +1,4 @@ -//mod test_accesscontrol; -//mod test_dual_accesscontrol; +mod test_accesscontrol; +mod test_dual_accesscontrol; mod test_ownable; mod test_dual_ownable; diff --git a/src/openzeppelin/tests/access/test_accesscontrol.cairo b/src/openzeppelin/tests/access/test_accesscontrol.cairo index 5e6c71489..704242309 100644 --- a/src/openzeppelin/tests/access/test_accesscontrol.cairo +++ b/src/openzeppelin/tests/access/test_accesscontrol.cairo @@ -1,13 +1,20 @@ -use openzeppelin::access::accesscontrol::AccessControl; -use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; -use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; use starknet::contract_address_const; use starknet::ContractAddress; use starknet::testing; +use openzeppelin::access::accesscontrol::AccessControl; +use openzeppelin::access::accesscontrol::AccessControl::InternalImpl; +use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; +use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; +use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; +use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; const ROLE: felt252 = 41; const OTHER_ROLE: felt252 = 42; +fn ZERO() -> ContractAddress { + contract_address_const::<0>() +} + fn ADMIN() -> ContractAddress { contract_address_const::<1>() } @@ -24,9 +31,18 @@ fn OTHER_ADMIN() -> ContractAddress { contract_address_const::<4>() } -fn setup() { - AccessControl::_grant_role(DEFAULT_ADMIN_ROLE, ADMIN()); - testing::set_caller_address(ADMIN()); +// +// Setup +// + +fn STATE() -> AccessControl::ContractState { + AccessControl::contract_state_for_testing() +} + +fn setup() -> AccessControl::ContractState { + let mut state = STATE(); + InternalImpl::_grant_role(ref state, DEFAULT_ADMIN_ROLE, ADMIN()); + state } // @@ -36,10 +52,13 @@ fn setup() { #[test] #[available_gas(2000000)] fn test_initializer() { - AccessControl::initializer(); - assert(AccessControl::supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); + let mut state = STATE(); + InternalImpl::initializer(ref state); + assert( + AccessControl::SRC5Impl::supports_interface(@state, IACCESSCONTROL_ID), + 'Should support own interface' + ); } - // // supports_interface & supportsInterface // @@ -47,15 +66,23 @@ fn test_initializer() { #[test] #[available_gas(2000000)] fn test_supports_interface() { - AccessControl::initializer(); - assert(AccessControl::supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); + let mut state = STATE(); + InternalImpl::initializer(ref state); + assert( + AccessControl::SRC5Impl::supports_interface(@state, IACCESSCONTROL_ID), + 'Should support own interface' + ); } #[test] #[available_gas(2000000)] fn test_supportsInterface() { - AccessControl::initializer(); - assert(AccessControl::supportsInterface(IACCESSCONTROL_ID), 'Should support own interface'); + let mut state = STATE(); + InternalImpl::initializer(ref state); + assert( + AccessControl::SRC5CamelImpl::supportsInterface(@state, IACCESSCONTROL_ID), + 'Should support own interface' + ); } // @@ -65,19 +92,19 @@ fn test_supportsInterface() { #[test] #[available_gas(2000000)] fn test_has_role() { - setup(); - assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'should not have role'); - AccessControl::_grant_role(ROLE, AUTHORIZED()); - assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'should have role'); + let mut state = setup(); + assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'should not have role'); + InternalImpl::_grant_role(ref state, ROLE, AUTHORIZED()); + assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'should have role'); } #[test] #[available_gas(2000000)] fn test_hasRole() { - setup(); - assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'should not have role'); - AccessControl::_grant_role(ROLE, AUTHORIZED()); - assert(AccessControl::hasRole(ROLE, AUTHORIZED()), 'should have role'); + let mut state = setup(); + assert(!AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'should not have role'); + InternalImpl::_grant_role(ref state, ROLE, AUTHORIZED()); + assert(AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'should have role'); } @@ -88,29 +115,32 @@ fn test_hasRole() { #[test] #[available_gas(2000000)] fn test_assert_only_role() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); - AccessControl::assert_only_role(ROLE); + InternalImpl::assert_only_role(@state, ROLE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role', ))] fn test_assert_only_role_unauthorized() { - setup(); + let state = setup(); testing::set_caller_address(OTHER()); - AccessControl::assert_only_role(ROLE); + InternalImpl::assert_only_role(@state, ROLE); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role', ))] fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); + let mut state = setup(); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); - AccessControl::assert_only_role(OTHER_ROLE); + InternalImpl::assert_only_role(@state, OTHER_ROLE); } // @@ -120,53 +150,61 @@ fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { #[test] #[available_gas(2000000)] fn test_grant_role() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); - assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should be granted'); + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be granted'); } #[test] #[available_gas(2000000)] -fn test_grant_role_multiple_times_for_granted_role() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); - AccessControl::grant_role(ROLE, AUTHORIZED()); - assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should still be granted'); +fn test_grantRole() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + assert(AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be granted'); } #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] -fn test_grant_role_unauthorized() { - setup(); - testing::set_caller_address(AUTHORIZED()); - AccessControl::grant_role(ROLE, AUTHORIZED()); +fn test_grant_role_multiple_times_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be granted'); } #[test] #[available_gas(2000000)] -fn test_grantRole() { - setup(); - AccessControl::grantRole(ROLE, AUTHORIZED()); - assert(AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should be granted'); +fn test_grantRole_multiple_times_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + assert( + AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should still be granted' + ); } #[test] #[available_gas(2000000)] -fn test_grantRole_multiple_times_for_granted_role() { - setup(); - AccessControl::grantRole(ROLE, AUTHORIZED()); - AccessControl::grantRole(ROLE, AUTHORIZED()); - assert(AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should still be granted'); +#[should_panic(expected: ('Caller is missing role', ))] +fn test_grant_role_unauthorized() { + let mut state = setup(); + testing::set_caller_address(AUTHORIZED()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role', ))] fn test_grantRole_unauthorized() { - setup(); + let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControl::grantRole(ROLE, AUTHORIZED()); + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); } // @@ -176,75 +214,85 @@ fn test_grantRole_unauthorized() { #[test] #[available_gas(2000000)] fn test_revoke_role_for_role_not_granted() { - setup(); - AccessControl::revoke_role(ROLE, AUTHORIZED()); + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); } #[test] #[available_gas(2000000)] -fn test_revoke_role_for_granted_role() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); - AccessControl::revoke_role(ROLE, AUTHORIZED()); - assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should be revoked'); +fn test_revokeRole_for_role_not_granted() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); } #[test] #[available_gas(2000000)] -fn test_revoke_role_multiple_times_for_granted_role() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); +fn test_revoke_role_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); - AccessControl::revoke_role(ROLE, AUTHORIZED()); - AccessControl::revoke_role(ROLE, AUTHORIZED()); - assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should still be revoked'); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be revoked'); } #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] -fn test_revoke_role_unauthorized() { - setup(); +fn test_revokeRole_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); - testing::set_caller_address(OTHER()); - AccessControl::revoke_role(ROLE, AUTHORIZED()); + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + assert(!AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be revoked'); } #[test] #[available_gas(2000000)] -fn test_revokeRole_for_role_not_granted() { - setup(); - AccessControl::revokeRole(ROLE, AUTHORIZED()); +fn test_revoke_role_multiple_times_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + assert( + !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be revoked' + ); } #[test] #[available_gas(2000000)] -fn test_revokeRole_for_granted_role() { - setup(); - AccessControl::grantRole(ROLE, AUTHORIZED()); - AccessControl::revokeRole(ROLE, AUTHORIZED()); - assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should be revoked'); +fn test_revokeRole_multiple_times_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + assert( + !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should still be revoked' + ); } #[test] #[available_gas(2000000)] -fn test_revokeRole_multiple_times_for_granted_role() { - setup(); - AccessControl::grantRole(ROLE, AUTHORIZED()); - - AccessControl::revokeRole(ROLE, AUTHORIZED()); - AccessControl::revokeRole(ROLE, AUTHORIZED()); - assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should still be revoked'); +#[should_panic(expected: ('Caller is missing role', ))] +fn test_revoke_role_unauthorized() { + let mut state = setup(); + testing::set_caller_address(OTHER()); + AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role', ))] fn test_revokeRole_unauthorized() { - setup(); - + let mut state = setup(); testing::set_caller_address(OTHER()); - AccessControl::revokeRole(ROLE, AUTHORIZED()); + AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); } // @@ -254,87 +302,98 @@ fn test_revokeRole_unauthorized() { #[test] #[available_gas(2000000)] fn test_renounce_role_for_role_not_granted() { - setup(); + let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - - AccessControl::renounce_role(ROLE, AUTHORIZED()); + AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); } #[test] #[available_gas(2000000)] -fn test_renounce_role_for_granted_role() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); +fn test_renounceRole_for_role_not_granted() { + let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - - AccessControl::renounce_role(ROLE, AUTHORIZED()); - assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should be renounced'); + AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); } #[test] #[available_gas(2000000)] -fn test_renounce_role_multiple_times_for_granted_role() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); - testing::set_caller_address(AUTHORIZED()); +fn test_renounce_role_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControl::renounce_role(ROLE, AUTHORIZED()); - AccessControl::renounce_role(ROLE, AUTHORIZED()); - assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'Role should still be renounced'); + testing::set_caller_address(AUTHORIZED()); + AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be renounced'); } #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Can only renounce role for self', ))] -fn test_renounce_role_unauthorized() { - setup(); - AccessControl::grant_role(ROLE, AUTHORIZED()); +fn test_renounceRole_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - // Admin is unauthorized caller - AccessControl::renounce_role(ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); + AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + assert( + !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be renounced' + ); } #[test] #[available_gas(2000000)] -fn test_renounceRole_for_role_not_granted() { - setup(); - testing::set_caller_address(AUTHORIZED()); +fn test_renounce_role_multiple_times_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControl::renounceRole(ROLE, AUTHORIZED()); + testing::set_caller_address(AUTHORIZED()); + AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + assert( + !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be renounced' + ); } #[test] #[available_gas(2000000)] -fn test_renounceRole_for_granted_role() { - setup(); - AccessControl::grantRole(ROLE, AUTHORIZED()); - testing::set_caller_address(AUTHORIZED()); +fn test_renounceRole_multiple_times_for_granted_role() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - AccessControl::renounceRole(ROLE, AUTHORIZED()); - assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should be renounced'); + testing::set_caller_address(AUTHORIZED()); + AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + assert( + !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), + 'Role should still be renounced' + ); } #[test] #[available_gas(2000000)] -fn test_renounceRole_multiple_times_for_granted_role() { - setup(); - AccessControl::grantRole(ROLE, AUTHORIZED()); - testing::set_caller_address(AUTHORIZED()); +#[should_panic(expected: ('Can only renounce role for self', ))] +fn test_renounce_role_unauthorized() { + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControl::renounceRole(ROLE, AUTHORIZED()); - AccessControl::renounceRole(ROLE, AUTHORIZED()); - assert(!AccessControl::hasRole(ROLE, AUTHORIZED()), 'Role should still be renounced'); + testing::set_caller_address(ZERO()); + AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Can only renounce role for self', ))] fn test_renounceRole_unauthorized() { - setup(); - AccessControl::grantRole(ROLE, AUTHORIZED()); + let mut state = setup(); + testing::set_caller_address(ADMIN()); + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); // Admin is unauthorized caller - AccessControl::renounceRole(ROLE, AUTHORIZED()); + AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); } // @@ -344,61 +403,67 @@ fn test_renounceRole_unauthorized() { #[test] #[available_gas(2000000)] fn test__set_role_admin() { - setup(); + let mut state = setup(); + assert( + AccessControlImpl::get_role_admin(@state, ROLE) == DEFAULT_ADMIN_ROLE, + 'ROLE admin default should be 0' + ); + InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); assert( - AccessControl::get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'ROLE admin default should be 0' + AccessControlImpl::get_role_admin(@state, ROLE) == OTHER_ROLE, + 'ROLE admin should be OTHER_ROLE' ); - AccessControl::_set_role_admin(ROLE, OTHER_ROLE); - assert(AccessControl::get_role_admin(ROLE) == OTHER_ROLE, 'ROLE admin should be OTHER_ROLE'); } #[test] #[available_gas(2000000)] fn test_new_admin_can_grant_roles() { - setup(); - AccessControl::_set_role_admin(ROLE, OTHER_ROLE); - AccessControl::grant_role(OTHER_ROLE, OTHER_ADMIN()); + let mut state = setup(); + InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); - testing::set_caller_address(OTHER_ADMIN()); - AccessControl::grant_role(ROLE, AUTHORIZED()); + testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, OTHER_ROLE, OTHER_ADMIN()); - assert(AccessControl::has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should have ROLE'); + testing::set_caller_address(OTHER_ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'AUTHORIZED should have ROLE'); } #[test] #[available_gas(2000000)] fn test_new_admin_can_revoke_roles() { - setup(); - AccessControl::_set_role_admin(ROLE, OTHER_ROLE); - AccessControl::grant_role(OTHER_ROLE, OTHER_ADMIN()); + let mut state = setup(); + InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); - testing::set_caller_address(OTHER_ADMIN()); - AccessControl::grant_role(ROLE, AUTHORIZED()); - AccessControl::revoke_role(ROLE, AUTHORIZED()); + testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, OTHER_ROLE, OTHER_ADMIN()); - assert(!AccessControl::has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should not have ROLE'); + testing::set_caller_address(OTHER_ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + assert( + !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'AUTHORIZED should not have ROLE' + ); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role', ))] fn test_previous_admin_cannot_grant_roles() { - setup(); - AccessControl::_set_role_admin(ROLE, OTHER_ROLE); - - // Caller is ADMIN - AccessControl::grant_role(ROLE, AUTHORIZED()); + let mut state = setup(); + InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); } #[test] #[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role', ))] fn test_previous_admin_cannot_revoke_roles() { - setup(); - AccessControl::_set_role_admin(ROLE, OTHER_ROLE); - - // Caller is ADMIN - AccessControl::revoke_role(ROLE, AUTHORIZED()); + let mut state = setup(); + InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + testing::set_caller_address(ADMIN()); + AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); } // @@ -408,8 +473,9 @@ fn test_previous_admin_cannot_revoke_roles() { #[test] #[available_gas(2000000)] fn test_other_role_admin_is_the_default_admin_role() { + let state = setup(); assert( - AccessControl::get_role_admin(OTHER_ROLE) == DEFAULT_ADMIN_ROLE, + AccessControlImpl::get_role_admin(@state, OTHER_ROLE) == DEFAULT_ADMIN_ROLE, 'Should be DEFAULT_ADMIN_ROLE' ); } @@ -417,8 +483,9 @@ fn test_other_role_admin_is_the_default_admin_role() { #[test] #[available_gas(2000000)] fn test_default_admin_role_is_its_own_admin() { + let state = setup(); assert( - AccessControl::get_role_admin(DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE, + AccessControlImpl::get_role_admin(@state, DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE, 'Should be DEFAULT_ADMIN_ROLE' ); } diff --git a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo index 7a229576e..7fc3b5049 100644 --- a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo +++ b/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo @@ -38,7 +38,7 @@ fn AUTHORIZED() -> ContractAddress { // fn setup_snake() -> (DualCaseAccessControl, IAccessControlDispatcher) { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; calldata.append_serde(ADMIN()); let target = utils::deploy(SnakeAccessControlMock::TEST_CLASS_HASH, calldata); ( @@ -48,7 +48,7 @@ fn setup_snake() -> (DualCaseAccessControl, IAccessControlDispatcher) { } fn setup_camel() -> (DualCaseAccessControl, IAccessControlCamelDispatcher) { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; calldata.append_serde(ADMIN()); let target = utils::deploy(CamelAccessControlMock::TEST_CLASS_HASH, calldata); ( @@ -58,18 +58,13 @@ fn setup_camel() -> (DualCaseAccessControl, IAccessControlCamelDispatcher) { } fn setup_non_accesscontrol() -> DualCaseAccessControl { - let calldata = ArrayTrait::new(); - let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, array![]); DualCaseAccessControl { contract_address: target } } fn setup_accesscontrol_panic() -> (DualCaseAccessControl, DualCaseAccessControl) { - let snake_target = utils::deploy( - SnakeAccessControlPanicMock::TEST_CLASS_HASH, ArrayTrait::new() - ); - let camel_target = utils::deploy( - CamelAccessControlPanicMock::TEST_CLASS_HASH, ArrayTrait::new() - ); + let snake_target = utils::deploy(SnakeAccessControlPanicMock::TEST_CLASS_HASH, array![]); + let camel_target = utils::deploy(CamelAccessControlPanicMock::TEST_CLASS_HASH, array![]); ( DualCaseAccessControl { contract_address: snake_target }, DualCaseAccessControl { contract_address: camel_target } diff --git a/src/openzeppelin/tests/mocks.cairo b/src/openzeppelin/tests/mocks.cairo index 4a8530b24..fd2e8f322 100644 --- a/src/openzeppelin/tests/mocks.cairo +++ b/src/openzeppelin/tests/mocks.cairo @@ -5,11 +5,11 @@ mod erc721_panic_mock; mod camel20_mock; mod snake20_mock; mod erc20_panic; -// mod accesscontrol_panic_mock; +mod accesscontrol_panic_mock; mod account_panic_mock; -// mod camel_accesscontrol_mock; +mod camel_accesscontrol_mock; mod camel_account_mock; -// mod snake_accesscontrol_mock; +mod snake_accesscontrol_mock; mod snake_account_mock; mod dual_ownable_mocks; mod snake721_mock; diff --git a/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo b/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo index 10601ca78..8ccfe80dc 100644 --- a/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo +++ b/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo @@ -4,78 +4,84 @@ // 3 for felt252 // false for bool -#[contract] +#[starknet::contract] mod SnakeAccessControlPanicMock { use starknet::ContractAddress; - #[view] - fn supports_interface(interface_id: felt252) -> bool { + #[storage] + struct Storage {} + + #[external(v0)] + fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { panic_with_felt252('Some error'); false } - #[view] - fn has_role(role: felt252, account: ContractAddress) -> bool { + #[external(v0)] + fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { panic_with_felt252('Some error'); - false + 3 } - #[view] - fn get_role_admin(role: felt252) -> felt252 { + #[external(v0)] + fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { panic_with_felt252('Some error'); - 3 } - #[external] - fn grant_role(role: felt252, account: ContractAddress) { + #[external(v0)] + fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { panic_with_felt252('Some error'); } - #[external] - fn revoke_role(role: felt252, account: ContractAddress) { + #[external(v0)] + fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { panic_with_felt252('Some error'); } - #[external] - fn renounce_role(role: felt252, account: ContractAddress) { + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { panic_with_felt252('Some error'); + false } } -#[contract] +#[starknet::contract] mod CamelAccessControlPanicMock { use starknet::ContractAddress; - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { + #[storage] + struct Storage {} + + #[external(v0)] + fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { panic_with_felt252('Some error'); false } - #[view] - fn hasRole(role: felt252, account: ContractAddress) -> bool { + #[external(v0)] + fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { panic_with_felt252('Some error'); - false + 3 } - #[view] - fn getRoleAdmin(role: felt252) -> felt252 { + #[external(v0)] + fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { panic_with_felt252('Some error'); - 3 } - #[external] - fn grantRole(role: felt252, account: ContractAddress) { + #[external(v0)] + fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { panic_with_felt252('Some error'); } - #[external] - fn revokeRole(role: felt252, account: ContractAddress) { + #[external(v0)] + fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { panic_with_felt252('Some error'); } - #[external] - fn renounceRole(role: felt252, account: ContractAddress) { + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { panic_with_felt252('Some error'); + false } } diff --git a/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo b/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo index dff5ab1b6..dc0879a60 100644 --- a/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo +++ b/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo @@ -1,43 +1,54 @@ -#[contract] +#[starknet::contract] mod CamelAccessControlMock { use starknet::ContractAddress; use starknet::get_caller_address; use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + #[storage] + struct Storage {} + #[constructor] - fn constructor(admin: ContractAddress) { - AccessControl::initializer(); - AccessControl::_grant_role(DEFAULT_ADMIN_ROLE, admin); + fn constructor(ref self: ContractState, admin: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControl::InternalImpl::initializer(ref unsafe_state); + AccessControl::InternalImpl::_grant_role(ref unsafe_state, DEFAULT_ADMIN_ROLE, admin); } - #[view] - fn supportsInterface(interfaceId: felt252) -> bool { - AccessControl::supportsInterface(interfaceId) + #[external(v0)] + fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + let unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlCamelImpl::hasRole(@unsafe_state, role, account) } - #[view] - fn hasRole(role: felt252, account: ContractAddress) -> bool { - AccessControl::hasRole(role, account) + #[external(v0)] + fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { + let unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlCamelImpl::getRoleAdmin(@unsafe_state, role) } - #[view] - fn getRoleAdmin(role: felt252) -> felt252 { - AccessControl::getRoleAdmin(role) + #[external(v0)] + fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlCamelImpl::grantRole(ref unsafe_state, role, account); } - #[external] - fn grantRole(role: felt252, account: ContractAddress) { - AccessControl::grantRole(role, account); + #[external(v0)] + fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlCamelImpl::revokeRole(ref unsafe_state, role, account); } - #[external] - fn revokeRole(role: felt252, account: ContractAddress) { - AccessControl::revokeRole(role, account); + #[external(v0)] + fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlCamelImpl::renounceRole(ref unsafe_state, role, account); } - #[external] - fn renounceRole(role: felt252, account: ContractAddress) { - AccessControl::renounceRole(role, account); + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + let unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControl::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) } } diff --git a/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo b/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo index ea3122a67..1d69feaec 100644 --- a/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo +++ b/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo @@ -1,44 +1,54 @@ -#[contract] +#[starknet::contract] mod SnakeAccessControlMock { use starknet::ContractAddress; use starknet::get_caller_address; use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; - use openzeppelin::utils::serde::SpanSerde; + + #[storage] + struct Storage {} #[constructor] - fn constructor(admin: ContractAddress) { - AccessControl::initializer(); - AccessControl::_grant_role(DEFAULT_ADMIN_ROLE, admin); + fn constructor(ref self: ContractState, admin: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControl::InternalImpl::initializer(ref unsafe_state); + AccessControl::InternalImpl::_grant_role(ref unsafe_state, DEFAULT_ADMIN_ROLE, admin); } - #[view] - fn supports_interface(interface_id: felt252) -> bool { - AccessControl::supports_interface(interface_id) + #[external(v0)] + fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + let unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlImpl::has_role(@unsafe_state, role, account) } - #[view] - fn has_role(role: felt252, account: ContractAddress) -> bool { - AccessControl::has_role(role, account) + #[external(v0)] + fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { + let unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlImpl::get_role_admin(@unsafe_state, role) } - #[view] - fn get_role_admin(role: felt252) -> felt252 { - AccessControl::get_role_admin(role) + #[external(v0)] + fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlImpl::grant_role(ref unsafe_state, role, account); } - #[external] - fn grant_role(role: felt252, account: ContractAddress) { - AccessControl::grant_role(role, account); + #[external(v0)] + fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlImpl::revoke_role(ref unsafe_state, role, account); } - #[external] - fn revoke_role(role: felt252, account: ContractAddress) { - AccessControl::revoke_role(role, account); + #[external(v0)] + fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControlImpl::renounce_role(ref unsafe_state, role, account); } - #[external] - fn renounce_role(role: felt252, account: ContractAddress) { - AccessControl::renounce_role(role, account); + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + let unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControl::SRC5Impl::supports_interface(@unsafe_state, interface_id) } } From 79fe2db03f5f290b98a0ea671a6f4799638a5d8e Mon Sep 17 00:00:00 2001 From: maciektr Date: Fri, 4 Aug 2023 03:24:54 +0200 Subject: [PATCH 074/124] Migrate to Scarb for cairo-2 (#671) * Migrate to Scarb * Hide tests module behind cfg --- .github/workflows/test.yml | 11 +- .gitignore | 8 +- CONTRIBUTING.md | 4 +- Cargo.lock | 3623 ----------------- Cargo.toml | 115 - Makefile | 28 - Scarb.toml | 21 + cairo | 1 - src/{openzeppelin => }/access.cairo | 0 .../access/accesscontrol.cairo | 0 .../access/accesscontrol/accesscontrol.cairo | 0 .../accesscontrol/dual_accesscontrol.cairo | 0 .../access/accesscontrol/interface.cairo | 0 src/{openzeppelin => }/access/ownable.cairo | 0 .../access/ownable/dual_ownable.cairo | 0 .../access/ownable/interface.cairo | 0 .../access/ownable/ownable.cairo | 0 src/{openzeppelin => }/account.cairo | 0 src/{openzeppelin => }/account/account.cairo | 0 .../account/dual_account.cairo | 0 .../account/interface.cairo | 0 src/{openzeppelin => }/cairo_project.toml | 0 src/{openzeppelin => }/introspection.cairo | 0 .../introspection/dual_src5.cairo | 0 .../introspection/interface.cairo | 0 .../introspection/src5.cairo | 0 src/{openzeppelin => }/lib.cairo | 4 +- src/{openzeppelin => }/security.cairo | 0 .../security/initializable.cairo | 0 .../security/pausable.cairo | 0 .../security/reentrancyguard.cairo | 0 src/{openzeppelin => }/tests.cairo | 0 src/{openzeppelin => }/tests/access.cairo | 0 .../tests/access/test_accesscontrol.cairo | 0 .../access/test_dual_accesscontrol.cairo | 21 +- .../tests/access/test_dual_ownable.cairo | 14 +- .../tests/access/test_ownable.cairo | 0 src/{openzeppelin => }/tests/account.cairo | 0 .../tests/account/test_account.cairo | 0 .../tests/account/test_dual_account.cairo | 21 +- .../tests/introspection.cairo | 0 .../tests/introspection/test_dual_src5.cairo | 7 +- .../tests/introspection/test_src5.cairo | 0 src/{openzeppelin => }/tests/mocks.cairo | 0 .../mocks/accesscontrol_panic_mock.cairo | 0 .../tests/mocks/account_panic_mock.cairo | 0 .../tests/mocks/camel20_mock.cairo | 0 .../tests/mocks/camel721_mock.cairo | 0 .../mocks/camel_accesscontrol_mock.cairo | 0 .../tests/mocks/camel_account_mock.cairo | 0 .../tests/mocks/dual721_receiver_mocks.cairo | 0 .../tests/mocks/dual_ownable_mocks.cairo | 0 .../tests/mocks/erc20_panic.cairo | 0 .../tests/mocks/erc721_panic_mock.cairo | 0 .../tests/mocks/erc721_receiver.cairo | 0 .../tests/mocks/non_implementing_mock.cairo | 0 .../mocks/reentrancy_attacker_mock.cairo | 0 .../tests/mocks/reentrancy_mock.cairo | 5 +- .../tests/mocks/snake20_mock.cairo | 0 .../tests/mocks/snake721_mock.cairo | 0 .../mocks/snake_accesscontrol_mock.cairo | 0 .../tests/mocks/snake_account_mock.cairo | 0 .../tests/mocks/src5_mocks.cairo | 0 src/{openzeppelin => }/tests/security.cairo | 0 .../tests/security/test_initializable.cairo | 0 .../tests/security/test_pausable.cairo | 0 .../tests/security/test_reentrancyguard.cairo | 0 src/{openzeppelin => }/tests/token.cairo | 0 .../tests/token/test_dual20.cairo | 0 .../tests/token/test_dual721.cairo | 14 +- .../tests/token/test_dual721_receiver.cairo | 21 +- .../tests/token/test_erc20.cairo | 0 .../tests/token/test_erc721.cairo | 0 src/{openzeppelin => }/tests/utils.cairo | 0 src/{openzeppelin => }/token.cairo | 0 src/{openzeppelin => }/token/erc20.cairo | 0 .../token/erc20/dual20.cairo | 0 .../token/erc20/erc20.cairo | 0 .../token/erc20/interface.cairo | 0 src/{openzeppelin => }/token/erc721.cairo | 0 .../token/erc721/dual721.cairo | 0 .../token/erc721/dual721_receiver.cairo | 0 .../token/erc721/erc721.cairo | 9 +- .../token/erc721/interface.cairo | 0 src/{openzeppelin => }/utils.cairo | 0 src/{openzeppelin => }/utils/constants.cairo | 0 src/{openzeppelin => }/utils/selectors.cairo | 0 src/{openzeppelin => }/utils/serde.cairo | 0 .../utils/unwrap_and_cast.cairo | 0 89 files changed, 114 insertions(+), 3813 deletions(-) delete mode 100644 Cargo.lock delete mode 100644 Cargo.toml delete mode 100644 Makefile create mode 100644 Scarb.toml delete mode 160000 cairo rename src/{openzeppelin => }/access.cairo (100%) rename src/{openzeppelin => }/access/accesscontrol.cairo (100%) rename src/{openzeppelin => }/access/accesscontrol/accesscontrol.cairo (100%) rename src/{openzeppelin => }/access/accesscontrol/dual_accesscontrol.cairo (100%) rename src/{openzeppelin => }/access/accesscontrol/interface.cairo (100%) rename src/{openzeppelin => }/access/ownable.cairo (100%) rename src/{openzeppelin => }/access/ownable/dual_ownable.cairo (100%) rename src/{openzeppelin => }/access/ownable/interface.cairo (100%) rename src/{openzeppelin => }/access/ownable/ownable.cairo (100%) rename src/{openzeppelin => }/account.cairo (100%) rename src/{openzeppelin => }/account/account.cairo (100%) rename src/{openzeppelin => }/account/dual_account.cairo (100%) rename src/{openzeppelin => }/account/interface.cairo (100%) rename src/{openzeppelin => }/cairo_project.toml (100%) rename src/{openzeppelin => }/introspection.cairo (100%) rename src/{openzeppelin => }/introspection/dual_src5.cairo (100%) rename src/{openzeppelin => }/introspection/interface.cairo (100%) rename src/{openzeppelin => }/introspection/src5.cairo (100%) rename src/{openzeppelin => }/lib.cairo (86%) rename src/{openzeppelin => }/security.cairo (100%) rename src/{openzeppelin => }/security/initializable.cairo (100%) rename src/{openzeppelin => }/security/pausable.cairo (100%) rename src/{openzeppelin => }/security/reentrancyguard.cairo (100%) rename src/{openzeppelin => }/tests.cairo (100%) rename src/{openzeppelin => }/tests/access.cairo (100%) rename src/{openzeppelin => }/tests/access/test_accesscontrol.cairo (100%) rename src/{openzeppelin => }/tests/access/test_dual_accesscontrol.cairo (95%) rename src/{openzeppelin => }/tests/access/test_dual_ownable.cairo (94%) rename src/{openzeppelin => }/tests/access/test_ownable.cairo (100%) rename src/{openzeppelin => }/tests/account.cairo (100%) rename src/{openzeppelin => }/tests/account/test_account.cairo (100%) rename src/{openzeppelin => }/tests/account/test_dual_account.cairo (94%) rename src/{openzeppelin => }/tests/introspection.cairo (100%) rename src/{openzeppelin => }/tests/introspection/test_dual_src5.cairo (94%) rename src/{openzeppelin => }/tests/introspection/test_src5.cairo (100%) rename src/{openzeppelin => }/tests/mocks.cairo (100%) rename src/{openzeppelin => }/tests/mocks/accesscontrol_panic_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/account_panic_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/camel20_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/camel721_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/camel_accesscontrol_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/camel_account_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/dual721_receiver_mocks.cairo (100%) rename src/{openzeppelin => }/tests/mocks/dual_ownable_mocks.cairo (100%) rename src/{openzeppelin => }/tests/mocks/erc20_panic.cairo (100%) rename src/{openzeppelin => }/tests/mocks/erc721_panic_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/erc721_receiver.cairo (100%) rename src/{openzeppelin => }/tests/mocks/non_implementing_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/reentrancy_attacker_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/reentrancy_mock.cairo (95%) rename src/{openzeppelin => }/tests/mocks/snake20_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/snake721_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/snake_accesscontrol_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/snake_account_mock.cairo (100%) rename src/{openzeppelin => }/tests/mocks/src5_mocks.cairo (100%) rename src/{openzeppelin => }/tests/security.cairo (100%) rename src/{openzeppelin => }/tests/security/test_initializable.cairo (100%) rename src/{openzeppelin => }/tests/security/test_pausable.cairo (100%) rename src/{openzeppelin => }/tests/security/test_reentrancyguard.cairo (100%) rename src/{openzeppelin => }/tests/token.cairo (100%) rename src/{openzeppelin => }/tests/token/test_dual20.cairo (100%) rename src/{openzeppelin => }/tests/token/test_dual721.cairo (98%) rename src/{openzeppelin => }/tests/token/test_dual721_receiver.cairo (89%) rename src/{openzeppelin => }/tests/token/test_erc20.cairo (100%) rename src/{openzeppelin => }/tests/token/test_erc721.cairo (100%) rename src/{openzeppelin => }/tests/utils.cairo (100%) rename src/{openzeppelin => }/token.cairo (100%) rename src/{openzeppelin => }/token/erc20.cairo (100%) rename src/{openzeppelin => }/token/erc20/dual20.cairo (100%) rename src/{openzeppelin => }/token/erc20/erc20.cairo (100%) rename src/{openzeppelin => }/token/erc20/interface.cairo (100%) rename src/{openzeppelin => }/token/erc721.cairo (100%) rename src/{openzeppelin => }/token/erc721/dual721.cairo (100%) rename src/{openzeppelin => }/token/erc721/dual721_receiver.cairo (100%) rename src/{openzeppelin => }/token/erc721/erc721.cairo (98%) rename src/{openzeppelin => }/token/erc721/interface.cairo (100%) rename src/{openzeppelin => }/utils.cairo (100%) rename src/{openzeppelin => }/utils/constants.cairo (100%) rename src/{openzeppelin => }/utils/selectors.cairo (100%) rename src/{openzeppelin => }/utils/serde.cairo (100%) rename src/{openzeppelin => }/utils/unwrap_and_cast.cairo (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa705adfa..0a9921611 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,10 +3,10 @@ name: Lint and test on: pull_request: branches: - - cairo-1 + - cairo-2 push: branches: - - cairo-1 + - cairo-2 jobs: lint_and_test: @@ -14,8 +14,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - uses: software-mansion/setup-scarb@v1 with: - submodules: recursive + scarb-version: "0.6.0-alpha.1" - name: Markdown lint uses: DavidAnson/markdownlint-cli2-action@5b7c9f74fec47e6b15667b2cc23c63dff11e449e # v9 with: @@ -23,6 +24,6 @@ jobs: *.md !PULL_REQUEST_TEMPLATE.md - name: Cairo lint - run: make check-format + run: scarb fmt --check - name: Cairo test - run: make test + run: scarb test diff --git a/.gitignore b/.gitignore index 73cda39c1..869665ba4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,11 @@ -artifacts/ .DS_Store # Cairo 1 - corelib/ +# Scarb +target/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -78,9 +79,6 @@ instance/ # Sphinx documentation docs/_build/ -# PyBuilder -target/ - # Jupyter Notebook .ipynb_checkpoints diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3c8aca19d..49e9b88d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ func internal_func(param_one, param_two){ } ``` -Compare our preset contracts with the libraries from which they're derived such as the [ERC20 preset](./src/openzeppelin/token/erc20/presets/ERC20.cairo) and [ERC20 library](./src/openzeppelin/token/erc20/presets/ERC20.cairo) for full examples. +Compare our preset contracts with the libraries from which they're derived such as the [ERC20 preset](src/token/erc20/presets/ERC20.cairo) and [ERC20 library](src/token/erc20/presets/ERC20.cairo) for full examples. See [Function names and coding style](https://docs.openzeppelin.com/contracts-cairo/0.4.0/extensibility#function_names_and_coding_style) for more information. And make sure to always include tests and documentation for the new developments. Please consider the following conventions: @@ -54,7 +54,7 @@ And make sure to always include tests and documentation for the new developments ``` - Preset contract testing - - Though, inheritance is not possible in Cairo, this repo utilizes inheritance for testing. This proves useful for testing multiple contracts that stem from the same base library. For example, the preset contracts [ERC20Mintable](./src/openzeppelin/token/erc20/presets/ERC20Mintable.cairo) and [ERC20Burnable](./src/openzeppelin/token/erc20/presets/ERC20Burnable.cairo) both share the base ERC20 functionality. To reduce code repetition, we follow these guidelines: + - Though, inheritance is not possible in Cairo, this repo utilizes inheritance for testing. This proves useful for testing multiple contracts that stem from the same base library. For example, the preset contracts [ERC20Mintable](src/token/erc20/presets/ERC20Mintable.cairo) and [ERC20Burnable](src/token/erc20/presets/ERC20Burnable.cairo) both share the base ERC20 functionality. To reduce code repetition, we follow these guidelines: - `BaseSuites` - module names are not prefixed with `test_` - set base tests inside a class diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 278c09912..000000000 --- a/Cargo.lock +++ /dev/null @@ -1,3623 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "aho-corasick" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" - -[[package]] -name = "anyhow" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" - -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits 0.2.15", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest", - "itertools 0.10.5", - "num-bigint", - "num-traits 0.2.15", - "paste", - "rustc_version", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.103", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits 0.2.15", - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", -] - -[[package]] -name = "ark-secp256k1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02e954eaeb4ddb29613fee20840c2bbc85ca4396d53e33837e11905363c5f2" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-secp256r1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-serialize-derive", - "ark-std", - "digest", - "num-bigint", -] - -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits 0.2.15", - "rand", -] - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" - -[[package]] -name = "async-trait" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "auto_impl" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bimap" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0455254eb5c6964c4545d8bac815e1a1be4f3afe0ae695ea539c12d728d44b" - -[[package]] -name = "bincode" -version = "2.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" -dependencies = [ - "serde", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "cairo-compile" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-compiler", - "cairo-lang-utils", - "clap", - "log", -] - -[[package]] -name = "cairo-felt" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8de851723a7d13ed8b0b588a78ffa6b38d8e1f3eb4b6e71a96376510e5504a" -dependencies = [ - "lazy_static", - "num-bigint", - "num-integer", - "num-traits 0.2.15", - "serde", -] - -[[package]] -name = "cairo-format" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-formatter", - "cairo-lang-utils", - "clap", - "colored", - "ignore", - "log", -] - -[[package]] -name = "cairo-lang-casm" -version = "2.0.2" -dependencies = [ - "cairo-lang-utils", - "env_logger", - "indoc", - "itertools 0.11.0", - "num-bigint", - "num-traits 0.2.15", - "parity-scale-codec", - "parity-scale-codec-derive", - "pretty_assertions", - "schemars", - "serde", - "test-case", - "test-log", - "thiserror", -] - -[[package]] -name = "cairo-lang-compiler" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-project", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-generator", - "cairo-lang-syntax", - "cairo-lang-utils", - "log", - "salsa", - "smol_str", - "test-log", - "thiserror", -] - -[[package]] -name = "cairo-lang-debug" -version = "2.0.2" -dependencies = [ - "cairo-lang-proc-macros", - "cairo-lang-utils", - "env_logger", - "salsa", - "test-log", -] - -[[package]] -name = "cairo-lang-defs" -version = "2.0.2" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-syntax", - "cairo-lang-test-utils", - "cairo-lang-utils", - "env_logger", - "indexmap 2.0.0", - "indoc", - "itertools 0.11.0", - "pretty_assertions", - "salsa", - "smol_str", - "test-log", -] - -[[package]] -name = "cairo-lang-diagnostics" -version = "2.0.2" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-filesystem", - "cairo-lang-proc-macros", - "cairo-lang-utils", - "env_logger", - "indoc", - "itertools 0.11.0", - "pretty_assertions", - "salsa", - "test-log", -] - -[[package]] -name = "cairo-lang-eq-solver" -version = "2.0.2" -dependencies = [ - "cairo-lang-utils", - "env_logger", - "good_lp", - "indexmap 2.0.0", - "indoc", - "itertools 0.11.0", - "test-case", - "test-log", -] - -[[package]] -name = "cairo-lang-filesystem" -version = "2.0.2" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-utils", - "env_logger", - "path-clean", - "salsa", - "serde", - "serde_json", - "smol_str", - "test-log", -] - -[[package]] -name = "cairo-lang-formatter" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-syntax", - "cairo-lang-utils", - "colored", - "diffy", - "ignore", - "itertools 0.11.0", - "log", - "pretty_assertions", - "salsa", - "smol_str", - "test-case", - "test-log", -] - -[[package]] -name = "cairo-lang-language-server" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-compiler", - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-formatter", - "cairo-lang-lowering", - "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-project", - "cairo-lang-semantic", - "cairo-lang-starknet", - "cairo-lang-syntax", - "cairo-lang-utils", - "indoc", - "log", - "lsp-types", - "salsa", - "scarb-metadata", - "serde", - "serde_json", - "smol_str", - "test-log", - "tokio", - "tower-lsp", -] - -[[package]] -name = "cairo-lang-lowering" -version = "2.0.2" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-proc-macros", - "cairo-lang-semantic", - "cairo-lang-syntax", - "cairo-lang-test-utils", - "cairo-lang-utils", - "env_logger", - "id-arena", - "indexmap 2.0.0", - "indoc", - "itertools 0.11.0", - "log", - "num-bigint", - "num-traits 0.2.15", - "pretty_assertions", - "salsa", - "smol_str", - "test-log", -] - -[[package]] -name = "cairo-lang-parser" -version = "2.0.2" -dependencies = [ - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-syntax", - "cairo-lang-syntax-codegen", - "cairo-lang-test-utils", - "cairo-lang-utils", - "colored", - "env_logger", - "itertools 0.11.0", - "log", - "num-bigint", - "num-traits 0.2.15", - "pretty_assertions", - "salsa", - "smol_str", - "test-case", - "test-log", - "unescaper", -] - -[[package]] -name = "cairo-lang-plugins" -version = "2.0.2" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-semantic", - "cairo-lang-syntax", - "cairo-lang-test-utils", - "cairo-lang-utils", - "env_logger", - "indoc", - "itertools 0.11.0", - "num-bigint", - "salsa", - "serde_json", - "smol_str", - "test-case", - "test-log", -] - -[[package]] -name = "cairo-lang-proc-macros" -version = "2.0.2" -dependencies = [ - "cairo-lang-debug", - "quote", - "syn 2.0.26", -] - -[[package]] -name = "cairo-lang-project" -version = "2.0.2" -dependencies = [ - "cairo-lang-filesystem", - "cairo-lang-utils", - "indoc", - "serde", - "smol_str", - "test-log", - "thiserror", - "toml", -] - -[[package]] -name = "cairo-lang-runner" -version = "2.0.2" -dependencies = [ - "anyhow", - "ark-ff", - "ark-secp256k1", - "ark-secp256r1", - "ark-std", - "cairo-felt", - "cairo-lang-casm", - "cairo-lang-compiler", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", - "cairo-lang-sierra-gas", - "cairo-lang-sierra-generator", - "cairo-lang-sierra-to-casm", - "cairo-lang-sierra-type-size", - "cairo-lang-starknet", - "cairo-lang-utils", - "cairo-vm", - "itertools 0.11.0", - "keccak", - "num-bigint", - "num-integer", - "num-traits 0.2.15", - "pretty_assertions", - "salsa", - "test-case", - "thiserror", -] - -[[package]] -name = "cairo-lang-semantic" -version = "2.0.2" -dependencies = [ - "assert_matches", - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-proc-macros", - "cairo-lang-syntax", - "cairo-lang-test-utils", - "cairo-lang-utils", - "env_logger", - "id-arena", - "indoc", - "itertools 0.11.0", - "log", - "num-bigint", - "num-traits 0.2.15", - "pretty_assertions", - "salsa", - "smol_str", - "test-case", - "test-log", -] - -[[package]] -name = "cairo-lang-sierra" -version = "2.0.2" -dependencies = [ - "assert_matches", - "bimap", - "cairo-lang-utils", - "const-fnv1a-hash", - "convert_case", - "derivative", - "env_logger", - "indoc", - "itertools 0.11.0", - "lalrpop", - "lalrpop-util", - "num-bigint", - "num-traits 0.2.15", - "pretty_assertions", - "regex", - "salsa", - "serde", - "sha3", - "smol_str", - "test-case", - "test-log", - "thiserror", -] - -[[package]] -name = "cairo-lang-sierra-ap-change" -version = "2.0.2" -dependencies = [ - "cairo-lang-eq-solver", - "cairo-lang-sierra", - "cairo-lang-sierra-type-size", - "cairo-lang-utils", - "env_logger", - "indoc", - "itertools 0.11.0", - "test-case", - "test-log", - "thiserror", -] - -[[package]] -name = "cairo-lang-sierra-gas" -version = "2.0.2" -dependencies = [ - "cairo-lang-eq-solver", - "cairo-lang-sierra", - "cairo-lang-sierra-type-size", - "cairo-lang-test-utils", - "cairo-lang-utils", - "env_logger", - "indoc", - "itertools 0.11.0", - "pretty_assertions", - "test-case", - "test-log", - "thiserror", -] - -[[package]] -name = "cairo-lang-sierra-generator" -version = "2.0.2" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-proc-macros", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-syntax", - "cairo-lang-test-utils", - "cairo-lang-utils", - "env_logger", - "id-arena", - "indexmap 2.0.0", - "indoc", - "itertools 0.11.0", - "log", - "num-bigint", - "pretty_assertions", - "salsa", - "smol_str", - "test-case", - "test-log", -] - -[[package]] -name = "cairo-lang-sierra-to-casm" -version = "2.0.2" -dependencies = [ - "assert_matches", - "cairo-felt", - "cairo-lang-casm", - "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", - "cairo-lang-sierra-gas", - "cairo-lang-sierra-type-size", - "cairo-lang-utils", - "env_logger", - "indoc", - "itertools 0.11.0", - "log", - "num-bigint", - "num-traits 0.2.15", - "pretty_assertions", - "test-case", - "test-log", - "thiserror", -] - -[[package]] -name = "cairo-lang-sierra-type-size" -version = "2.0.2" -dependencies = [ - "cairo-lang-sierra", - "cairo-lang-utils", -] - -[[package]] -name = "cairo-lang-starknet" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-felt", - "cairo-lang-casm", - "cairo-lang-compiler", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", - "cairo-lang-sierra-gas", - "cairo-lang-sierra-generator", - "cairo-lang-sierra-to-casm", - "cairo-lang-syntax", - "cairo-lang-test-utils", - "cairo-lang-utils", - "convert_case", - "env_logger", - "genco", - "indent", - "indoc", - "itertools 0.11.0", - "log", - "num-bigint", - "num-integer", - "num-traits 0.2.15", - "once_cell", - "pretty_assertions", - "serde", - "serde_json", - "sha3", - "smol_str", - "test-case", - "test-log", - "thiserror", -] - -[[package]] -name = "cairo-lang-syntax" -version = "2.0.2" -dependencies = [ - "cairo-lang-debug", - "cairo-lang-filesystem", - "cairo-lang-utils", - "env_logger", - "num-bigint", - "num-traits 0.2.15", - "pretty_assertions", - "salsa", - "smol_str", - "test-log", - "thiserror", - "unescaper", -] - -[[package]] -name = "cairo-lang-syntax-codegen" -version = "2.0.2" -dependencies = [ - "env_logger", - "genco", - "test-log", - "xshell", -] - -[[package]] -name = "cairo-lang-test-runner" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-felt", - "cairo-lang-casm", - "cairo-lang-compiler", - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-plugins", - "cairo-lang-project", - "cairo-lang-runner", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-generator", - "cairo-lang-sierra-to-casm", - "cairo-lang-starknet", - "cairo-lang-syntax", - "cairo-lang-utils", - "cairo-vm", - "colored", - "itertools 0.11.0", - "num-bigint", - "num-traits 0.2.15", - "rayon", - "salsa", - "thiserror", -] - -[[package]] -name = "cairo-lang-test-utils" -version = "2.0.2" -dependencies = [ - "cairo-lang-utils", - "env_logger", - "log", - "pretty_assertions", - "test-log", -] - -[[package]] -name = "cairo-lang-utils" -version = "2.0.2" -dependencies = [ - "env_logger", - "indexmap 2.0.0", - "itertools 0.11.0", - "log", - "num-bigint", - "num-integer", - "num-traits 0.2.15", - "parity-scale-codec", - "schemars", - "serde", - "serde_json", - "test-case", - "test-log", - "time", -] - -[[package]] -name = "cairo-language-server" -version = "2.0.2" -dependencies = [ - "cairo-lang-language-server", - "cairo-lang-utils", - "log", - "tokio", -] - -[[package]] -name = "cairo-run" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-compiler", - "cairo-lang-diagnostics", - "cairo-lang-runner", - "cairo-lang-sierra", - "cairo-lang-sierra-generator", - "cairo-lang-starknet", - "cairo-lang-utils", - "clap", -] - -[[package]] -name = "cairo-test" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-compiler", - "cairo-lang-test-runner", - "clap", -] - -[[package]] -name = "cairo-vm" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656c25c13b6ffcc75e081292f3c23f27e429b3d4b8d69ecdc327a441798e91f4" -dependencies = [ - "anyhow", - "bincode", - "bitvec", - "cairo-felt", - "generic-array", - "hashbrown 0.14.0", - "hex", - "keccak", - "lazy_static", - "mimalloc", - "nom", - "num-bigint", - "num-integer", - "num-prime", - "num-traits 0.2.15", - "rand", - "serde", - "serde_json", - "sha2", - "sha3", - "starknet-crypto", - "thiserror-no-std", -] - -[[package]] -name = "camino" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" -dependencies = [ - "serde", -] - -[[package]] -name = "cc" -version = "1.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" -dependencies = [ - "atty", - "bitflags", - "clap_derive", - "clap_lex", - "once_cell", - "strsim", - "termcolor", -] - -[[package]] -name = "clap_derive" -version = "4.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" -dependencies = [ - "heck 0.4.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "clap_lex" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "colored" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" -dependencies = [ - "atty", - "lazy_static", - "winapi", -] - -[[package]] -name = "const-fnv1a-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" -dependencies = [ - "generic-array", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.103", -] - -[[package]] -name = "dashmap" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" -dependencies = [ - "cfg-if", - "hashbrown 0.12.3", - "lock_api", - "once_cell", - "parking_lot_core 0.9.4", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "diffy" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e616e59155c92257e84970156f506287853355f58cd4a6eb167385722c32b790" -dependencies = [ - "nu-ansi-term", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dyn-clone" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" - -[[package]] -name = "either" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" - -[[package]] -name = "futures-executor" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" - -[[package]] -name = "futures-macro" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "futures-sink" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" - -[[package]] -name = "futures-task" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" - -[[package]] -name = "futures-timer" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" - -[[package]] -name = "futures-util" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "genco" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8598ff0782dbc5231cf9eb727c1c5e398515b7b62ee68761c2c73950a1de1f4" -dependencies = [ - "genco-macros", - "relative-path", - "smallvec", -] - -[[package]] -name = "genco-macros" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40803f2757f84c877f088e62420931f6e05a72514f1f03630384aa30b91d667b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "generate-syntax" -version = "2.0.2" -dependencies = [ - "cairo-lang-syntax-codegen", - "cairo-lang-utils", - "log", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "globset" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" -dependencies = [ - "aho-corasick 0.7.20", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "good_lp" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51d78cbb7b734379eea7f811ddb33b2b13defefa1dab50068d7bc7f781a3056" -dependencies = [ - "fnv", - "minilp", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.6", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.3", -] - -[[package]] -name = "hashbrown" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" -dependencies = [ - "ahash 0.8.3", - "allocator-api2", - "serde", -] - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "ignore" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" -dependencies = [ - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "indent" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1a0777d972970f204fdf8ef319f1f4f8459131636d7e3c96c5d59570d0fa6" - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" -dependencies = [ - "equivalent", - "hashbrown 0.14.0", - "serde", -] - -[[package]] -name = "indoc" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.45.0", -] - -[[package]] -name = "is-terminal" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.45.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" -dependencies = [ - "ascii-canvas", - "bit-set", - "diff", - "ena", - "is-terminal", - "itertools 0.10.5", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" -dependencies = [ - "regex", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] - -[[package]] -name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "libmimalloc-sys" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ac0e912c8ef1b735e92369695618dc5b1819f5a7bf3f167301a3ba1cea515e" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lru" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" -dependencies = [ - "hashbrown 0.12.3", -] - -[[package]] -name = "lsp-types" -version = "0.94.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b63735a13a1f9cd4f4835223d828ed9c2e35c8c5e61837774399f558b6a1237" -dependencies = [ - "bitflags", - "serde", - "serde_json", - "serde_repr", - "url", -] - -[[package]] -name = "matrixmultiply" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916806ba0031cd542105d916a97c8572e1fa6dd79c9c51e7eb43a09ec2dd84c1" -dependencies = [ - "rawpointer", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mimalloc" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2894987a3459f3ffb755608bd82188f8ed00d0ae077f1edea29c068d639d98" -dependencies = [ - "libmimalloc-sys", -] - -[[package]] -name = "minilp" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a7750a9e5076c660b7bec5e6457b4dbff402b9863c8d112891434e18fd5385" -dependencies = [ - "log", - "sprs", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.42.0", -] - -[[package]] -name = "ndarray" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac06db03ec2f46ee0ecdca1a1c34a99c0d188a0d83439b84bf0cb4b386e4ab09" -dependencies = [ - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits 0.2.15", - "rawpointer", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nom" -version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits 0.2.15", - "rand", - "serde", -] - -[[package]] -name = "num-complex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" -dependencies = [ - "autocfg", - "num-traits 0.2.15", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits 0.2.15", -] - -[[package]] -name = "num-modular" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits 0.2.15", -] - -[[package]] -name = "num-prime" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4e3bc495f6e95bc15a6c0c55ac00421504a5a43d09e3cc455d1fea7015581d" -dependencies = [ - "bitvec", - "either", - "lru", - "num-bigint", - "num-integer", - "num-modular", - "num-traits 0.2.15", - "rand", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.15", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" -dependencies = [ - "hermit-abi 0.1.19", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parity-scale-codec" -version = "3.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756d439303e94fae44f288ba881ad29670c65b0c4b0e05674ca81061bb65f2c5" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d884d78fcf214d70b1e239fcd1c6e5e95aa3be1881918da2e488cc946c7a476" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.5", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.4", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.42.0", -] - -[[package]] -name = "paste" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" - -[[package]] -name = "path-clean" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap 1.9.2", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - -[[package]] -name = "pin-project" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "pretty_assertions" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" -dependencies = [ - "ctor", - "diff", - "output_vt100", - "yansi", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.103", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "rayon" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" -dependencies = [ - "aho-corasick 1.0.2", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" -dependencies = [ - "aho-corasick 1.0.2", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" - -[[package]] -name = "relative-path" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "rstest" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b96577ca10cb3eade7b337eb46520108a67ca2818a24d0b63f41fd62bc9651c" -dependencies = [ - "futures", - "futures-timer", - "rstest_macros", - "rustc_version", -] - -[[package]] -name = "rstest_macros" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225e674cf31712b8bb15fdbca3ec0c1b9d825c5a24407ff2b7e005fb6a29ba03" -dependencies = [ - "cfg-if", - "glob", - "proc-macro2", - "quote", - "regex", - "relative-path", - "rustc_version", - "syn 2.0.26", - "unicode-ident", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.36.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.45.0", -] - -[[package]] -name = "rustversion" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "salsa" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b84d9f96071f3f3be0dc818eae3327625d8ebc95b58da37d6850724f31d3403" -dependencies = [ - "crossbeam-utils", - "indexmap 1.9.2", - "lock_api", - "log", - "oorandom", - "parking_lot 0.11.2", - "rustc-hash", - "salsa-macros", - "smallvec", -] - -[[package]] -name = "salsa-macros" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3904a4ba0a9d0211816177fd34b04c7095443f8cdacd11175064fe541c8fe2" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scarb-metadata" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ba10c59bd4ebde82de954e3a3d6d503eb17bd634106ef144af1356b28b8f0f" -dependencies = [ - "camino", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "schemars" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" -dependencies = [ - "dyn-clone", - "indexmap 1.9.2", - "schemars_derive", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 1.0.103", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.171" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.171" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.26", -] - -[[package]] -name = "serde_derive_internals" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "serde_json" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "serde_spanned" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" -dependencies = [ - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "sierra-compile" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-sierra", - "cairo-lang-sierra-to-casm", - "cairo-lang-utils", - "clap", - "indoc", - "log", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "smol_str" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", -] - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "sprs" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec63571489873d4506683915840eeb1bb16b3198ee4894cc6f2fe3013d505e56" -dependencies = [ - "ndarray", - "num-complex", - "num-traits 0.1.43", -] - -[[package]] -name = "starknet-compile" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-compiler", - "cairo-lang-starknet", - "clap", -] - -[[package]] -name = "starknet-crypto" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693e6362f150f9276e429a910481fb7f3bcb8d6aa643743f587cfece0b374874" -dependencies = [ - "crypto-bigint", - "hex", - "hmac", - "num-bigint", - "num-integer", - "num-traits 0.2.15", - "rfc6979", - "sha2", - "starknet-crypto-codegen", - "starknet-curve 0.3.0", - "starknet-ff", - "zeroize", -] - -[[package]] -name = "starknet-crypto-codegen" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" -dependencies = [ - "starknet-curve 0.4.0", - "starknet-ff", - "syn 2.0.26", -] - -[[package]] -name = "starknet-curve" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "252610baff59e4c4332ce3569f7469c5d3f9b415a2240d698fb238b2b4fc0942" -dependencies = [ - "starknet-ff", -] - -[[package]] -name = "starknet-curve" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68a0d87ae56572abf83ddbfd44259a7c90dbeeee1629a1ffe223e7f9a8f3052" -dependencies = [ - "starknet-ff", -] - -[[package]] -name = "starknet-ff" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2cb1d9c0a50380cddab99cb202c6bfb3332728a2769bd0ca2ee80b0b390dd4" -dependencies = [ - "ark-ff", - "crypto-bigint", - "getrandom", - "hex", -] - -[[package]] -name = "starknet-sierra-compile" -version = "2.0.2" -dependencies = [ - "anyhow", - "cairo-lang-sierra", - "cairo-lang-starknet", - "cairo-lang-utils", - "clap", - "serde", - "serde_json", -] - -[[package]] -name = "string_cache" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot 0.12.1", - "phf_shared", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", - "unicode-xid", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "test-case" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1d6e7bde536b0412f20765b76e921028059adfd1b90d8974d33fd3c91b25df" -dependencies = [ - "test-case-macros", -] - -[[package]] -name = "test-case-core" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d10394d5d1e27794f772b6fc854c7e91a2dc26e2cbf807ad523370c2a59c0cee" -dependencies = [ - "cfg-if", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "test-case-macros" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb9a44b1c6a54c1ba58b152797739dba2a83ca74e18168a68c980eb142f9404" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.103", - "test-case-core", -] - -[[package]] -name = "test-log" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f0c854faeb68a048f0f2dc410c5ddae3bf83854ef0e4977d58306a5edef50e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "tests" -version = "2.0.2" -dependencies = [ - "assert_matches", - "cairo-felt", - "cairo-lang-casm", - "cairo-lang-compiler", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-runner", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-gas", - "cairo-lang-sierra-generator", - "cairo-lang-sierra-to-casm", - "cairo-lang-syntax", - "cairo-lang-test-utils", - "cairo-lang-utils", - "env_logger", - "itertools 0.11.0", - "log", - "num-bigint", - "once_cell", - "pretty_assertions", - "rstest", - "salsa", - "test-case", - "test-log", -] - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.26", -] - -[[package]] -name = "thiserror-impl-no-std" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "thiserror-no-std" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" -dependencies = [ - "thiserror-impl-no-std", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" -dependencies = [ - "itoa", - "libc", - "num_threads", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" - -[[package]] -name = "time-macros" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" -dependencies = [ - "time-core", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot 0.12.1", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "winapi", -] - -[[package]] -name = "tokio-macros" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "tokio-util" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" -dependencies = [ - "indexmap 2.0.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-lsp" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b38fb0e6ce037835174256518aace3ca621c4f96383c56bb846cfc11b341910" -dependencies = [ - "async-trait", - "auto_impl", - "bytes", - "dashmap", - "futures", - "httparse", - "lsp-types", - "memchr", - "serde", - "serde_json", - "tokio", - "tokio-util", - "tower", - "tower-lsp-macros", - "tracing", -] - -[[package]] -name = "tower-lsp-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34723c06344244474fdde365b76aebef8050bf6be61a935b91ee9ff7c4e91157" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.26", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unescaper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995483205de764db1185c9461a000fff73fa4b9ee2bbe4c8b4027a94692700fe" -dependencies = [ - "thiserror", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-ident" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.103", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "winnow" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "xshell" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d47097dc5c85234b1e41851b3422dd6d19b3befdd35b4ae5ce386724aeca981" -dependencies = [ - "xshell-macros", -] - -[[package]] -name = "xshell-macros" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88301b56c26dd9bf5c43d858538f82d6f3f7764767defbc5d34e59459901c41a" - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.103", - "synstructure", -] diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 753694083..000000000 --- a/Cargo.toml +++ /dev/null @@ -1,115 +0,0 @@ -[profile.release] -overflow-checks = true # Enable integer overflow checks. - -[workspace] - -members = [ - "cairo/crates/cairo-lang-casm", - "cairo/crates/cairo-lang-compiler", - "cairo/crates/cairo-lang-debug", - "cairo/crates/cairo-lang-defs", - "cairo/crates/cairo-lang-diagnostics", - "cairo/crates/cairo-lang-eq-solver", - "cairo/crates/cairo-lang-filesystem", - "cairo/crates/cairo-lang-formatter", - "cairo/crates/cairo-lang-language-server", - "cairo/crates/cairo-lang-lowering", - "cairo/crates/cairo-lang-parser", - "cairo/crates/cairo-lang-plugins", - "cairo/crates/cairo-lang-proc-macros", - "cairo/crates/cairo-lang-project", - "cairo/crates/cairo-lang-runner", - "cairo/crates/cairo-lang-semantic", - "cairo/crates/cairo-lang-sierra", - "cairo/crates/cairo-lang-sierra-ap-change", - "cairo/crates/cairo-lang-sierra-gas", - "cairo/crates/cairo-lang-sierra-generator", - "cairo/crates/cairo-lang-sierra-to-casm", - "cairo/crates/cairo-lang-sierra-type-size", - "cairo/crates/cairo-lang-starknet", - "cairo/crates/cairo-lang-syntax", - "cairo/crates/cairo-lang-syntax-codegen", - "cairo/crates/cairo-lang-test-runner", - "cairo/crates/cairo-lang-utils", - "cairo/crates/bin/cairo-language-server", - "cairo/crates/bin/cairo-compile", - "cairo/crates/bin/cairo-format", - "cairo/crates/bin/cairo-test", - "cairo/crates/bin/cairo-run", - "cairo/crates/bin/sierra-compile", - "cairo/crates/bin/starknet-compile", - "cairo/crates/bin/starknet-sierra-compile", - "cairo/crates/bin/generate-syntax", - "cairo/tests", -] - -[workspace.package] -version = "2.0.2" -edition = "2021" -repository = "https://github.com/starkware-libs/cairo/" -license = "Apache-2.0" -license-file = "LICENSE" - -[workspace.dependencies] -anyhow = "1.0.66" -ark-ff = "0.4.0-alpha.7" -ark-secp256k1 = "0.4.0" -ark-secp256r1 = "0.4.0" -ark-std = "0.4.0" -assert_matches = "1.5" -bimap = "0.6.2" -cairo-felt = "0.8.2" -cairo-vm = "0.8.2" -clap = { version = "4.0", features = ["derive"] } -colored = "2" -const-fnv1a-hash = "1.1.0" -convert_case = "0.6.0" -derivative = "2.2.0" -diffy = "0.3.0" -env_logger = "0.10.0" -genco = "0.17.0" -good_lp = { version = "1.3.2", features = ["minilp"], default-features = false } -id-arena = "2.2.1" -ignore = "0.4.20" -indent = "0.1.1" -indexmap = { version = "2.0.0", features = ["serde"] } -indoc = "2.0.1" -itertools = "0.11.0" -keccak = "0.1.3" -lalrpop-util = { version = "0.20.0", features = ["lexer"] } -log = "0.4" -lsp = { version = "0.94", package = "lsp-types" } -num-bigint = "0.4" -num-integer = "0.1" -num-traits = "0.2" -once_cell = "1.17.1" -parity-scale-codec = "3.5.0" -parity-scale-codec-derive = "3.1.4" -path-clean = "1.0.1" -pretty_assertions = "1.2.1" -proc-macro2 = "1.0" -quote = "1.0.21" -rayon = "1.7.0" -rstest = "0.18.1" -salsa = "0.16.1" -scarb-metadata = "1.4.2" -schemars = { version = "0.8.12", features = ["preserve_order"] } -serde = { version = "1.0.130", features = ["derive"] } -serde_json = "1.0" -sha3 = "0.10.6" -smol_str = { version = "0.2.0", features = ["serde"] } -syn = { version = "2.0.25", features = ["full", "extra-traits"] } -test-case = "3.1.0" -test-case-macros = "2.2.2" -test-log = "0.2.11" -thiserror = "1.0.32" -time = { version = "0.3.20", features = [ - "formatting", - "macros", - "local-offset", -] } -tokio = { version = "1.18.2", features = ["full", "sync"] } -toml = "0.7.6" -tower-lsp = "0.19.0" -unescaper = "0.1.1" -xshell = "0.2.2" diff --git a/Makefile b/Makefile deleted file mode 100644 index 0ed75752e..000000000 --- a/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -.SILENT: -.PHONY: compile -SOURCE_FOLDER=./src/openzeppelin - -install: - git submodule init && git submodule update && cp -rf cairo/corelib . - -update: - git submodule update && cp -rf cairo/corelib . - -build: - cargo build - -test: - cargo run --bin cairo-test -- --starknet $(SOURCE_FOLDER) - -format: - cargo run --bin cairo-format -- --recursive $(SOURCE_FOLDER) --print-parsing-errors - -check-format: - cargo run --bin cairo-format -- --check --recursive $(SOURCE_FOLDER) - -starknet-compile: - mkdir -p artifacts && \ - cargo run --bin starknet-compile -- ${dir} artifacts/$(shell basename $(dir)).json --allowed-libfuncs-list-name experimental_v0.1.0 - -language-server: - cargo build --bin cairo-language-server --release diff --git a/Scarb.toml b/Scarb.toml new file mode 100644 index 000000000..e36e29c60 --- /dev/null +++ b/Scarb.toml @@ -0,0 +1,21 @@ +[package] +name = "openzeppelin" +version = "0.1.0" +cairo-version = "2.1.0-rc1" +authors = ["OpenZeppelin Community "] +description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" +documentation = "https://docs.openzeppelin.com/contracts-cairo" +readme = "README.md" +repository = "https://github.com/OpenZeppelin/cairo-contracts" +license-file = "LICENSE" +keywords = ["openzeppelin", "starknet", "cairo", "contracts", "security", "standards"] + +[dependencies] +starknet = ">=2.1.0-rc0" + +[lib] + +[[target.starknet-contract]] +allowed-libfuncs-list.name = "experimental" +sierra = true +casm = false diff --git a/cairo b/cairo deleted file mode 160000 index 06722bd86..000000000 --- a/cairo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 06722bd868b675500f61e87125cc5db519592e63 diff --git a/src/openzeppelin/access.cairo b/src/access.cairo similarity index 100% rename from src/openzeppelin/access.cairo rename to src/access.cairo diff --git a/src/openzeppelin/access/accesscontrol.cairo b/src/access/accesscontrol.cairo similarity index 100% rename from src/openzeppelin/access/accesscontrol.cairo rename to src/access/accesscontrol.cairo diff --git a/src/openzeppelin/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo similarity index 100% rename from src/openzeppelin/access/accesscontrol/accesscontrol.cairo rename to src/access/accesscontrol/accesscontrol.cairo diff --git a/src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo b/src/access/accesscontrol/dual_accesscontrol.cairo similarity index 100% rename from src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo rename to src/access/accesscontrol/dual_accesscontrol.cairo diff --git a/src/openzeppelin/access/accesscontrol/interface.cairo b/src/access/accesscontrol/interface.cairo similarity index 100% rename from src/openzeppelin/access/accesscontrol/interface.cairo rename to src/access/accesscontrol/interface.cairo diff --git a/src/openzeppelin/access/ownable.cairo b/src/access/ownable.cairo similarity index 100% rename from src/openzeppelin/access/ownable.cairo rename to src/access/ownable.cairo diff --git a/src/openzeppelin/access/ownable/dual_ownable.cairo b/src/access/ownable/dual_ownable.cairo similarity index 100% rename from src/openzeppelin/access/ownable/dual_ownable.cairo rename to src/access/ownable/dual_ownable.cairo diff --git a/src/openzeppelin/access/ownable/interface.cairo b/src/access/ownable/interface.cairo similarity index 100% rename from src/openzeppelin/access/ownable/interface.cairo rename to src/access/ownable/interface.cairo diff --git a/src/openzeppelin/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo similarity index 100% rename from src/openzeppelin/access/ownable/ownable.cairo rename to src/access/ownable/ownable.cairo diff --git a/src/openzeppelin/account.cairo b/src/account.cairo similarity index 100% rename from src/openzeppelin/account.cairo rename to src/account.cairo diff --git a/src/openzeppelin/account/account.cairo b/src/account/account.cairo similarity index 100% rename from src/openzeppelin/account/account.cairo rename to src/account/account.cairo diff --git a/src/openzeppelin/account/dual_account.cairo b/src/account/dual_account.cairo similarity index 100% rename from src/openzeppelin/account/dual_account.cairo rename to src/account/dual_account.cairo diff --git a/src/openzeppelin/account/interface.cairo b/src/account/interface.cairo similarity index 100% rename from src/openzeppelin/account/interface.cairo rename to src/account/interface.cairo diff --git a/src/openzeppelin/cairo_project.toml b/src/cairo_project.toml similarity index 100% rename from src/openzeppelin/cairo_project.toml rename to src/cairo_project.toml diff --git a/src/openzeppelin/introspection.cairo b/src/introspection.cairo similarity index 100% rename from src/openzeppelin/introspection.cairo rename to src/introspection.cairo diff --git a/src/openzeppelin/introspection/dual_src5.cairo b/src/introspection/dual_src5.cairo similarity index 100% rename from src/openzeppelin/introspection/dual_src5.cairo rename to src/introspection/dual_src5.cairo diff --git a/src/openzeppelin/introspection/interface.cairo b/src/introspection/interface.cairo similarity index 100% rename from src/openzeppelin/introspection/interface.cairo rename to src/introspection/interface.cairo diff --git a/src/openzeppelin/introspection/src5.cairo b/src/introspection/src5.cairo similarity index 100% rename from src/openzeppelin/introspection/src5.cairo rename to src/introspection/src5.cairo diff --git a/src/openzeppelin/lib.cairo b/src/lib.cairo similarity index 86% rename from src/openzeppelin/lib.cairo rename to src/lib.cairo index e03376525..235e12392 100644 --- a/src/openzeppelin/lib.cairo +++ b/src/lib.cairo @@ -2,6 +2,8 @@ mod access; mod account; mod introspection; mod security; -mod tests; mod token; mod utils; + +#[cfg(test)] +mod tests; diff --git a/src/openzeppelin/security.cairo b/src/security.cairo similarity index 100% rename from src/openzeppelin/security.cairo rename to src/security.cairo diff --git a/src/openzeppelin/security/initializable.cairo b/src/security/initializable.cairo similarity index 100% rename from src/openzeppelin/security/initializable.cairo rename to src/security/initializable.cairo diff --git a/src/openzeppelin/security/pausable.cairo b/src/security/pausable.cairo similarity index 100% rename from src/openzeppelin/security/pausable.cairo rename to src/security/pausable.cairo diff --git a/src/openzeppelin/security/reentrancyguard.cairo b/src/security/reentrancyguard.cairo similarity index 100% rename from src/openzeppelin/security/reentrancyguard.cairo rename to src/security/reentrancyguard.cairo diff --git a/src/openzeppelin/tests.cairo b/src/tests.cairo similarity index 100% rename from src/openzeppelin/tests.cairo rename to src/tests.cairo diff --git a/src/openzeppelin/tests/access.cairo b/src/tests/access.cairo similarity index 100% rename from src/openzeppelin/tests/access.cairo rename to src/tests/access.cairo diff --git a/src/openzeppelin/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo similarity index 100% rename from src/openzeppelin/tests/access/test_accesscontrol.cairo rename to src/tests/access/test_accesscontrol.cairo diff --git a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo similarity index 95% rename from src/openzeppelin/tests/access/test_dual_accesscontrol.cairo rename to src/tests/access/test_dual_accesscontrol.cairo index 7fc3b5049..fb3c916d5 100644 --- a/src/openzeppelin/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -42,8 +42,11 @@ fn setup_snake() -> (DualCaseAccessControl, IAccessControlDispatcher) { calldata.append_serde(ADMIN()); let target = utils::deploy(SnakeAccessControlMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccessControl { contract_address: target }, - IAccessControlDispatcher { contract_address: target } + DualCaseAccessControl { + contract_address: target + }, IAccessControlDispatcher { + contract_address: target + } ) } @@ -52,8 +55,11 @@ fn setup_camel() -> (DualCaseAccessControl, IAccessControlCamelDispatcher) { calldata.append_serde(ADMIN()); let target = utils::deploy(CamelAccessControlMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccessControl { contract_address: target }, - IAccessControlCamelDispatcher { contract_address: target } + DualCaseAccessControl { + contract_address: target + }, IAccessControlCamelDispatcher { + contract_address: target + } ) } @@ -66,8 +72,11 @@ fn setup_accesscontrol_panic() -> (DualCaseAccessControl, DualCaseAccessControl) let snake_target = utils::deploy(SnakeAccessControlPanicMock::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelAccessControlPanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseAccessControl { contract_address: snake_target }, - DualCaseAccessControl { contract_address: camel_target } + DualCaseAccessControl { + contract_address: snake_target + }, DualCaseAccessControl { + contract_address: camel_target + } ) } diff --git a/src/openzeppelin/tests/access/test_dual_ownable.cairo b/src/tests/access/test_dual_ownable.cairo similarity index 94% rename from src/openzeppelin/tests/access/test_dual_ownable.cairo rename to src/tests/access/test_dual_ownable.cairo index 672df30ce..470709dc6 100644 --- a/src/openzeppelin/tests/access/test_dual_ownable.cairo +++ b/src/tests/access/test_dual_ownable.cairo @@ -46,8 +46,11 @@ fn setup_camel() -> (DualCaseOwnable, IOwnableCamelOnlyDispatcher) { calldata.append_serde(OWNER()); let target = utils::deploy(CamelOwnableMock::TEST_CLASS_HASH, calldata); ( - DualCaseOwnable { contract_address: target }, - IOwnableCamelOnlyDispatcher { contract_address: target } + DualCaseOwnable { + contract_address: target + }, IOwnableCamelOnlyDispatcher { + contract_address: target + } ) } @@ -61,8 +64,11 @@ fn setup_ownable_panic() -> (DualCaseOwnable, DualCaseOwnable) { let snake_target = utils::deploy(SnakeOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); let camel_target = utils::deploy(CamelOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); ( - DualCaseOwnable { contract_address: snake_target }, - DualCaseOwnable { contract_address: camel_target } + DualCaseOwnable { + contract_address: snake_target + }, DualCaseOwnable { + contract_address: camel_target + } ) } diff --git a/src/openzeppelin/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo similarity index 100% rename from src/openzeppelin/tests/access/test_ownable.cairo rename to src/tests/access/test_ownable.cairo diff --git a/src/openzeppelin/tests/account.cairo b/src/tests/account.cairo similarity index 100% rename from src/openzeppelin/tests/account.cairo rename to src/tests/account.cairo diff --git a/src/openzeppelin/tests/account/test_account.cairo b/src/tests/account/test_account.cairo similarity index 100% rename from src/openzeppelin/tests/account/test_account.cairo rename to src/tests/account/test_account.cairo diff --git a/src/openzeppelin/tests/account/test_dual_account.cairo b/src/tests/account/test_dual_account.cairo similarity index 94% rename from src/openzeppelin/tests/account/test_dual_account.cairo rename to src/tests/account/test_dual_account.cairo index 76ea9fb99..c1178b22a 100644 --- a/src/openzeppelin/tests/account/test_dual_account.cairo +++ b/src/tests/account/test_dual_account.cairo @@ -30,8 +30,11 @@ fn setup_snake() -> (DualCaseAccount, AccountABIDispatcher) { let mut calldata = array![PUBLIC_KEY]; let target = utils::deploy(SnakeAccountMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccount { contract_address: target }, - AccountABIDispatcher { contract_address: target } + DualCaseAccount { + contract_address: target + }, AccountABIDispatcher { + contract_address: target + } ) } @@ -39,8 +42,11 @@ fn setup_camel() -> (DualCaseAccount, AccountCamelABIDispatcher) { let mut calldata = array![PUBLIC_KEY]; let target = utils::deploy(CamelAccountMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccount { contract_address: target }, - AccountCamelABIDispatcher { contract_address: target } + DualCaseAccount { + contract_address: target + }, AccountCamelABIDispatcher { + contract_address: target + } ) } @@ -54,8 +60,11 @@ fn setup_account_panic() -> (DualCaseAccount, DualCaseAccount) { let snake_target = utils::deploy(SnakeAccountPanicMock::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelAccountPanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseAccount { contract_address: snake_target }, - DualCaseAccount { contract_address: camel_target } + DualCaseAccount { + contract_address: snake_target + }, DualCaseAccount { + contract_address: camel_target + } ) } diff --git a/src/openzeppelin/tests/introspection.cairo b/src/tests/introspection.cairo similarity index 100% rename from src/openzeppelin/tests/introspection.cairo rename to src/tests/introspection.cairo diff --git a/src/openzeppelin/tests/introspection/test_dual_src5.cairo b/src/tests/introspection/test_dual_src5.cairo similarity index 94% rename from src/openzeppelin/tests/introspection/test_dual_src5.cairo rename to src/tests/introspection/test_dual_src5.cairo index 4e47773cc..629cd4977 100644 --- a/src/openzeppelin/tests/introspection/test_dual_src5.cairo +++ b/src/tests/introspection/test_dual_src5.cairo @@ -39,8 +39,11 @@ fn setup_src5_panic() -> (DualCaseSRC5, DualCaseSRC5) { let snake_target = utils::deploy(SnakeSRC5PanicMock::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelSRC5PanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseSRC5 { contract_address: snake_target }, - DualCaseSRC5 { contract_address: camel_target } + DualCaseSRC5 { + contract_address: snake_target + }, DualCaseSRC5 { + contract_address: camel_target + } ) } diff --git a/src/openzeppelin/tests/introspection/test_src5.cairo b/src/tests/introspection/test_src5.cairo similarity index 100% rename from src/openzeppelin/tests/introspection/test_src5.cairo rename to src/tests/introspection/test_src5.cairo diff --git a/src/openzeppelin/tests/mocks.cairo b/src/tests/mocks.cairo similarity index 100% rename from src/openzeppelin/tests/mocks.cairo rename to src/tests/mocks.cairo diff --git a/src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo b/src/tests/mocks/accesscontrol_panic_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/accesscontrol_panic_mock.cairo rename to src/tests/mocks/accesscontrol_panic_mock.cairo diff --git a/src/openzeppelin/tests/mocks/account_panic_mock.cairo b/src/tests/mocks/account_panic_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/account_panic_mock.cairo rename to src/tests/mocks/account_panic_mock.cairo diff --git a/src/openzeppelin/tests/mocks/camel20_mock.cairo b/src/tests/mocks/camel20_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/camel20_mock.cairo rename to src/tests/mocks/camel20_mock.cairo diff --git a/src/openzeppelin/tests/mocks/camel721_mock.cairo b/src/tests/mocks/camel721_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/camel721_mock.cairo rename to src/tests/mocks/camel721_mock.cairo diff --git a/src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo b/src/tests/mocks/camel_accesscontrol_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/camel_accesscontrol_mock.cairo rename to src/tests/mocks/camel_accesscontrol_mock.cairo diff --git a/src/openzeppelin/tests/mocks/camel_account_mock.cairo b/src/tests/mocks/camel_account_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/camel_account_mock.cairo rename to src/tests/mocks/camel_account_mock.cairo diff --git a/src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo b/src/tests/mocks/dual721_receiver_mocks.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/dual721_receiver_mocks.cairo rename to src/tests/mocks/dual721_receiver_mocks.cairo diff --git a/src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo b/src/tests/mocks/dual_ownable_mocks.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/dual_ownable_mocks.cairo rename to src/tests/mocks/dual_ownable_mocks.cairo diff --git a/src/openzeppelin/tests/mocks/erc20_panic.cairo b/src/tests/mocks/erc20_panic.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/erc20_panic.cairo rename to src/tests/mocks/erc20_panic.cairo diff --git a/src/openzeppelin/tests/mocks/erc721_panic_mock.cairo b/src/tests/mocks/erc721_panic_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/erc721_panic_mock.cairo rename to src/tests/mocks/erc721_panic_mock.cairo diff --git a/src/openzeppelin/tests/mocks/erc721_receiver.cairo b/src/tests/mocks/erc721_receiver.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/erc721_receiver.cairo rename to src/tests/mocks/erc721_receiver.cairo diff --git a/src/openzeppelin/tests/mocks/non_implementing_mock.cairo b/src/tests/mocks/non_implementing_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/non_implementing_mock.cairo rename to src/tests/mocks/non_implementing_mock.cairo diff --git a/src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo b/src/tests/mocks/reentrancy_attacker_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/reentrancy_attacker_mock.cairo rename to src/tests/mocks/reentrancy_attacker_mock.cairo diff --git a/src/openzeppelin/tests/mocks/reentrancy_mock.cairo b/src/tests/mocks/reentrancy_mock.cairo similarity index 95% rename from src/openzeppelin/tests/mocks/reentrancy_mock.cairo rename to src/tests/mocks/reentrancy_mock.cairo index 0850954c5..718a7db39 100644 --- a/src/openzeppelin/tests/mocks/reentrancy_mock.cairo +++ b/src/tests/mocks/reentrancy_mock.cairo @@ -72,8 +72,9 @@ mod ReentrancyMock { if n != 0 { self.count(); let this: ContractAddress = get_contract_address(); - IReentrancyGuardedDispatcher { contract_address: this } - .count_external_recursive(n - 1) + IReentrancyGuardedDispatcher { + contract_address: this + }.count_external_recursive(n - 1) } ReentrancyGuard::InternalImpl::end(ref unsafe_state); diff --git a/src/openzeppelin/tests/mocks/snake20_mock.cairo b/src/tests/mocks/snake20_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/snake20_mock.cairo rename to src/tests/mocks/snake20_mock.cairo diff --git a/src/openzeppelin/tests/mocks/snake721_mock.cairo b/src/tests/mocks/snake721_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/snake721_mock.cairo rename to src/tests/mocks/snake721_mock.cairo diff --git a/src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo b/src/tests/mocks/snake_accesscontrol_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/snake_accesscontrol_mock.cairo rename to src/tests/mocks/snake_accesscontrol_mock.cairo diff --git a/src/openzeppelin/tests/mocks/snake_account_mock.cairo b/src/tests/mocks/snake_account_mock.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/snake_account_mock.cairo rename to src/tests/mocks/snake_account_mock.cairo diff --git a/src/openzeppelin/tests/mocks/src5_mocks.cairo b/src/tests/mocks/src5_mocks.cairo similarity index 100% rename from src/openzeppelin/tests/mocks/src5_mocks.cairo rename to src/tests/mocks/src5_mocks.cairo diff --git a/src/openzeppelin/tests/security.cairo b/src/tests/security.cairo similarity index 100% rename from src/openzeppelin/tests/security.cairo rename to src/tests/security.cairo diff --git a/src/openzeppelin/tests/security/test_initializable.cairo b/src/tests/security/test_initializable.cairo similarity index 100% rename from src/openzeppelin/tests/security/test_initializable.cairo rename to src/tests/security/test_initializable.cairo diff --git a/src/openzeppelin/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo similarity index 100% rename from src/openzeppelin/tests/security/test_pausable.cairo rename to src/tests/security/test_pausable.cairo diff --git a/src/openzeppelin/tests/security/test_reentrancyguard.cairo b/src/tests/security/test_reentrancyguard.cairo similarity index 100% rename from src/openzeppelin/tests/security/test_reentrancyguard.cairo rename to src/tests/security/test_reentrancyguard.cairo diff --git a/src/openzeppelin/tests/token.cairo b/src/tests/token.cairo similarity index 100% rename from src/openzeppelin/tests/token.cairo rename to src/tests/token.cairo diff --git a/src/openzeppelin/tests/token/test_dual20.cairo b/src/tests/token/test_dual20.cairo similarity index 100% rename from src/openzeppelin/tests/token/test_dual20.cairo rename to src/tests/token/test_dual20.cairo diff --git a/src/openzeppelin/tests/token/test_dual721.cairo b/src/tests/token/test_dual721.cairo similarity index 98% rename from src/openzeppelin/tests/token/test_dual721.cairo rename to src/tests/token/test_dual721.cairo index dfaa53bad..8ff48f036 100644 --- a/src/openzeppelin/tests/token/test_dual721.cairo +++ b/src/tests/token/test_dual721.cairo @@ -76,8 +76,11 @@ fn setup_camel() -> (DualCaseERC721, IERC721CamelOnlyDispatcher) { set_caller_address(OWNER()); let target = utils::deploy(CamelERC721Mock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721 { contract_address: target }, - IERC721CamelOnlyDispatcher { contract_address: target } + DualCaseERC721 { + contract_address: target + }, IERC721CamelOnlyDispatcher { + contract_address: target + } ) } @@ -91,8 +94,11 @@ fn setup_erc721_panic() -> (DualCaseERC721, DualCaseERC721) { let snake_target = utils::deploy(SnakeERC721PanicMock::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelERC721PanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseERC721 { contract_address: snake_target }, - DualCaseERC721 { contract_address: camel_target } + DualCaseERC721 { + contract_address: snake_target + }, DualCaseERC721 { + contract_address: camel_target + } ) } diff --git a/src/openzeppelin/tests/token/test_dual721_receiver.cairo b/src/tests/token/test_dual721_receiver.cairo similarity index 89% rename from src/openzeppelin/tests/token/test_dual721_receiver.cairo rename to src/tests/token/test_dual721_receiver.cairo index a3197dddc..ef02380a9 100644 --- a/src/openzeppelin/tests/token/test_dual721_receiver.cairo +++ b/src/tests/token/test_dual721_receiver.cairo @@ -49,8 +49,11 @@ fn setup_snake() -> (DualCaseERC721Receiver, IERC721ReceiverDispatcher) { let mut calldata = ArrayTrait::new(); let target = utils::deploy(SnakeERC721ReceiverMock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721Receiver { contract_address: target }, - IERC721ReceiverDispatcher { contract_address: target } + DualCaseERC721Receiver { + contract_address: target + }, IERC721ReceiverDispatcher { + contract_address: target + } ) } @@ -58,8 +61,11 @@ fn setup_camel() -> (DualCaseERC721Receiver, IERC721ReceiverCamelDispatcher) { let mut calldata = ArrayTrait::new(); let target = utils::deploy(CamelERC721ReceiverMock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721Receiver { contract_address: target }, - IERC721ReceiverCamelDispatcher { contract_address: target } + DualCaseERC721Receiver { + contract_address: target + }, IERC721ReceiverCamelDispatcher { + contract_address: target + } ) } @@ -77,8 +83,11 @@ fn setup_erc721_receiver_panic() -> (DualCaseERC721Receiver, DualCaseERC721Recei CamelERC721ReceiverPanicMock::TEST_CLASS_HASH, ArrayTrait::new() ); ( - DualCaseERC721Receiver { contract_address: snake_target }, - DualCaseERC721Receiver { contract_address: camel_target } + DualCaseERC721Receiver { + contract_address: snake_target + }, DualCaseERC721Receiver { + contract_address: camel_target + } ) } diff --git a/src/openzeppelin/tests/token/test_erc20.cairo b/src/tests/token/test_erc20.cairo similarity index 100% rename from src/openzeppelin/tests/token/test_erc20.cairo rename to src/tests/token/test_erc20.cairo diff --git a/src/openzeppelin/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo similarity index 100% rename from src/openzeppelin/tests/token/test_erc721.cairo rename to src/tests/token/test_erc721.cairo diff --git a/src/openzeppelin/tests/utils.cairo b/src/tests/utils.cairo similarity index 100% rename from src/openzeppelin/tests/utils.cairo rename to src/tests/utils.cairo diff --git a/src/openzeppelin/token.cairo b/src/token.cairo similarity index 100% rename from src/openzeppelin/token.cairo rename to src/token.cairo diff --git a/src/openzeppelin/token/erc20.cairo b/src/token/erc20.cairo similarity index 100% rename from src/openzeppelin/token/erc20.cairo rename to src/token/erc20.cairo diff --git a/src/openzeppelin/token/erc20/dual20.cairo b/src/token/erc20/dual20.cairo similarity index 100% rename from src/openzeppelin/token/erc20/dual20.cairo rename to src/token/erc20/dual20.cairo diff --git a/src/openzeppelin/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo similarity index 100% rename from src/openzeppelin/token/erc20/erc20.cairo rename to src/token/erc20/erc20.cairo diff --git a/src/openzeppelin/token/erc20/interface.cairo b/src/token/erc20/interface.cairo similarity index 100% rename from src/openzeppelin/token/erc20/interface.cairo rename to src/token/erc20/interface.cairo diff --git a/src/openzeppelin/token/erc721.cairo b/src/token/erc721.cairo similarity index 100% rename from src/openzeppelin/token/erc721.cairo rename to src/token/erc721.cairo diff --git a/src/openzeppelin/token/erc721/dual721.cairo b/src/token/erc721/dual721.cairo similarity index 100% rename from src/openzeppelin/token/erc721/dual721.cairo rename to src/token/erc721/dual721.cairo diff --git a/src/openzeppelin/token/erc721/dual721_receiver.cairo b/src/token/erc721/dual721_receiver.cairo similarity index 100% rename from src/openzeppelin/token/erc721/dual721_receiver.cairo rename to src/token/erc721/dual721_receiver.cairo diff --git a/src/openzeppelin/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo similarity index 98% rename from src/openzeppelin/token/erc721/erc721.cairo rename to src/token/erc721/erc721.cairo index 4e2a1bb80..c2429a676 100644 --- a/src/openzeppelin/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -342,9 +342,12 @@ mod ERC721 { fn _check_on_erc721_received( from: ContractAddress, to: ContractAddress, token_id: u256, data: Span ) -> bool { - if (DualCaseSRC5 { contract_address: to } - .supports_interface(interface::IERC721_RECEIVER_ID)) { - DualCaseERC721Receiver { contract_address: to } + if (DualCaseSRC5 { + contract_address: to + }.supports_interface(interface::IERC721_RECEIVER_ID)) { + DualCaseERC721Receiver { + contract_address: to + } .on_erc721_received( get_caller_address(), from, token_id, data ) == interface::IERC721_RECEIVER_ID diff --git a/src/openzeppelin/token/erc721/interface.cairo b/src/token/erc721/interface.cairo similarity index 100% rename from src/openzeppelin/token/erc721/interface.cairo rename to src/token/erc721/interface.cairo diff --git a/src/openzeppelin/utils.cairo b/src/utils.cairo similarity index 100% rename from src/openzeppelin/utils.cairo rename to src/utils.cairo diff --git a/src/openzeppelin/utils/constants.cairo b/src/utils/constants.cairo similarity index 100% rename from src/openzeppelin/utils/constants.cairo rename to src/utils/constants.cairo diff --git a/src/openzeppelin/utils/selectors.cairo b/src/utils/selectors.cairo similarity index 100% rename from src/openzeppelin/utils/selectors.cairo rename to src/utils/selectors.cairo diff --git a/src/openzeppelin/utils/serde.cairo b/src/utils/serde.cairo similarity index 100% rename from src/openzeppelin/utils/serde.cairo rename to src/utils/serde.cairo diff --git a/src/openzeppelin/utils/unwrap_and_cast.cairo b/src/utils/unwrap_and_cast.cairo similarity index 100% rename from src/openzeppelin/utils/unwrap_and_cast.cairo rename to src/utils/unwrap_and_cast.cairo From 177ad630dcf98d44428a9ddb8c46e3193a791018 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 4 Aug 2023 10:06:36 -0400 Subject: [PATCH 075/124] Add spdx (#684) * add spdx * add spdx --- src/access/accesscontrol/accesscontrol.cairo | 3 +++ src/access/accesscontrol/dual_accesscontrol.cairo | 3 +++ src/access/accesscontrol/interface.cairo | 3 +++ src/access/ownable/dual_ownable.cairo | 3 +++ src/access/ownable/interface.cairo | 3 +++ src/access/ownable/ownable.cairo | 3 +++ src/account/account.cairo | 3 +++ src/account/dual_account.cairo | 3 +++ src/account/interface.cairo | 3 +++ src/introspection/dual_src5.cairo | 3 +++ src/introspection/interface.cairo | 3 +++ src/introspection/src5.cairo | 3 +++ src/security/initializable.cairo | 3 +++ src/security/pausable.cairo | 3 +++ src/security/reentrancyguard.cairo | 3 +++ src/token/erc20/dual20.cairo | 3 +++ src/token/erc20/erc20.cairo | 3 +++ src/token/erc20/interface.cairo | 3 +++ src/token/erc721/dual721.cairo | 3 +++ src/token/erc721/dual721_receiver.cairo | 3 +++ src/token/erc721/erc721.cairo | 3 +++ src/token/erc721/interface.cairo | 3 +++ src/utils.cairo | 3 +++ src/utils/constants.cairo | 3 +++ src/utils/selectors.cairo | 3 +++ src/utils/serde.cairo | 3 +++ src/utils/unwrap_and_cast.cairo | 3 +++ 27 files changed, 81 insertions(+) diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index 78d245945..c1f85d985 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (access/accesscontrol/accesscontrol.cairo) + #[starknet::contract] mod AccessControl { use starknet::ContractAddress; diff --git a/src/access/accesscontrol/dual_accesscontrol.cairo b/src/access/accesscontrol/dual_accesscontrol.cairo index 49367b2e5..711413022 100644 --- a/src/access/accesscontrol/dual_accesscontrol.cairo +++ b/src/access/accesscontrol/dual_accesscontrol.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (access/accesscontrol/dual_accesscontrol.cairo) + use array::ArrayTrait; use starknet::ContractAddress; use starknet::SyscallResultTrait; diff --git a/src/access/accesscontrol/interface.cairo b/src/access/accesscontrol/interface.cairo index 50adbddf7..1a2f0a59b 100644 --- a/src/access/accesscontrol/interface.cairo +++ b/src/access/accesscontrol/interface.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (access/accesscontrol/interface.cairo) + use starknet::ContractAddress; const IACCESSCONTROL_ID: felt252 = diff --git a/src/access/ownable/dual_ownable.cairo b/src/access/ownable/dual_ownable.cairo index 583d96ffe..ccff1582c 100644 --- a/src/access/ownable/dual_ownable.cairo +++ b/src/access/ownable/dual_ownable.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/dual_ownable.cairo) + use array::SpanTrait; use array::ArrayTrait; use core::result::ResultTrait; diff --git a/src/access/ownable/interface.cairo b/src/access/ownable/interface.cairo index 4641093dc..7047ffcf8 100644 --- a/src/access/ownable/interface.cairo +++ b/src/access/ownable/interface.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/interface.cairo) + use starknet::ContractAddress; #[starknet::interface] diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index a7670a100..b249d7528 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/ownable.cairo) + #[starknet::contract] mod Ownable { use openzeppelin::access::ownable::interface; diff --git a/src/account/account.cairo b/src/account/account.cairo index 21b2d79d7..56204122e 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (account/account.cairo) + use array::ArrayTrait; use array::SpanTrait; use option::OptionTrait; diff --git a/src/account/dual_account.cairo b/src/account/dual_account.cairo index ee4e1c0b6..a55600814 100644 --- a/src/account/dual_account.cairo +++ b/src/account/dual_account.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (account/dual_account.cairo) + use array::ArrayTrait; use array::SpanTrait; use starknet::ContractAddress; diff --git a/src/account/interface.cairo b/src/account/interface.cairo index e557b6dec..fdf4563a7 100644 --- a/src/account/interface.cairo +++ b/src/account/interface.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (account/interface.cairo) + use array::ArrayTrait; use array::SpanTrait; use starknet::account::Call; diff --git a/src/introspection/dual_src5.cairo b/src/introspection/dual_src5.cairo index ca6868cae..708bc9ecc 100644 --- a/src/introspection/dual_src5.cairo +++ b/src/introspection/dual_src5.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (introspection/dual_src5.cairo) + use array::ArrayTrait; use starknet::ContractAddress; diff --git a/src/introspection/interface.cairo b/src/introspection/interface.cairo index 68909245c..831071bce 100644 --- a/src/introspection/interface.cairo +++ b/src/introspection/interface.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (introspection/interface.cairo) + const ISRC5_ID: felt252 = 0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055; #[starknet::interface] diff --git a/src/introspection/src5.cairo b/src/introspection/src5.cairo index 2f9a9389e..75ad1d3b2 100644 --- a/src/introspection/src5.cairo +++ b/src/introspection/src5.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (introspection/src5.cairo) + #[starknet::contract] mod SRC5 { use openzeppelin::introspection::interface; diff --git a/src/security/initializable.cairo b/src/security/initializable.cairo index 1be5ab059..e0e7e658f 100644 --- a/src/security/initializable.cairo +++ b/src/security/initializable.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (security/initializable.cairo) + #[starknet::contract] mod Initializable { #[storage] diff --git a/src/security/pausable.cairo b/src/security/pausable.cairo index 66e159181..73480add7 100644 --- a/src/security/pausable.cairo +++ b/src/security/pausable.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (security/pausable.cairo) + #[starknet::interface] trait IPausable { fn is_paused(self: @TState) -> bool; diff --git a/src/security/reentrancyguard.cairo b/src/security/reentrancyguard.cairo index 17a2e8d9c..f08713776 100644 --- a/src/security/reentrancyguard.cairo +++ b/src/security/reentrancyguard.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (security/reentrancyguard.cairo) + #[starknet::contract] mod ReentrancyGuard { use starknet::get_caller_address; diff --git a/src/token/erc20/dual20.cairo b/src/token/erc20/dual20.cairo index 848f53363..1a867c0f7 100644 --- a/src/token/erc20/dual20.cairo +++ b/src/token/erc20/dual20.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (token/erc20/dual20.cairo) + use array::ArrayTrait; use starknet::call_contract_syscall; use starknet::ContractAddress; diff --git a/src/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo index f83a965a8..ebdc5af0f 100644 --- a/src/token/erc20/erc20.cairo +++ b/src/token/erc20/erc20.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (token/erc20/erc20.cairo) + #[starknet::contract] mod ERC20 { use integer::BoundedInt; diff --git a/src/token/erc20/interface.cairo b/src/token/erc20/interface.cairo index 8f86d6d75..8f0526299 100644 --- a/src/token/erc20/interface.cairo +++ b/src/token/erc20/interface.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (token/erc20/interface.cairo) + use starknet::ContractAddress; #[starknet::interface] diff --git a/src/token/erc721/dual721.cairo b/src/token/erc721/dual721.cairo index 55655d9c7..8d4ce8ffa 100644 --- a/src/token/erc721/dual721.cairo +++ b/src/token/erc721/dual721.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/dual721.cairo) + use array::ArrayTrait; use starknet::ContractAddress; use starknet::SyscallResultTrait; diff --git a/src/token/erc721/dual721_receiver.cairo b/src/token/erc721/dual721_receiver.cairo index 6c13fc931..55029bdd1 100644 --- a/src/token/erc721/dual721_receiver.cairo +++ b/src/token/erc721/dual721_receiver.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/dual721_receiver.cairo) + use array::ArrayTrait; use starknet::ContractAddress; use starknet::SyscallResultTrait; diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index c2429a676..0ea2598c7 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/erc721.cairo) + use starknet::ContractAddress; #[starknet::contract] diff --git a/src/token/erc721/interface.cairo b/src/token/erc721/interface.cairo index 5e22d6f07..44ff80a5e 100644 --- a/src/token/erc721/interface.cairo +++ b/src/token/erc721/interface.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/interface.cairo) + use starknet::ContractAddress; use array::SpanTrait; diff --git a/src/utils.cairo b/src/utils.cairo index e8d356c77..721dfdfee 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (utils.cairo) + mod constants; mod selectors; mod serde; diff --git a/src/utils/constants.cairo b/src/utils/constants.cairo index 9d2414bac..0747ddb3c 100644 --- a/src/utils/constants.cairo +++ b/src/utils/constants.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (utils/constants.cairo) + // // Interface ids // diff --git a/src/utils/selectors.cairo b/src/utils/selectors.cairo index ee89772f9..1695e17cb 100644 --- a/src/utils/selectors.cairo +++ b/src/utils/selectors.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (utils/selectors.cairo) + // // AccessControl // diff --git a/src/utils/serde.cairo b/src/utils/serde.cairo index 1b3ea8cd8..23fdad21b 100644 --- a/src/utils/serde.cairo +++ b/src/utils/serde.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (utils/serde.cairo) + use serde::Serde; trait SerializedAppend { diff --git a/src/utils/unwrap_and_cast.cairo b/src/utils/unwrap_and_cast.cairo index 0e3959664..185242dc1 100644 --- a/src/utils/unwrap_and_cast.cairo +++ b/src/utils/unwrap_and_cast.cairo @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (utils/unwrap_and_cast.cairo) + use array::SpanTrait; use option::OptionTrait; use starknet::ContractAddress; From 495ed8a66cc6f3e6ca7eb8cb741ff4eba2265807 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 4 Aug 2023 17:43:46 +0200 Subject: [PATCH 076/124] feat: sort imports (#679) --- src/access/accesscontrol.cairo | 4 +- src/access/accesscontrol/accesscontrol.cairo | 4 +- .../accesscontrol/dual_accesscontrol.cairo | 6 +-- src/access/ownable.cairo | 6 +-- src/access/ownable/dual_ownable.cairo | 14 +++---- src/account.cairo | 6 +-- src/account/account.cairo | 14 +++---- src/account/dual_account.cairo | 7 ++-- src/account/interface.cairo | 2 +- src/introspection.cairo | 2 +- src/introspection/dual_src5.cairo | 5 +-- src/security.cairo | 4 +- src/tests/access.cairo | 2 +- src/tests/access/test_accesscontrol.cairo | 12 +++--- .../access/test_dual_accesscontrol.cairo | 21 +++++------ src/tests/access/test_dual_ownable.cairo | 23 ++++++------ src/tests/access/test_ownable.cairo | 10 ++--- src/tests/account/test_account.cairo | 15 ++++---- src/tests/account/test_dual_account.cairo | 11 +++--- src/tests/introspection.cairo | 2 +- src/tests/introspection/test_dual_src5.cairo | 16 ++++---- src/tests/introspection/test_src5.cairo | 6 +-- src/tests/mocks.cairo | 24 ++++++------ src/tests/mocks/camel20_mock.cairo | 2 +- src/tests/mocks/camel721_mock.cairo | 6 +-- .../mocks/camel_accesscontrol_mock.cairo | 6 +-- src/tests/mocks/dual721_receiver_mocks.cairo | 2 +- src/tests/mocks/erc721_receiver.cairo | 9 ++--- .../mocks/reentrancy_attacker_mock.cairo | 4 +- src/tests/mocks/reentrancy_mock.cairo | 4 +- src/tests/mocks/snake20_mock.cairo | 2 +- src/tests/mocks/snake721_mock.cairo | 6 +-- .../mocks/snake_accesscontrol_mock.cairo | 6 +-- src/tests/security.cairo | 2 +- src/tests/security/test_initializable.cairo | 2 +- src/tests/security/test_pausable.cairo | 4 +- src/tests/security/test_reentrancyguard.cairo | 6 +-- src/tests/token.cairo | 2 +- src/tests/token/test_dual20.cairo | 11 +++--- src/tests/token/test_dual721.cairo | 30 +++++++-------- src/tests/token/test_dual721_receiver.cairo | 26 ++++++------- src/tests/token/test_erc20.cairo | 9 ++--- src/tests/token/test_erc721.cairo | 37 +++++++++---------- src/tests/utils.cairo | 2 +- src/token/erc20.cairo | 2 +- src/token/erc20/dual20.cairo | 11 +++--- src/token/erc20/erc20.cairo | 5 +-- src/token/erc721/dual721.cairo | 8 ++-- src/token/erc721/dual721_receiver.cairo | 8 ++-- src/token/erc721/erc721.cairo | 9 ++--- src/token/erc721/interface.cairo | 2 +- src/utils.cairo | 2 +- src/utils/unwrap_and_cast.cairo | 4 +- 53 files changed, 216 insertions(+), 229 deletions(-) diff --git a/src/access/accesscontrol.cairo b/src/access/accesscontrol.cairo index 025142e68..6c2df16c2 100644 --- a/src/access/accesscontrol.cairo +++ b/src/access/accesscontrol.cairo @@ -1,7 +1,7 @@ mod accesscontrol; -use accesscontrol::AccessControl; - mod dual_accesscontrol; mod interface; +use accesscontrol::AccessControl; + const DEFAULT_ADMIN_ROLE: felt252 = 0; diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index c1f85d985..718137ecf 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -3,12 +3,12 @@ #[starknet::contract] mod AccessControl { - use starknet::ContractAddress; - use starknet::get_caller_address; use openzeppelin::access::accesscontrol::interface; use openzeppelin::introspection::interface::ISRC5; use openzeppelin::introspection::interface::ISRC5Camel; use openzeppelin::introspection::src5::SRC5; + use starknet::ContractAddress; + use starknet::get_caller_address; #[storage] struct Storage { diff --git a/src/access/accesscontrol/dual_accesscontrol.cairo b/src/access/accesscontrol/dual_accesscontrol.cairo index 711413022..eb086840e 100644 --- a/src/access/accesscontrol/dual_accesscontrol.cairo +++ b/src/access/accesscontrol/dual_accesscontrol.cairo @@ -2,14 +2,14 @@ // OpenZeppelin Contracts for Cairo v0.7.0 (access/accesscontrol/dual_accesscontrol.cairo) use array::ArrayTrait; -use starknet::ContractAddress; -use starknet::SyscallResultTrait; use openzeppelin::utils::Felt252TryIntoBool; +use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::try_selector_with_fallback; -use openzeppelin::utils::UnwrapAndCast; +use starknet::ContractAddress; +use starknet::SyscallResultTrait; #[derive(Copy, Drop)] struct DualCaseAccessControl { diff --git a/src/access/ownable.cairo b/src/access/ownable.cairo index 7b8e812b9..4c70a8a9d 100644 --- a/src/access/ownable.cairo +++ b/src/access/ownable.cairo @@ -1,5 +1,5 @@ +mod dual_ownable; +mod interface; mod ownable; -use ownable::Ownable; -mod interface; -mod dual_ownable; +use ownable::Ownable; diff --git a/src/access/ownable/dual_ownable.cairo b/src/access/ownable/dual_ownable.cairo index ccff1582c..03d2ba51b 100644 --- a/src/access/ownable/dual_ownable.cairo +++ b/src/access/ownable/dual_ownable.cairo @@ -1,9 +1,15 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/dual_ownable.cairo) -use array::SpanTrait; use array::ArrayTrait; +use array::SpanTrait; use core::result::ResultTrait; + +use openzeppelin::utils::Felt252TryIntoBool; +use openzeppelin::utils::UnwrapAndCast; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::try_selector_with_fallback; use option::OptionTrait; use starknet::ContractAddress; use starknet::Felt252TryIntoContractAddress; @@ -11,12 +17,6 @@ use starknet::SyscallResultTrait; use starknet::call_contract_syscall; use traits::TryInto; -use openzeppelin::utils::Felt252TryIntoBool; -use openzeppelin::utils::selectors; -use openzeppelin::utils::serde::SerializedAppend; -use openzeppelin::utils::try_selector_with_fallback; -use openzeppelin::utils::UnwrapAndCast; - #[derive(Copy, Drop)] struct DualCaseOwnable { contract_address: ContractAddress diff --git a/src/account.cairo b/src/account.cairo index d8f6cab7a..1ca2c1578 100644 --- a/src/account.cairo +++ b/src/account.cairo @@ -3,9 +3,9 @@ mod dual_account; mod interface; use account::Account; -use account::TRANSACTION_VERSION; use account::QUERY_VERSION; -use interface::AccountCamelABIDispatcher; -use interface::AccountCamelABIDispatcherTrait; +use account::TRANSACTION_VERSION; use interface::AccountABIDispatcher; use interface::AccountABIDispatcherTrait; +use interface::AccountCamelABIDispatcher; +use interface::AccountCamelABIDispatcherTrait; diff --git a/src/account/account.cairo b/src/account/account.cairo index 56204122e..8d8105521 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -5,8 +5,8 @@ use array::ArrayTrait; use array::SpanTrait; use option::OptionTrait; use serde::Serde; -use starknet::account::Call; use starknet::ContractAddress; +use starknet::account::Call; const TRANSACTION_VERSION: felt252 = 1; @@ -25,24 +25,24 @@ trait PublicKeyCamelTrait { #[starknet::contract] mod Account { - use array::SpanTrait; use array::ArrayTrait; + use array::SpanTrait; use box::BoxTrait; use ecdsa::check_ecdsa_signature; - use option::OptionTrait; - use starknet::get_tx_info; - use starknet::get_caller_address; - use starknet::get_contract_address; - use zeroable::Zeroable; use openzeppelin::account::interface; use openzeppelin::introspection::interface::ISRC5; use openzeppelin::introspection::interface::ISRC5Camel; use openzeppelin::introspection::src5::SRC5; + use option::OptionTrait; + use starknet::get_caller_address; + use starknet::get_contract_address; + use starknet::get_tx_info; use super::Call; use super::QUERY_VERSION; use super::TRANSACTION_VERSION; + use zeroable::Zeroable; #[storage] struct Storage { diff --git a/src/account/dual_account.cairo b/src/account/dual_account.cairo index a55600814..9e4d321c8 100644 --- a/src/account/dual_account.cairo +++ b/src/account/dual_account.cairo @@ -3,13 +3,12 @@ use array::ArrayTrait; use array::SpanTrait; -use starknet::ContractAddress; -use starknet::SyscallResultTrait; - +use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::try_selector_with_fallback; -use openzeppelin::utils::UnwrapAndCast; +use starknet::ContractAddress; +use starknet::SyscallResultTrait; #[derive(Copy, Drop)] struct DualCaseAccount { diff --git a/src/account/interface.cairo b/src/account/interface.cairo index fdf4563a7..b9a5abbef 100644 --- a/src/account/interface.cairo +++ b/src/account/interface.cairo @@ -3,8 +3,8 @@ use array::ArrayTrait; use array::SpanTrait; -use starknet::account::Call; use starknet::ContractAddress; +use starknet::account::Call; const ISRC6_ID: felt252 = 0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd; diff --git a/src/introspection.cairo b/src/introspection.cairo index 184f921e7..5eb468c65 100644 --- a/src/introspection.cairo +++ b/src/introspection.cairo @@ -1,3 +1,3 @@ -mod src5; mod dual_src5; mod interface; +mod src5; diff --git a/src/introspection/dual_src5.cairo b/src/introspection/dual_src5.cairo index 708bc9ecc..48d7c9c68 100644 --- a/src/introspection/dual_src5.cairo +++ b/src/introspection/dual_src5.cairo @@ -2,11 +2,10 @@ // OpenZeppelin Contracts for Cairo v0.7.0 (introspection/dual_src5.cairo) use array::ArrayTrait; -use starknet::ContractAddress; - +use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::try_selector_with_fallback; -use openzeppelin::utils::UnwrapAndCast; +use starknet::ContractAddress; #[derive(Copy, Drop)] struct DualCaseSRC5 { diff --git a/src/security.cairo b/src/security.cairo index 45a9c998a..4713c3cff 100644 --- a/src/security.cairo +++ b/src/security.cairo @@ -1,3 +1,3 @@ -mod reentrancyguard; -mod pausable; mod initializable; +mod pausable; +mod reentrancyguard; diff --git a/src/tests/access.cairo b/src/tests/access.cairo index 149c62b59..2599d6d1f 100644 --- a/src/tests/access.cairo +++ b/src/tests/access.cairo @@ -1,4 +1,4 @@ mod test_accesscontrol; mod test_dual_accesscontrol; -mod test_ownable; mod test_dual_ownable; +mod test_ownable; diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index 704242309..86ef607e0 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -1,12 +1,12 @@ -use starknet::contract_address_const; -use starknet::ContractAddress; -use starknet::testing; -use openzeppelin::access::accesscontrol::AccessControl; -use openzeppelin::access::accesscontrol::AccessControl::InternalImpl; -use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; +use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; +use openzeppelin::access::accesscontrol::AccessControl::InternalImpl; +use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing; const ROLE: felt252 = 41; const OTHER_ROLE: felt252 = 42; diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index fb3c916d5..a20657902 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -1,23 +1,22 @@ use array::ArrayTrait; -use starknet::ContractAddress; -use starknet::contract_address_const; -use starknet::testing::set_contract_address; - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; -use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; -use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; -use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; -use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; -use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; -use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; use openzeppelin::tests::mocks::accesscontrol_panic_mock::CamelAccessControlPanicMock; +use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_contract_address; // // Constants diff --git a/src/tests/access/test_dual_ownable.cairo b/src/tests/access/test_dual_ownable.cairo index 470709dc6..380672757 100644 --- a/src/tests/access/test_dual_ownable.cairo +++ b/src/tests/access/test_dual_ownable.cairo @@ -1,22 +1,21 @@ -use starknet::ContractAddress; -use starknet::contract_address_const; -use starknet::testing::set_caller_address; -use starknet::testing::set_contract_address; -use zeroable::Zeroable; - -use openzeppelin::access::ownable::interface::IOwnableDispatcher; +use openzeppelin::access::ownable::dual_ownable::DualCaseOwnable; +use openzeppelin::access::ownable::dual_ownable::DualCaseOwnableTrait; use openzeppelin::access::ownable::interface::IOwnableCamelOnlyDispatcher; -use openzeppelin::access::ownable::interface::IOwnableDispatcherTrait; use openzeppelin::access::ownable::interface::IOwnableCamelOnlyDispatcherTrait; -use openzeppelin::access::ownable::dual_ownable::DualCaseOwnableTrait; -use openzeppelin::access::ownable::dual_ownable::DualCaseOwnable; -use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnableMock; +use openzeppelin::access::ownable::interface::IOwnableDispatcher; +use openzeppelin::access::ownable::interface::IOwnableDispatcherTrait; use openzeppelin::tests::mocks::dual_ownable_mocks::CamelOwnableMock; -use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnablePanicMock; use openzeppelin::tests::mocks::dual_ownable_mocks::CamelOwnablePanicMock; +use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnableMock; +use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnablePanicMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_caller_address; +use starknet::testing::set_contract_address; +use zeroable::Zeroable; // // Constants diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index 2b906dbed..d88d0f786 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -1,12 +1,12 @@ +use openzeppelin::access::ownable::Ownable::InternalImpl; +use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; +use openzeppelin::access::ownable::Ownable::OwnableImpl; +use openzeppelin::access::ownable::Ownable::_owner::InternalContractStateTrait; +use openzeppelin::access::ownable::Ownable; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; use zeroable::Zeroable; -use openzeppelin::access::ownable::Ownable; -use openzeppelin::access::ownable::Ownable::OwnableImpl; -use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; -use openzeppelin::access::ownable::Ownable::InternalImpl; -use openzeppelin::access::ownable::Ownable::_owner::InternalContractStateTrait; fn ZERO() -> ContractAddress { contract_address_const::<0>() diff --git a/src/tests/account/test_account.cairo b/src/tests/account/test_account.cairo index b5d9828f7..b2fe45ceb 100644 --- a/src/tests/account/test_account.cairo +++ b/src/tests/account/test_account.cairo @@ -1,18 +1,11 @@ use array::ArrayTrait; use core::traits::Into; -use option::OptionTrait; -use serde::Serde; -use starknet::account::Call; -use starknet::contract_address_const; -use starknet::ContractAddress; -use starknet::testing; - use openzeppelin::account::Account; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; -use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::account::QUERY_VERSION; use openzeppelin::account::TRANSACTION_VERSION; +use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::utils; use openzeppelin::token::erc20::ERC20; @@ -20,6 +13,12 @@ use openzeppelin::token::erc20::interface::IERC20Dispatcher; use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; +use option::OptionTrait; +use serde::Serde; +use starknet::ContractAddress; +use starknet::account::Call; +use starknet::contract_address_const; +use starknet::testing; // // Constants diff --git a/src/tests/account/test_dual_account.cairo b/src/tests/account/test_dual_account.cairo index c1178b22a..f38c308c5 100644 --- a/src/tests/account/test_dual_account.cairo +++ b/src/tests/account/test_dual_account.cairo @@ -1,11 +1,9 @@ -use starknet::testing; - -use openzeppelin::account::dual_account::DualCaseAccount; -use openzeppelin::account::dual_account::DualCaseAccountABI; -use openzeppelin::account::AccountCamelABIDispatcher; -use openzeppelin::account::AccountCamelABIDispatcherTrait; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; +use openzeppelin::account::AccountCamelABIDispatcher; +use openzeppelin::account::AccountCamelABIDispatcherTrait; +use openzeppelin::account::dual_account::DualCaseAccount; +use openzeppelin::account::dual_account::DualCaseAccountABI; use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::account::test_account::SIGNED_TX_DATA; use openzeppelin::tests::mocks::account_panic_mock::CamelAccountPanicMock; @@ -14,6 +12,7 @@ use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::snake_account_mock::SnakeAccountMock; use openzeppelin::tests::utils; +use starknet::testing; // // Constants diff --git a/src/tests/introspection.cairo b/src/tests/introspection.cairo index d46bcfe7d..010db98a8 100644 --- a/src/tests/introspection.cairo +++ b/src/tests/introspection.cairo @@ -1,2 +1,2 @@ -mod test_src5; mod test_dual_src5; +mod test_src5; diff --git a/src/tests/introspection/test_dual_src5.cairo b/src/tests/introspection/test_dual_src5.cairo index 629cd4977..84157605b 100644 --- a/src/tests/introspection/test_dual_src5.cairo +++ b/src/tests/introspection/test_dual_src5.cairo @@ -1,16 +1,16 @@ use array::ArrayTrait; -use openzeppelin::introspection::interface::ISRC5_ID; -use openzeppelin::introspection::interface::ISRC5Dispatcher; -use openzeppelin::introspection::interface::ISRC5DispatcherTrait; -use openzeppelin::introspection::interface::ISRC5CamelDispatcher; -use openzeppelin::introspection::interface::ISRC5CamelDispatcherTrait; use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; -use openzeppelin::tests::mocks::src5_mocks::SnakeSRC5Mock; +use openzeppelin::introspection::interface::ISRC5CamelDispatcher; +use openzeppelin::introspection::interface::ISRC5CamelDispatcherTrait; +use openzeppelin::introspection::interface::ISRC5Dispatcher; +use openzeppelin::introspection::interface::ISRC5DispatcherTrait; +use openzeppelin::introspection::interface::ISRC5_ID; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::src5_mocks::CamelSRC5Mock; -use openzeppelin::tests::mocks::src5_mocks::SnakeSRC5PanicMock; use openzeppelin::tests::mocks::src5_mocks::CamelSRC5PanicMock; -use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::mocks::src5_mocks::SnakeSRC5Mock; +use openzeppelin::tests::mocks::src5_mocks::SnakeSRC5PanicMock; use openzeppelin::tests::utils; // diff --git a/src/tests/introspection/test_src5.cairo b/src/tests/introspection/test_src5.cairo index 7b0ea5418..d81cf3e37 100644 --- a/src/tests/introspection/test_src5.cairo +++ b/src/tests/introspection/test_src5.cairo @@ -1,7 +1,7 @@ -use openzeppelin::introspection::src5::SRC5; -use openzeppelin::introspection::src5::SRC5::SRC5Impl; -use openzeppelin::introspection::src5::SRC5::InternalImpl; use openzeppelin::introspection::interface::ISRC5_ID; +use openzeppelin::introspection::src5::SRC5::InternalImpl; +use openzeppelin::introspection::src5::SRC5::SRC5Impl; +use openzeppelin::introspection::src5::SRC5; const OTHER_ID: felt252 = 0x12345678; diff --git a/src/tests/mocks.cairo b/src/tests/mocks.cairo index fd2e8f322..cb3112db1 100644 --- a/src/tests/mocks.cairo +++ b/src/tests/mocks.cairo @@ -1,19 +1,19 @@ -mod reentrancy_attacker_mock; -mod reentrancy_mock; -mod erc721_receiver; -mod erc721_panic_mock; -mod camel20_mock; -mod snake20_mock; -mod erc20_panic; mod accesscontrol_panic_mock; mod account_panic_mock; +mod camel20_mock; +mod camel721_mock; mod camel_accesscontrol_mock; mod camel_account_mock; -mod snake_accesscontrol_mock; -mod snake_account_mock; +mod dual721_receiver_mocks; mod dual_ownable_mocks; -mod snake721_mock; -mod camel721_mock; +mod erc20_panic; +mod erc721_panic_mock; +mod erc721_receiver; mod non_implementing_mock; -mod dual721_receiver_mocks; +mod reentrancy_attacker_mock; +mod reentrancy_mock; +mod snake20_mock; +mod snake721_mock; +mod snake_accesscontrol_mock; +mod snake_account_mock; mod src5_mocks; diff --git a/src/tests/mocks/camel20_mock.cairo b/src/tests/mocks/camel20_mock.cairo index 6eab0e06f..7c6e55637 100644 --- a/src/tests/mocks/camel20_mock.cairo +++ b/src/tests/mocks/camel20_mock.cairo @@ -1,7 +1,7 @@ #[starknet::contract] mod CamelERC20Mock { - use starknet::ContractAddress; use openzeppelin::token::erc20::ERC20; + use starknet::ContractAddress; #[storage] struct Storage {} diff --git a/src/tests/mocks/camel721_mock.cairo b/src/tests/mocks/camel721_mock.cairo index 553114f7e..9fcbbb248 100644 --- a/src/tests/mocks/camel721_mock.cairo +++ b/src/tests/mocks/camel721_mock.cairo @@ -1,10 +1,10 @@ #[starknet::contract] mod CamelERC721Mock { + use openzeppelin::token::erc721::ERC721::ERC721CamelOnlyImpl; + use openzeppelin::token::erc721::ERC721::InternalImpl; + use openzeppelin::token::erc721::ERC721; use starknet::ContractAddress; use starknet::get_caller_address; - use openzeppelin::token::erc721::ERC721; - use openzeppelin::token::erc721::ERC721::InternalImpl; - use openzeppelin::token::erc721::ERC721::ERC721CamelOnlyImpl; #[storage] struct Storage {} diff --git a/src/tests/mocks/camel_accesscontrol_mock.cairo b/src/tests/mocks/camel_accesscontrol_mock.cairo index dc0879a60..55835f50c 100644 --- a/src/tests/mocks/camel_accesscontrol_mock.cairo +++ b/src/tests/mocks/camel_accesscontrol_mock.cairo @@ -1,10 +1,10 @@ #[starknet::contract] mod CamelAccessControlMock { - use starknet::ContractAddress; - use starknet::get_caller_address; - use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; + use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use starknet::ContractAddress; + use starknet::get_caller_address; #[storage] struct Storage {} diff --git a/src/tests/mocks/dual721_receiver_mocks.cairo b/src/tests/mocks/dual721_receiver_mocks.cairo index 897918b68..a6e4f5f2a 100644 --- a/src/tests/mocks/dual721_receiver_mocks.cairo +++ b/src/tests/mocks/dual721_receiver_mocks.cairo @@ -1,6 +1,6 @@ use openzeppelin::introspection::src5::SRC5; -use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver::IERC721_RECEIVER_ID; +use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; #[starknet::contract] mod SnakeERC721ReceiverMock { diff --git a/src/tests/mocks/erc721_receiver.cairo b/src/tests/mocks/erc721_receiver.cairo index 673e4100e..9205f6d97 100644 --- a/src/tests/mocks/erc721_receiver.cairo +++ b/src/tests/mocks/erc721_receiver.cairo @@ -4,14 +4,13 @@ const FAILURE: felt252 = 456456; #[starknet::contract] mod ERC721Receiver { use array::SpanTrait; - use starknet::ContractAddress; - - use openzeppelin::token::erc721::interface::IERC721Receiver; - use openzeppelin::token::erc721::interface::IERC721ReceiverCamel; - use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; use openzeppelin::introspection::interface::ISRC5; use openzeppelin::introspection::interface::ISRC5Camel; use openzeppelin::introspection::src5::SRC5; + use openzeppelin::token::erc721::interface::IERC721Receiver; + use openzeppelin::token::erc721::interface::IERC721ReceiverCamel; + use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; + use starknet::ContractAddress; #[storage] struct Storage {} diff --git a/src/tests/mocks/reentrancy_attacker_mock.cairo b/src/tests/mocks/reentrancy_attacker_mock.cairo index 39560f902..6657cc145 100644 --- a/src/tests/mocks/reentrancy_attacker_mock.cairo +++ b/src/tests/mocks/reentrancy_attacker_mock.cairo @@ -5,10 +5,10 @@ trait IAttacker { #[starknet::contract] mod Attacker { - use starknet::ContractAddress; - use starknet::get_caller_address; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcherTrait; + use starknet::ContractAddress; + use starknet::get_caller_address; #[storage] struct Storage {} diff --git a/src/tests/mocks/reentrancy_mock.cairo b/src/tests/mocks/reentrancy_mock.cairo index 718a7db39..1204afa47 100644 --- a/src/tests/mocks/reentrancy_mock.cairo +++ b/src/tests/mocks/reentrancy_mock.cairo @@ -16,11 +16,11 @@ trait IReentrancyMock { #[starknet::contract] mod ReentrancyMock { - use starknet::ContractAddress; - use starknet::get_contract_address; use openzeppelin::security::reentrancyguard::ReentrancyGuard; use openzeppelin::tests::mocks::reentrancy_attacker_mock::IAttackerDispatcher; use openzeppelin::tests::mocks::reentrancy_attacker_mock::IAttackerDispatcherTrait; + use starknet::ContractAddress; + use starknet::get_contract_address; use super::IReentrancyGuardedDispatcher; use super::IReentrancyGuardedDispatcherTrait; diff --git a/src/tests/mocks/snake20_mock.cairo b/src/tests/mocks/snake20_mock.cairo index ba20d54b1..17c7b32ef 100644 --- a/src/tests/mocks/snake20_mock.cairo +++ b/src/tests/mocks/snake20_mock.cairo @@ -1,7 +1,7 @@ #[starknet::contract] mod SnakeERC20Mock { - use starknet::ContractAddress; use openzeppelin::token::erc20::ERC20; + use starknet::ContractAddress; #[storage] struct Storage {} diff --git a/src/tests/mocks/snake721_mock.cairo b/src/tests/mocks/snake721_mock.cairo index 13335a52f..6f1382c61 100644 --- a/src/tests/mocks/snake721_mock.cairo +++ b/src/tests/mocks/snake721_mock.cairo @@ -1,10 +1,10 @@ #[starknet::contract] mod SnakeERC721Mock { + use openzeppelin::token::erc721::ERC721::ERC721Impl; + use openzeppelin::token::erc721::ERC721::InternalImpl; + use openzeppelin::token::erc721::ERC721; use starknet::ContractAddress; use starknet::get_caller_address; - use openzeppelin::token::erc721::ERC721; - use openzeppelin::token::erc721::ERC721::InternalImpl; - use openzeppelin::token::erc721::ERC721::ERC721Impl; #[storage] struct Storage {} diff --git a/src/tests/mocks/snake_accesscontrol_mock.cairo b/src/tests/mocks/snake_accesscontrol_mock.cairo index 1d69feaec..48b291979 100644 --- a/src/tests/mocks/snake_accesscontrol_mock.cairo +++ b/src/tests/mocks/snake_accesscontrol_mock.cairo @@ -1,10 +1,10 @@ #[starknet::contract] mod SnakeAccessControlMock { - use starknet::ContractAddress; - use starknet::get_caller_address; - use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; + use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use starknet::ContractAddress; + use starknet::get_caller_address; #[storage] struct Storage {} diff --git a/src/tests/security.cairo b/src/tests/security.cairo index 1efdf53c8..35c30a0e8 100644 --- a/src/tests/security.cairo +++ b/src/tests/security.cairo @@ -1,3 +1,3 @@ mod test_initializable; -mod test_reentrancyguard; mod test_pausable; +mod test_reentrancyguard; diff --git a/src/tests/security/test_initializable.cairo b/src/tests/security/test_initializable.cairo index 86bf68fbc..66d2b89dc 100644 --- a/src/tests/security/test_initializable.cairo +++ b/src/tests/security/test_initializable.cairo @@ -1,5 +1,5 @@ -use openzeppelin::security::initializable::Initializable; use openzeppelin::security::initializable::Initializable::InternalImpl; +use openzeppelin::security::initializable::Initializable; fn STATE() -> Initializable::ContractState { Initializable::contract_state_for_testing() diff --git a/src/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo index 79bafced6..ac84fedc2 100644 --- a/src/tests/security/test_pausable.cairo +++ b/src/tests/security/test_pausable.cairo @@ -1,6 +1,6 @@ -use openzeppelin::security::pausable::Pausable; -use openzeppelin::security::pausable::Pausable::PausableImpl; use openzeppelin::security::pausable::Pausable::InternalImpl; +use openzeppelin::security::pausable::Pausable::PausableImpl; +use openzeppelin::security::pausable::Pausable; fn STATE() -> Pausable::ContractState { Pausable::contract_state_for_testing() diff --git a/src/tests/security/test_reentrancyguard.cairo b/src/tests/security/test_reentrancyguard.cairo index f0891b213..b608706db 100644 --- a/src/tests/security/test_reentrancyguard.cairo +++ b/src/tests/security/test_reentrancyguard.cairo @@ -1,10 +1,10 @@ -use openzeppelin::security::reentrancyguard::ReentrancyGuard; use openzeppelin::security::reentrancyguard::ReentrancyGuard::InternalImpl; use openzeppelin::security::reentrancyguard::ReentrancyGuard::entered::InternalContractStateTrait; -use openzeppelin::tests::mocks::reentrancy_mock::ReentrancyMock; +use openzeppelin::security::reentrancyguard::ReentrancyGuard; +use openzeppelin::tests::mocks::reentrancy_attacker_mock::Attacker; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcherTrait; -use openzeppelin::tests::mocks::reentrancy_attacker_mock::Attacker; +use openzeppelin::tests::mocks::reentrancy_mock::ReentrancyMock; use openzeppelin::tests::utils; fn STATE() -> ReentrancyGuard::ContractState { diff --git a/src/tests/token.cairo b/src/tests/token.cairo index fa678fb9c..458159c98 100644 --- a/src/tests/token.cairo +++ b/src/tests/token.cairo @@ -1,6 +1,6 @@ mod test_dual20; mod test_dual721; +mod test_dual721_receiver; mod test_erc20; mod test_erc721; -mod test_dual721_receiver; diff --git a/src/tests/token/test_dual20.cairo b/src/tests/token/test_dual20.cairo index d8b56c5fa..6e1e5dc86 100644 --- a/src/tests/token/test_dual20.cairo +++ b/src/tests/token/test_dual20.cairo @@ -1,21 +1,20 @@ use array::ArrayTrait; -use starknet::ContractAddress; -use starknet::contract_address_const; -use starknet::testing::set_contract_address; - use openzeppelin::tests::mocks::camel20_mock::CamelERC20Mock; -use openzeppelin::tests::mocks::erc20_panic::SnakeERC20Panic; use openzeppelin::tests::mocks::erc20_panic::CamelERC20Panic; +use openzeppelin::tests::mocks::erc20_panic::SnakeERC20Panic; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::snake20_mock::SnakeERC20Mock; +use openzeppelin::tests::utils; use openzeppelin::token::erc20::dual20::DualERC20; use openzeppelin::token::erc20::dual20::DualERC20Trait; use openzeppelin::token::erc20::interface::IERC20CamelDispatcher; use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait; use openzeppelin::token::erc20::interface::IERC20Dispatcher; use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; -use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_contract_address; // // Constants diff --git a/src/tests/token/test_dual721.cairo b/src/tests/token/test_dual721.cairo index 8ff48f036..55349de11 100644 --- a/src/tests/token/test_dual721.cairo +++ b/src/tests/token/test_dual721.cairo @@ -1,25 +1,25 @@ use array::ArrayTrait; -use starknet::ContractAddress; -use starknet::contract_address_const; -use starknet::testing::set_caller_address; -use starknet::testing::set_contract_address; -use openzeppelin::token::erc721::interface::IERC721_ID; -use openzeppelin::token::erc721::interface::IERC721Dispatcher; -use openzeppelin::token::erc721::interface::IERC721CamelOnlyDispatcher; -use openzeppelin::token::erc721::interface::IERC721DispatcherTrait; -use openzeppelin::token::erc721::interface::IERC721CamelOnlyDispatcherTrait; -use openzeppelin::token::erc721::dual721::DualCaseERC721Trait; -use openzeppelin::token::erc721::dual721::DualCaseERC721; -use openzeppelin::tests::mocks::snake721_mock::SnakeERC721Mock; use openzeppelin::tests::mocks::camel721_mock::CamelERC721Mock; +use openzeppelin::tests::mocks::erc721_panic_mock::CamelERC721PanicMock; +use openzeppelin::tests::mocks::erc721_panic_mock::SnakeERC721PanicMock; use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; -use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; use openzeppelin::tests::mocks::erc721_receiver::FAILURE; -use openzeppelin::tests::mocks::erc721_panic_mock::SnakeERC721PanicMock; -use openzeppelin::tests::mocks::erc721_panic_mock::CamelERC721PanicMock; +use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::mocks::snake721_mock::SnakeERC721Mock; use openzeppelin::tests::utils; +use openzeppelin::token::erc721::dual721::DualCaseERC721; +use openzeppelin::token::erc721::dual721::DualCaseERC721Trait; +use openzeppelin::token::erc721::interface::IERC721CamelOnlyDispatcher; +use openzeppelin::token::erc721::interface::IERC721CamelOnlyDispatcherTrait; +use openzeppelin::token::erc721::interface::IERC721Dispatcher; +use openzeppelin::token::erc721::interface::IERC721DispatcherTrait; +use openzeppelin::token::erc721::interface::IERC721_ID; use openzeppelin::utils::serde::SerializedAppend; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_caller_address; +use starknet::testing::set_contract_address; // // Constants diff --git a/src/tests/token/test_dual721_receiver.cairo b/src/tests/token/test_dual721_receiver.cairo index ef02380a9..9fde537c0 100644 --- a/src/tests/token/test_dual721_receiver.cairo +++ b/src/tests/token/test_dual721_receiver.cairo @@ -1,21 +1,21 @@ use array::ArrayTrait; -use starknet::ContractAddress; -use starknet::contract_address_const; -use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; -use openzeppelin::tests::mocks::erc721_receiver::FAILURE; -use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; -use openzeppelin::token::erc721::interface::IERC721ReceiverDispatcher; -use openzeppelin::token::erc721::interface::IERC721ReceiverCamelDispatcher; -use openzeppelin::token::erc721::interface::IERC721ReceiverDispatcherTrait; -use openzeppelin::token::erc721::interface::IERC721ReceiverCamelDispatcherTrait; -use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; -use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; -use openzeppelin::tests::mocks::dual721_receiver_mocks::SnakeERC721ReceiverMock; use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; -use openzeppelin::tests::mocks::dual721_receiver_mocks::SnakeERC721ReceiverPanicMock; use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverPanicMock; +use openzeppelin::tests::mocks::dual721_receiver_mocks::SnakeERC721ReceiverMock; +use openzeppelin::tests::mocks::dual721_receiver_mocks::SnakeERC721ReceiverPanicMock; +use openzeppelin::tests::mocks::erc721_receiver::FAILURE; +use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils; +use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; +use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; +use openzeppelin::token::erc721::interface::IERC721ReceiverCamelDispatcher; +use openzeppelin::token::erc721::interface::IERC721ReceiverCamelDispatcherTrait; +use openzeppelin::token::erc721::interface::IERC721ReceiverDispatcher; +use openzeppelin::token::erc721::interface::IERC721ReceiverDispatcherTrait; +use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; +use starknet::ContractAddress; +use starknet::contract_address_const; // // Constants diff --git a/src/tests/token/test_erc20.cairo b/src/tests/token/test_erc20.cairo index 55945c0e2..1303c3e1c 100644 --- a/src/tests/token/test_erc20.cairo +++ b/src/tests/token/test_erc20.cairo @@ -1,17 +1,16 @@ use integer::BoundedInt; use integer::u256; use integer::u256_from_felt252; +use openzeppelin::token::erc20::ERC20::ERC20CamelOnlyImpl; +use openzeppelin::token::erc20::ERC20::ERC20Impl; +use openzeppelin::token::erc20::ERC20::InternalImpl; +use openzeppelin::token::erc20::ERC20; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing::set_caller_address; use traits::Into; use zeroable::Zeroable; -use openzeppelin::token::erc20::ERC20; -use openzeppelin::token::erc20::ERC20::ERC20CamelOnlyImpl; -use openzeppelin::token::erc20::ERC20::ERC20Impl; -use openzeppelin::token::erc20::ERC20::InternalImpl; - // // Constants // diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index 5c7fdc4f9..45bd6c39e 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -1,17 +1,19 @@ -use starknet::contract_address_const; -use starknet::ContractAddress; -use starknet::testing::set_caller_address; +use ERC721::_owners::InternalContractStateTrait as OwnersTrait; +use ERC721::_token_approvals::InternalContractStateTrait as TokenApprovalsTrait; +use array::ArrayTrait; use integer::u256; use integer::u256_from_felt252; -use array::ArrayTrait; -use traits::Into; -use zeroable::Zeroable; use openzeppelin::account::Account; -use openzeppelin::introspection; use openzeppelin::introspection::src5; -use openzeppelin::token::erc721; -use openzeppelin::token::erc721::ERC721; +use openzeppelin::introspection; +use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; +use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; +use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; +use openzeppelin::tests::mocks::erc721_receiver::FAILURE; +use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils; use openzeppelin::token::erc721::ERC721::ERC721CamelOnlyImpl; use openzeppelin::token::erc721::ERC721::ERC721Impl; use openzeppelin::token::erc721::ERC721::ERC721MetadataCamelOnlyImpl; @@ -19,16 +21,13 @@ use openzeppelin::token::erc721::ERC721::ERC721MetadataImpl; use openzeppelin::token::erc721::ERC721::InternalImpl; use openzeppelin::token::erc721::ERC721::SRC5CamelImpl; use openzeppelin::token::erc721::ERC721::SRC5Impl; -use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; -use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; -use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; -use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; -use openzeppelin::tests::mocks::erc721_receiver::FAILURE; -use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; -use openzeppelin::tests::utils; - -use ERC721::_owners::InternalContractStateTrait as OwnersTrait; -use ERC721::_token_approvals::InternalContractStateTrait as TokenApprovalsTrait; +use openzeppelin::token::erc721::ERC721; +use openzeppelin::token::erc721; +use starknet::ContractAddress; +use starknet::contract_address_const; +use starknet::testing::set_caller_address; +use traits::Into; +use zeroable::Zeroable; const NAME: felt252 = 111; const SYMBOL: felt252 = 222; diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index d3b720cce..5eb3d1001 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -1,8 +1,8 @@ use array::ArrayTrait; use core::result::ResultTrait; use option::OptionTrait; -use starknet::class_hash::Felt252TryIntoClassHash; use starknet::ContractAddress; +use starknet::class_hash::Felt252TryIntoClassHash; use traits::TryInto; fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { diff --git a/src/token/erc20.cairo b/src/token/erc20.cairo index 6784045a0..736230aca 100644 --- a/src/token/erc20.cairo +++ b/src/token/erc20.cairo @@ -1,5 +1,5 @@ -mod erc20; mod dual20; +mod erc20; mod interface; use erc20::ERC20; diff --git a/src/token/erc20/dual20.cairo b/src/token/erc20/dual20.cairo index 1a867c0f7..28897c6f5 100644 --- a/src/token/erc20/dual20.cairo +++ b/src/token/erc20/dual20.cairo @@ -2,14 +2,13 @@ // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc20/dual20.cairo) use array::ArrayTrait; -use starknet::call_contract_syscall; -use starknet::ContractAddress; -use starknet::SyscallResultTrait; - -use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; -use openzeppelin::utils::UnwrapAndCast; +use openzeppelin::utils::try_selector_with_fallback; +use starknet::ContractAddress; +use starknet::SyscallResultTrait; +use starknet::call_contract_syscall; #[derive(Copy, Drop)] struct DualERC20 { diff --git a/src/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo index ebdc5af0f..9448b8ef3 100644 --- a/src/token/erc20/erc20.cairo +++ b/src/token/erc20/erc20.cairo @@ -4,13 +4,12 @@ #[starknet::contract] mod ERC20 { use integer::BoundedInt; + use openzeppelin::token::erc20::interface::IERC20; + use openzeppelin::token::erc20::interface::IERC20CamelOnly; use starknet::ContractAddress; use starknet::get_caller_address; use zeroable::Zeroable; - use openzeppelin::token::erc20::interface::IERC20; - use openzeppelin::token::erc20::interface::IERC20CamelOnly; - #[storage] struct Storage { _name: felt252, diff --git a/src/token/erc721/dual721.cairo b/src/token/erc721/dual721.cairo index 8d4ce8ffa..88cc35abd 100644 --- a/src/token/erc721/dual721.cairo +++ b/src/token/erc721/dual721.cairo @@ -2,13 +2,13 @@ // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/dual721.cairo) use array::ArrayTrait; +use openzeppelin::utils::UnwrapAndCast; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::try_selector_with_fallback; use starknet::ContractAddress; use starknet::SyscallResultTrait; use starknet::call_contract_syscall; -use openzeppelin::utils::try_selector_with_fallback; -use openzeppelin::utils::selectors; -use openzeppelin::utils::UnwrapAndCast; -use openzeppelin::utils::serde::SerializedAppend; #[derive(Copy, Drop)] struct DualCaseERC721 { diff --git a/src/token/erc721/dual721_receiver.cairo b/src/token/erc721/dual721_receiver.cairo index 55029bdd1..650285d6d 100644 --- a/src/token/erc721/dual721_receiver.cairo +++ b/src/token/erc721/dual721_receiver.cairo @@ -2,12 +2,12 @@ // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/dual721_receiver.cairo) use array::ArrayTrait; -use starknet::ContractAddress; -use starknet::SyscallResultTrait; -use openzeppelin::utils::try_selector_with_fallback; +use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; -use openzeppelin::utils::UnwrapAndCast; +use openzeppelin::utils::try_selector_with_fallback; +use starknet::ContractAddress; +use starknet::SyscallResultTrait; #[derive(Copy, Drop)] struct DualCaseERC721Receiver { diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index 0ea2598c7..5a5b56b51 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -6,11 +6,6 @@ use starknet::ContractAddress; #[starknet::contract] mod ERC721 { use array::SpanTrait; - use option::OptionTrait; - use starknet::ContractAddress; - use starknet::get_caller_address; - use zeroable::Zeroable; - use openzeppelin::account; use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; @@ -20,6 +15,10 @@ mod ERC721 { use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; use openzeppelin::token::erc721::interface; + use option::OptionTrait; + use starknet::ContractAddress; + use starknet::get_caller_address; + use zeroable::Zeroable; #[storage] struct Storage { diff --git a/src/token/erc721/interface.cairo b/src/token/erc721/interface.cairo index 44ff80a5e..4aff670b8 100644 --- a/src/token/erc721/interface.cairo +++ b/src/token/erc721/interface.cairo @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/interface.cairo) -use starknet::ContractAddress; use array::SpanTrait; +use starknet::ContractAddress; const IERC721_ID: felt252 = 0x33eb2f84c309543403fd69f0d0f363781ef06ef6faeb0131ff16ea3175bd943; const IERC721_METADATA_ID: felt252 = diff --git a/src/utils.cairo b/src/utils.cairo index 721dfdfee..38b0b35dd 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -10,10 +10,10 @@ use array::ArrayTrait; use array::SpanTrait; use box::BoxTrait; use option::OptionTrait; -use starknet::call_contract_syscall; use starknet::ContractAddress; use starknet::SyscallResult; use starknet::SyscallResultTrait; +use starknet::call_contract_syscall; use unwrap_and_cast::UnwrapAndCast; fn try_selector_with_fallback( diff --git a/src/utils/unwrap_and_cast.cairo b/src/utils/unwrap_and_cast.cairo index 185242dc1..9e58009a2 100644 --- a/src/utils/unwrap_and_cast.cairo +++ b/src/utils/unwrap_and_cast.cairo @@ -2,6 +2,8 @@ // OpenZeppelin Contracts for Cairo v0.7.0 (utils/unwrap_and_cast.cairo) use array::SpanTrait; + +use openzeppelin::utils::Felt252TryIntoBool; use option::OptionTrait; use starknet::ContractAddress; use starknet::Felt252TryIntoContractAddress; @@ -9,8 +11,6 @@ use starknet::SyscallResult; use starknet::SyscallResultTrait; use traits::TryInto; -use openzeppelin::utils::Felt252TryIntoBool; - trait UnwrapAndCast { fn unwrap_and_cast(self: SyscallResult>) -> T; } From c28c75875a43fa85a6163b1c1b6f113c1182d517 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 10 Aug 2023 02:47:19 -0400 Subject: [PATCH 077/124] Migrate upgrades (#603) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add upgrades to lib * add proxy mod * update cairo * update Cargo * fix test command * add upgrades * fix spelling * add upgrade test * fix spelling * add upgrade_and_call * update cairo * update Cargo * add events * tidy up code * fix format * update cairo to alpha7 * update Cargo * fix expected syntax * fix conflict * update expected syntax * formatting * update cairo to rc0 * update Cargo * fix import * refactor mocks * start test refactor * simplify upgrades, add upgrade_and_call * refactor mocks * refactor upgrades * refactor tests * fix imports, add impl * fix imports * fix formatting * add abis to mocks * refactor tests with dispatchers * fix formatting * start migration * update syntax * update syntax in mocks * fix tests * add line * remove line * add upgradeable trait * replace interface impl with trait impl * fix formatting * add assertion * add tests for events * Apply suggestions from code review Co-authored-by: Eric Nordelo * move logic to internal impl * add interface * update paths * fix formatting * simplify imports * Apply suggestions from code review Co-authored-by: Eric Nordelo * Apply suggestions from code review Co-authored-by: Martín Triay * remove upgrade_and_call, test event in separate test * remove upgrade_and_call * remove unused import * reorder imports, tidy up code --------- Co-authored-by: Eric Nordelo Co-authored-by: Martín Triay --- src/lib.cairo | 1 + src/tests.cairo | 1 + src/tests/mocks.cairo | 2 + src/tests/mocks/upgrades_v1.cairo | 55 ++++++++++++ src/tests/mocks/upgrades_v2.cairo | 64 +++++++++++++ src/tests/upgrades.cairo | 1 + src/tests/upgrades/test_upgradeable.cairo | 104 ++++++++++++++++++++++ src/upgrades.cairo | 2 + src/upgrades/interface.cairo | 6 ++ src/upgrades/upgradeable.cairo | 29 ++++++ 10 files changed, 265 insertions(+) create mode 100644 src/tests/mocks/upgrades_v1.cairo create mode 100644 src/tests/mocks/upgrades_v2.cairo create mode 100644 src/tests/upgrades.cairo create mode 100644 src/tests/upgrades/test_upgradeable.cairo create mode 100644 src/upgrades.cairo create mode 100644 src/upgrades/interface.cairo create mode 100644 src/upgrades/upgradeable.cairo diff --git a/src/lib.cairo b/src/lib.cairo index 235e12392..ea35f72ca 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -3,6 +3,7 @@ mod account; mod introspection; mod security; mod token; +mod upgrades; mod utils; #[cfg(test)] diff --git a/src/tests.cairo b/src/tests.cairo index cc78a11ec..7145f5650 100644 --- a/src/tests.cairo +++ b/src/tests.cairo @@ -4,4 +4,5 @@ mod introspection; mod mocks; mod security; mod token; +mod upgrades; mod utils; diff --git a/src/tests/mocks.cairo b/src/tests/mocks.cairo index cb3112db1..11a30de47 100644 --- a/src/tests/mocks.cairo +++ b/src/tests/mocks.cairo @@ -17,3 +17,5 @@ mod snake721_mock; mod snake_accesscontrol_mock; mod snake_account_mock; mod src5_mocks; +mod upgrades_v1; +mod upgrades_v2; diff --git a/src/tests/mocks/upgrades_v1.cairo b/src/tests/mocks/upgrades_v1.cairo new file mode 100644 index 000000000..d851f59d9 --- /dev/null +++ b/src/tests/mocks/upgrades_v1.cairo @@ -0,0 +1,55 @@ +// This contract is a mock used to test the core functionality of the upgrade functions. +// The functions are NOT PROTECTED. +// DO NOT USE IN PRODUCTION. + +use array::ArrayTrait; +use starknet::ClassHash; + +#[starknet::interface] +trait IUpgradesV1 { + fn upgrade(ref self: TState, impl_hash: ClassHash); + fn set_value(ref self: TState, val: felt252); + fn get_value(self: @TState) -> felt252; + fn remove_selector(self: @TState); +} + +trait UpgradesV1Trait { + fn set_value(ref self: TState, val: felt252); + fn get_value(self: @TState) -> felt252; + fn remove_selector(self: @TState); +} + +#[starknet::contract] +mod UpgradesV1 { + use array::ArrayTrait; + use starknet::ClassHash; + use starknet::ContractAddress; + use openzeppelin::upgrades::interface::IUpgradeable; + use openzeppelin::upgrades::upgradeable::Upgradeable; + + #[storage] + struct Storage { + value: felt252 + } + + #[external(v0)] + impl UpgradeableImpl of IUpgradeable { + fn upgrade(ref self: ContractState, impl_hash: ClassHash) { + let mut unsafe_state = Upgradeable::unsafe_new_contract_state(); + Upgradeable::InternalImpl::_upgrade(ref unsafe_state, impl_hash); + } + } + + #[external(v0)] + impl UpgradesV1Impl of super::UpgradesV1Trait { + fn set_value(ref self: ContractState, val: felt252) { + self.value.write(val); + } + + fn get_value(self: @ContractState) -> felt252 { + self.value.read() + } + + fn remove_selector(self: @ContractState) {} + } +} diff --git a/src/tests/mocks/upgrades_v2.cairo b/src/tests/mocks/upgrades_v2.cairo new file mode 100644 index 000000000..f0ad60ee7 --- /dev/null +++ b/src/tests/mocks/upgrades_v2.cairo @@ -0,0 +1,64 @@ +// This contract is a mock used to test the core functionality of the upgrade functions. +// The functions are NOT PROTECTED. +// DO NOT USE IN PRODUCTION. + +use array::ArrayTrait; +use starknet::ClassHash; + +#[starknet::interface] +trait IUpgradesV2 { + fn upgrade(ref self: TState, impl_hash: ClassHash); + fn set_value(ref self: TState, val: felt252); + fn set_value2(ref self: TState, val: felt252); + fn get_value(self: @TState) -> felt252; + fn get_value2(self: @TState) -> felt252; +} + +trait UpgradesV2Trait { + fn set_value(ref self: TState, val: felt252); + fn set_value2(ref self: TState, val: felt252); + fn get_value(self: @TState) -> felt252; + fn get_value2(self: @TState) -> felt252; +} + +#[starknet::contract] +mod UpgradesV2 { + use array::ArrayTrait; + use starknet::ClassHash; + use starknet::ContractAddress; + use openzeppelin::upgrades::interface::IUpgradeable; + use openzeppelin::upgrades::upgradeable::Upgradeable; + + #[storage] + struct Storage { + value: felt252, + value2: felt252, + } + + #[external(v0)] + impl UpgradeableImpl of IUpgradeable { + fn upgrade(ref self: ContractState, impl_hash: ClassHash) { + let mut unsafe_state = Upgradeable::unsafe_new_contract_state(); + Upgradeable::InternalImpl::_upgrade(ref unsafe_state, impl_hash); + } + } + + #[external(v0)] + impl UpgradesV2Impl of super::UpgradesV2Trait { + fn set_value(ref self: ContractState, val: felt252) { + self.value.write(val); + } + + fn set_value2(ref self: ContractState, val: felt252) { + self.value2.write(val); + } + + fn get_value(self: @ContractState) -> felt252 { + self.value.read() + } + + fn get_value2(self: @ContractState) -> felt252 { + self.value2.read() + } + } +} diff --git a/src/tests/upgrades.cairo b/src/tests/upgrades.cairo new file mode 100644 index 000000000..fe66e01e3 --- /dev/null +++ b/src/tests/upgrades.cairo @@ -0,0 +1 @@ +mod test_upgradeable; diff --git a/src/tests/upgrades/test_upgradeable.cairo b/src/tests/upgrades/test_upgradeable.cairo new file mode 100644 index 000000000..66de7a2a7 --- /dev/null +++ b/src/tests/upgrades/test_upgradeable.cairo @@ -0,0 +1,104 @@ +use array::ArrayTrait; +use openzeppelin::tests::mocks::upgrades_v1::IUpgradesV1Dispatcher; +use openzeppelin::tests::mocks::upgrades_v1::IUpgradesV1DispatcherTrait; +use openzeppelin::tests::mocks::upgrades_v2::IUpgradesV2Dispatcher; +use openzeppelin::tests::mocks::upgrades_v2::IUpgradesV2DispatcherTrait; +use openzeppelin::tests::mocks::upgrades_v1::UpgradesV1; +use openzeppelin::tests::mocks::upgrades_v2::UpgradesV2; +use openzeppelin::tests::utils; +use openzeppelin::upgrades::upgradeable::Upgradeable::Upgraded; +use option::OptionTrait; +use starknet::ClassHash; +use starknet::ContractAddress; +use starknet::Felt252TryIntoClassHash; +use starknet::class_hash_const; +use starknet::contract_address_const; +use starknet::testing; +use traits::TryInto; + +const VALUE: felt252 = 123; + +fn V2_CLASS_HASH() -> ClassHash { + UpgradesV2::TEST_CLASS_HASH.try_into().unwrap() +} + +fn CLASS_HASH_ZERO() -> ClassHash { + class_hash_const::<0>() +} + +fn ZERO() -> ContractAddress { + contract_address_const::<0>() +} + +// +// Setup +// + +fn deploy_v1() -> IUpgradesV1Dispatcher { + let calldata = array![]; + let address = utils::deploy(UpgradesV1::TEST_CLASS_HASH, calldata); + IUpgradesV1Dispatcher { contract_address: address } +} + +// +// upgrade +// + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('Class hash cannot be zero', 'ENTRYPOINT_FAILED', ))] +fn test_upgrade_with_class_hash_zero() { + let v1 = deploy_v1(); + v1.upgrade(CLASS_HASH_ZERO()); +} + +#[test] +#[available_gas(2000000)] +fn test_upgraded_event() { + let v1 = deploy_v1(); + v1.upgrade(V2_CLASS_HASH()); + + let event = testing::pop_log::(v1.contract_address).unwrap(); + assert(event.class_hash == V2_CLASS_HASH(), 'Invalid class hash'); +} + +#[test] +#[available_gas(2000000)] +fn test_new_selector_after_upgrade() { + let v1 = deploy_v1(); + + v1.upgrade(V2_CLASS_HASH()); + let v2 = IUpgradesV2Dispatcher { contract_address: v1.contract_address }; + + v2.set_value2(VALUE); + assert(v2.get_value2() == VALUE, 'New selector should be callable'); +} + +#[test] +#[available_gas(2000000)] +fn test_state_persists_after_upgrade() { + let v1 = deploy_v1(); + v1.set_value(VALUE); + + v1.upgrade(V2_CLASS_HASH()); + let v2 = IUpgradesV2Dispatcher { contract_address: v1.contract_address }; + + assert(v2.get_value() == VALUE, 'Should keep state after upgrade'); +} + +#[test] +#[available_gas(2000000)] +fn test_remove_selector_passes_in_v1() { + let v1 = deploy_v1(); + v1.remove_selector(); +} + +#[test] +#[available_gas(2000000)] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +fn test_remove_selector_fails_in_v2() { + let v1 = deploy_v1(); + v1.upgrade(V2_CLASS_HASH()); + // We use the v1 dispatcher because remove_selector is not in v2 interface + v1.remove_selector(); +} diff --git a/src/upgrades.cairo b/src/upgrades.cairo new file mode 100644 index 000000000..18d78fc73 --- /dev/null +++ b/src/upgrades.cairo @@ -0,0 +1,2 @@ +mod upgradeable; +mod interface; diff --git a/src/upgrades/interface.cairo b/src/upgrades/interface.cairo new file mode 100644 index 000000000..1857c003d --- /dev/null +++ b/src/upgrades/interface.cairo @@ -0,0 +1,6 @@ +use starknet::ClassHash; + +#[starknet::interface] +trait IUpgradeable { + fn upgrade(ref self: TState, impl_hash: ClassHash); +} diff --git a/src/upgrades/upgradeable.cairo b/src/upgrades/upgradeable.cairo new file mode 100644 index 000000000..444cf36b7 --- /dev/null +++ b/src/upgrades/upgradeable.cairo @@ -0,0 +1,29 @@ +#[starknet::contract] +mod Upgradeable { + use starknet::ClassHash; + use starknet::SyscallResult; + use zeroable::Zeroable; + + #[storage] + struct Storage {} + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + Upgraded: Upgraded + } + + #[derive(Drop, starknet::Event)] + struct Upgraded { + class_hash: ClassHash + } + + #[generate_trait] + impl InternalImpl of InternalState { + fn _upgrade(ref self: ContractState, new_class_hash: ClassHash) { + assert(!new_class_hash.is_zero(), 'Class hash cannot be zero'); + starknet::replace_class_syscall(new_class_hash).unwrap_syscall(); + self.emit(Upgraded { class_hash: new_class_hash }); + } + } +} From f9c30da2d70762660e33088965006b43f07ccfcb Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 11 Aug 2023 20:11:48 +0200 Subject: [PATCH 078/124] Add testing for Ownable events (#675) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add tests for ownable events * feat: improve tests * Update src/tests/utils.cairo Co-authored-by: Martín Triay --------- Co-authored-by: Martín Triay --- src/tests/access/test_accesscontrol.cairo | 26 ++-------- .../access/test_dual_accesscontrol.cairo | 29 ++++------- src/tests/access/test_ownable.cairo | 48 ++++++++++++++----- src/tests/utils.cairo | 22 ++++++++- src/tests/utils/constants.cairo | 33 +++++++++++++ 5 files changed, 100 insertions(+), 58 deletions(-) create mode 100644 src/tests/utils/constants.cairo diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index 86ef607e0..6099c551f 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -4,33 +4,13 @@ use openzeppelin::access::accesscontrol::AccessControl::InternalImpl; use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; +use openzeppelin::tests::utils::constants::{ + ADMIN, AUTHORIZED, OTHER, OTHER_ADMIN, ROLE, OTHER_ROLE, ZERO +}; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; -const ROLE: felt252 = 41; -const OTHER_ROLE: felt252 = 42; - -fn ZERO() -> ContractAddress { - contract_address_const::<0>() -} - -fn ADMIN() -> ContractAddress { - contract_address_const::<1>() -} - -fn AUTHORIZED() -> ContractAddress { - contract_address_const::<2>() -} - -fn OTHER() -> ContractAddress { - contract_address_const::<3>() -} - -fn OTHER_ADMIN() -> ContractAddress { - contract_address_const::<4>() -} - // // Setup // diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index a20657902..2d6a17be4 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -1,37 +1,24 @@ use array::ArrayTrait; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; -use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; -use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; -use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; -use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; +use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::CamelAccessControlPanicMock; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; +use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; +use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::tests::mocks::accesscontrol_panic_mock::CamelAccessControlPanicMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; -use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; +use openzeppelin::tests::utils::constants::{ADMIN, AUTHORIZED, ROLE}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing::set_contract_address; -// -// Constants -// - -const ROLE: felt252 = 41; - -fn ADMIN() -> ContractAddress { - contract_address_const::<10>() -} - -fn AUTHORIZED() -> ContractAddress { - contract_address_const::<20>() -} - // // Setup // diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index d88d0f786..c2e6b8682 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -1,25 +1,17 @@ +use openzeppelin::access::ownable::Ownable; use openzeppelin::access::ownable::Ownable::InternalImpl; use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; use openzeppelin::access::ownable::Ownable::OwnableImpl; +use openzeppelin::access::ownable::Ownable::OwnershipTransferred; use openzeppelin::access::ownable::Ownable::_owner::InternalContractStateTrait; -use openzeppelin::access::ownable::Ownable; +use openzeppelin::tests::utils; +use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; +use option::OptionTrait; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; use zeroable::Zeroable; -fn ZERO() -> ContractAddress { - contract_address_const::<0>() -} - -fn OWNER() -> ContractAddress { - contract_address_const::<10>() -} - -fn OTHER() -> ContractAddress { - contract_address_const::<20>() -} - // // Setup // @@ -31,6 +23,7 @@ fn STATE() -> Ownable::ContractState { fn setup() -> Ownable::ContractState { let mut state = STATE(); InternalImpl::initializer(ref state, OWNER()); + testing::pop_log_raw(ZERO()); state } @@ -44,6 +37,9 @@ fn test_initializer() { let mut state = STATE(); assert(state._owner.read().is_zero(), 'Should be zero'); InternalImpl::initializer(ref state, OWNER()); + + assert_event_ownership_transferred(ZERO(), OWNER()); + assert(state._owner.read() == OWNER(), 'Owner should be set'); } @@ -85,6 +81,9 @@ fn test_assert_only_owner_when_caller_zero() { fn test__transfer_ownership() { let mut state = setup(); InternalImpl::_transfer_ownership(ref state, OTHER()); + + assert_event_ownership_transferred(OWNER(), OTHER()); + assert(state._owner.read() == OTHER(), 'Owner should be OTHER'); } @@ -98,6 +97,9 @@ fn test_transfer_ownership() { let mut state = setup(); testing::set_caller_address(OWNER()); OwnableImpl::transfer_ownership(ref state, OTHER()); + + assert_event_ownership_transferred(OWNER(), OTHER()); + assert(OwnableImpl::owner(@state) == OTHER(), 'Should transfer ownership'); } @@ -133,6 +135,9 @@ fn test_transferOwnership() { let mut state = setup(); testing::set_caller_address(OWNER()); OwnableCamelOnlyImpl::transferOwnership(ref state, OTHER()); + + assert_event_ownership_transferred(OWNER(), OTHER()); + assert(OwnableImpl::owner(@state) == OTHER(), 'Should transfer ownership'); } @@ -172,6 +177,9 @@ fn test_renounce_ownership() { let mut state = setup(); testing::set_caller_address(OWNER()); OwnableImpl::renounce_ownership(ref state); + + assert_event_ownership_transferred(OWNER(), ZERO()); + assert(OwnableImpl::owner(@state) == ZERO(), 'Should renounce ownership'); } @@ -198,6 +206,9 @@ fn test_renounceOwnership() { let mut state = setup(); testing::set_caller_address(OWNER()); OwnableCamelOnlyImpl::renounceOwnership(ref state); + + assert_event_ownership_transferred(OWNER(), ZERO()); + assert(OwnableImpl::owner(@state) == ZERO(), 'Should renounce ownership'); } @@ -217,3 +228,14 @@ fn test_renounceOwnership_from_nonowner() { testing::set_caller_address(OTHER()); OwnableCamelOnlyImpl::renounceOwnership(ref state); } + +// +// Helpers +// + +fn assert_event_ownership_transferred(previous_owner: ContractAddress, new_owner: ContractAddress) { + let event = utils::pop_log::(ZERO()).unwrap(); + assert(event.previous_owner == previous_owner, 'Invalid previous_owner'); + assert(event.new_owner == new_owner, 'Invalid new_owner'); + utils::assert_no_events_left(ZERO()); +} diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index 5eb3d1001..084e685e7 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -1,8 +1,12 @@ +mod constants; + use array::ArrayTrait; +use array::SpanTrait; use core::result::ResultTrait; use option::OptionTrait; -use starknet::ContractAddress; use starknet::class_hash::Felt252TryIntoClassHash; +use starknet::ContractAddress; +use starknet::testing; use traits::TryInto; fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { @@ -12,3 +16,19 @@ fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAdd .unwrap(); address } + +/// Pop the earliest unpopped logged event for the contract as the requested type +/// and checks there's no more data left on the event, preventing missing extra params. +/// Indexed event members are currently not supported, so they are ignored. +fn pop_log, impl TEvent: starknet::Event>( + address: ContractAddress +) -> Option { + let (mut keys, mut data) = testing::pop_log_raw(address)?; + let ret = starknet::Event::deserialize(ref keys, ref data); + assert(data.is_empty(), 'Event has extra data'); + ret +} + +fn assert_no_events_left(address: ContractAddress) { + assert(testing::pop_log_raw(address).is_none(), 'Events remaining on queue'); +} diff --git a/src/tests/utils/constants.cairo b/src/tests/utils/constants.cairo new file mode 100644 index 000000000..84cc4eae4 --- /dev/null +++ b/src/tests/utils/constants.cairo @@ -0,0 +1,33 @@ +use starknet::ContractAddress; +use starknet::contract_address_const; + +const ROLE: felt252 = 'ROLE'; +const OTHER_ROLE: felt252 = 'OTHER_ROLE'; + +fn ADMIN() -> ContractAddress { + contract_address_const::<'ADMIN'>() +} + +fn AUTHORIZED() -> ContractAddress { + contract_address_const::<'AUTHORIZED'>() +} + +fn ZERO() -> ContractAddress { + contract_address_const::<0>() +} + +fn OWNER() -> ContractAddress { + contract_address_const::<'OWNER'>() +} + +fn NEW_OWNER() -> ContractAddress { + contract_address_const::<'NEW_OWNER'>() +} + +fn OTHER() -> ContractAddress { + contract_address_const::<'OTHER'>() +} + +fn OTHER_ADMIN() -> ContractAddress { + contract_address_const::<'OTHER_ADMIN'>() +} From 457b98b10080820ad041980d71b24e7856766336 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 11 Aug 2023 14:20:47 -0400 Subject: [PATCH 079/124] Add account events (#687) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add tests for ownable events * define account events * add event to set_public_key * add event test * change param name * fix event emit param * fix formatting * add tests for events * add default checks in tests * feat: improve tests * Apply suggestions from code review Co-authored-by: Eric Nordelo * reorder imports, remove Account prefix * fix events * fix formatting * Update src/tests/utils.cairo Co-authored-by: Martín Triay * add event checks, use ZERO from constants * fix formatting --------- Co-authored-by: Eric Nordelo Co-authored-by: Martín Triay --- src/account/account.cairo | 30 +++++++++-- src/tests/account/test_account.cairo | 79 ++++++++++++++++++++++------ 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/account/account.cairo b/src/account/account.cairo index 8d8105521..8fffb55ea 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -49,6 +49,23 @@ mod Account { public_key: felt252 } + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + OwnerAdded: OwnerAdded, + OwnerRemoved: OwnerRemoved, + } + + #[derive(Drop, starknet::Event)] + struct OwnerAdded { + new_owner_guid: felt252 + } + + #[derive(Drop, starknet::Event)] + struct OwnerRemoved { + removed_owner_guid: felt252 + } + #[constructor] fn constructor(ref self: ContractState, _public_key: felt252) { self.initializer(_public_key); @@ -131,7 +148,8 @@ mod Account { fn set_public_key(ref self: ContractState, new_public_key: felt252) { assert_only_self(); - self.public_key.write(new_public_key); + self.emit(OwnerRemoved { removed_owner_guid: self.public_key.read() }); + self._set_public_key(new_public_key); } } @@ -142,8 +160,7 @@ mod Account { } fn setPublicKey(ref self: ContractState, newPublicKey: felt252) { - assert_only_self(); - self.public_key.write(newPublicKey); + PublicKeyImpl::set_public_key(ref self, newPublicKey); } } @@ -166,7 +183,7 @@ mod Account { fn initializer(ref self: ContractState, _public_key: felt252) { let mut unsafe_state = SRC5::unsafe_new_contract_state(); SRC5::InternalImpl::register_interface(ref unsafe_state, interface::ISRC6_ID); - self.public_key.write(_public_key); + self._set_public_key(_public_key); } fn validate_transaction(self: @ContractState) -> felt252 { @@ -177,6 +194,11 @@ mod Account { starknet::VALIDATED } + fn _set_public_key(ref self: ContractState, new_public_key: felt252) { + self.public_key.write(new_public_key); + self.emit(OwnerAdded { new_owner_guid: new_public_key }); + } + fn _is_valid_signature( self: @ContractState, hash: felt252, signature: Span ) -> bool { diff --git a/src/tests/account/test_account.cairo b/src/tests/account/test_account.cairo index b2fe45ceb..d66e9fbfe 100644 --- a/src/tests/account/test_account.cairo +++ b/src/tests/account/test_account.cairo @@ -1,5 +1,9 @@ use array::ArrayTrait; use core::traits::Into; +use openzeppelin::account::Account::OwnerAdded; +use openzeppelin::account::Account::OwnerRemoved; +use openzeppelin::account::Account::PublicKeyCamelImpl; +use openzeppelin::account::Account::PublicKeyImpl; use openzeppelin::account::Account; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; @@ -8,6 +12,7 @@ use openzeppelin::account::TRANSACTION_VERSION; use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::utils; +use openzeppelin::tests::utils::constants::ZERO; use openzeppelin::token::erc20::ERC20; use openzeppelin::token::erc20::interface::IERC20Dispatcher; use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; @@ -100,9 +105,12 @@ fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispa fn test_constructor() { let mut state = STATE(); Account::constructor(ref state, PUBLIC_KEY); - assert( - Account::PublicKeyImpl::get_public_key(@state) == PUBLIC_KEY, 'Should return public key' - ); + + let event = testing::pop_log::(ZERO()).unwrap(); + assert(event.new_owner_guid == PUBLIC_KEY, 'Invalid owner key'); + utils::assert_no_events_left(ZERO()); + + assert(PublicKeyImpl::get_public_key(@state) == PUBLIC_KEY, 'Should return public key'); } // @@ -149,7 +157,7 @@ fn test_is_valid_signature() { let mut good_signature = array![data.r, data.s]; let mut bad_signature = array![0x987, 0x564]; - Account::PublicKeyImpl::set_public_key(ref state, data.public_key); + PublicKeyImpl::set_public_key(ref state, data.public_key); let is_valid = Account::SRC6Impl::is_valid_signature(@state, hash, good_signature); assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); @@ -168,7 +176,7 @@ fn test_isValidSignature() { let mut good_signature = array![data.r, data.s]; let mut bad_signature = array![0x987, 0x564]; - Account::PublicKeyImpl::set_public_key(ref state, data.public_key); + PublicKeyImpl::set_public_key(ref state, data.public_key); let is_valid = Account::SRC6CamelOnlyImpl::isValidSignature(@state, hash, good_signature); assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); @@ -437,9 +445,21 @@ fn test_public_key_setter_and_getter() { testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(ACCOUNT_ADDRESS()); - Account::PublicKeyImpl::set_public_key(ref state, NEW_PUBKEY); + // Check default + let public_key = PublicKeyImpl::get_public_key(@state); + assert(public_key == 0, 'Should be zero'); + + // Set key + PublicKeyImpl::set_public_key(ref state, NEW_PUBKEY); + + let event = testing::pop_log::(ACCOUNT_ADDRESS()).unwrap(); + assert(event.removed_owner_guid == 0, 'Invalid old owner key'); - let public_key = Account::PublicKeyImpl::get_public_key(@state); + let event = testing::pop_log::(ACCOUNT_ADDRESS()).unwrap(); + assert(event.new_owner_guid == NEW_PUBKEY, 'Invalid new owner key'); + utils::assert_no_events_left(ACCOUNT_ADDRESS()); + + let public_key = PublicKeyImpl::get_public_key(@state); assert(public_key == NEW_PUBKEY, 'Should update key'); } @@ -452,7 +472,7 @@ fn test_public_key_setter_different_account() { testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(caller); - Account::PublicKeyImpl::set_public_key(ref state, NEW_PUBKEY); + PublicKeyImpl::set_public_key(ref state, NEW_PUBKEY); } // @@ -466,9 +486,21 @@ fn test_public_key_setter_and_getter_camel() { testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(ACCOUNT_ADDRESS()); - Account::PublicKeyCamelImpl::setPublicKey(ref state, NEW_PUBKEY); + // Check default + let public_key = PublicKeyCamelImpl::getPublicKey(@state); + assert(public_key == 0, 'Should be zero'); + + // Set key + PublicKeyCamelImpl::setPublicKey(ref state, NEW_PUBKEY); + + let event = testing::pop_log::(ACCOUNT_ADDRESS()).unwrap(); + assert(event.removed_owner_guid == 0, 'Invalid old owner key'); - let public_key = Account::PublicKeyCamelImpl::getPublicKey(@state); + let event = testing::pop_log::(ACCOUNT_ADDRESS()).unwrap(); + assert(event.new_owner_guid == NEW_PUBKEY, 'Invalid new owner key'); + utils::assert_no_events_left(ACCOUNT_ADDRESS()); + + let public_key = PublicKeyCamelImpl::getPublicKey(@state); assert(public_key == NEW_PUBKEY, 'Should update key'); } @@ -481,7 +513,7 @@ fn test_public_key_setter_different_account_camel() { testing::set_contract_address(ACCOUNT_ADDRESS()); testing::set_caller_address(caller); - Account::PublicKeyCamelImpl::setPublicKey(ref state, NEW_PUBKEY); + PublicKeyCamelImpl::setPublicKey(ref state, NEW_PUBKEY); } // @@ -493,9 +525,12 @@ fn test_public_key_setter_different_account_camel() { fn test_initializer() { let mut state = STATE(); Account::InternalImpl::initializer(ref state, PUBLIC_KEY); - assert( - Account::PublicKeyImpl::get_public_key(@state) == PUBLIC_KEY, 'Should return public key' - ); + + let event = testing::pop_log::(ZERO()).unwrap(); + assert(event.new_owner_guid == PUBLIC_KEY, 'Invalid owner key'); + utils::assert_no_events_left(ZERO()); + + assert(PublicKeyImpl::get_public_key(@state) == PUBLIC_KEY, 'Should return public key'); } #[test] @@ -527,7 +562,7 @@ fn test__is_valid_signature() { let mut bad_signature = array![0x987, 0x564]; let mut invalid_length_signature = array![0x987]; - Account::PublicKeyImpl::set_public_key(ref state, data.public_key); + PublicKeyImpl::set_public_key(ref state, data.public_key); let is_valid = Account::InternalImpl::_is_valid_signature(@state, hash, good_signature.span()); assert(is_valid, 'Should accept valid signature'); @@ -540,3 +575,17 @@ fn test__is_valid_signature() { ); assert(!is_valid, 'Should reject invalid length'); } + +#[test] +#[available_gas(2000000)] +fn test__set_public_key() { + let mut state = STATE(); + Account::InternalImpl::_set_public_key(ref state, PUBLIC_KEY); + + let event = testing::pop_log::(ZERO()).unwrap(); + assert(event.new_owner_guid == PUBLIC_KEY, 'Invalid owner key'); + utils::assert_no_events_left(ZERO()); + + let public_key = PublicKeyImpl::get_public_key(@state); + assert(public_key == PUBLIC_KEY, 'Should update key'); +} From 544ddacd26736533651f0430bf15ccb5ff70332e Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 16 Aug 2023 00:25:07 +0200 Subject: [PATCH 080/124] Add testing for AccessControl events (#674) * feat: add testing for events * feat: add tests for ownable events * feat: improve tests * feat: apply review updates --- src/tests/access/test_accesscontrol.cairo | 60 ++++++++++++++++++++++- src/tests/access/test_ownable.cairo | 6 +-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index 6099c551f..cea50e7d4 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -1,12 +1,17 @@ use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; use openzeppelin::access::accesscontrol::AccessControl::InternalImpl; +use openzeppelin::access::accesscontrol::AccessControl::RoleAdminChanged; +use openzeppelin::access::accesscontrol::AccessControl::RoleGranted; +use openzeppelin::access::accesscontrol::AccessControl::RoleRevoked; use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; use openzeppelin::tests::utils::constants::{ ADMIN, AUTHORIZED, OTHER, OTHER_ADMIN, ROLE, OTHER_ROLE, ZERO }; +use openzeppelin::tests::utils; +use option::OptionTrait; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; @@ -22,6 +27,7 @@ fn STATE() -> AccessControl::ContractState { fn setup() -> AccessControl::ContractState { let mut state = STATE(); InternalImpl::_grant_role(ref state, DEFAULT_ADMIN_ROLE, ADMIN()); + testing::pop_log_raw(ZERO()); state } @@ -133,6 +139,8 @@ fn test_grant_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + + assert_event_role_granted(ROLE, AUTHORIZED(), ADMIN()); assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be granted'); } @@ -142,6 +150,8 @@ fn test_grantRole() { let mut state = setup(); testing::set_caller_address(ADMIN()); AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + + assert_event_role_granted(ROLE, AUTHORIZED(), ADMIN()); assert(AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be granted'); } @@ -214,7 +224,11 @@ fn test_revoke_role_for_granted_role() { testing::set_caller_address(ADMIN()); AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + testing::pop_log_raw(ZERO()); + AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + + assert_event_role_revoked(ROLE, AUTHORIZED(), ADMIN()); assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be revoked'); } @@ -225,7 +239,11 @@ fn test_revokeRole_for_granted_role() { testing::set_caller_address(ADMIN()); AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + testing::pop_log_raw(ZERO()); + AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + + assert_event_role_revoked(ROLE, AUTHORIZED(), ADMIN()); assert(!AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be revoked'); } @@ -300,10 +318,14 @@ fn test_renounceRole_for_role_not_granted() { fn test_renounce_role_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); + AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + testing::pop_log_raw(ZERO()); testing::set_caller_address(AUTHORIZED()); AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + + assert_event_role_revoked(ROLE, AUTHORIZED(), AUTHORIZED()); assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be renounced'); } @@ -312,10 +334,14 @@ fn test_renounce_role_for_granted_role() { fn test_renounceRole_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); + AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + testing::pop_log_raw(ZERO()); testing::set_caller_address(AUTHORIZED()); AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + + assert_event_role_revoked(ROLE, AUTHORIZED(), AUTHORIZED()); assert( !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be renounced' ); @@ -389,6 +415,8 @@ fn test__set_role_admin() { 'ROLE admin default should be 0' ); InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + + assert_event_role_admin_changed(ROLE, DEFAULT_ADMIN_ROLE, OTHER_ROLE); assert( AccessControlImpl::get_role_admin(@state, ROLE) == OTHER_ROLE, 'ROLE admin should be OTHER_ROLE' @@ -447,7 +475,7 @@ fn test_previous_admin_cannot_revoke_roles() { } // -// default admin +// Default admin // #[test] @@ -469,3 +497,33 @@ fn test_default_admin_role_is_its_own_admin() { 'Should be DEFAULT_ADMIN_ROLE' ); } + +// +// Helpers +// + +fn assert_event_role_revoked(role: felt252, account: ContractAddress, sender: ContractAddress) { + let event = utils::pop_log::(ZERO()).unwrap(); + assert(event.role == role, 'Invalid `role`'); + assert(event.account == account, 'Invalid `account`'); + assert(event.sender == sender, 'Invalid `sender`'); + utils::assert_no_events_left(ZERO()); +} + +fn assert_event_role_granted(role: felt252, account: ContractAddress, sender: ContractAddress) { + let event = utils::pop_log::(ZERO()).unwrap(); + assert(event.role == role, 'Invalid `role`'); + assert(event.account == account, 'Invalid `account`'); + assert(event.sender == sender, 'Invalid `sender`'); + utils::assert_no_events_left(ZERO()); +} + +fn assert_event_role_admin_changed( + role: felt252, previous_admin_role: felt252, new_admin_role: felt252 +) { + let event = utils::pop_log::(ZERO()).unwrap(); + assert(event.role == role, 'Invalid `role`'); + assert(event.previous_admin_role == previous_admin_role, 'Invalid `previous_admin_role`'); + assert(event.new_admin_role == new_admin_role, 'Invalid `new_admin_role`'); + utils::assert_no_events_left(ZERO()); +} diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index c2e6b8682..c27af64d6 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -4,8 +4,8 @@ use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; use openzeppelin::access::ownable::Ownable::OwnableImpl; use openzeppelin::access::ownable::Ownable::OwnershipTransferred; use openzeppelin::access::ownable::Ownable::_owner::InternalContractStateTrait; -use openzeppelin::tests::utils; use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; +use openzeppelin::tests::utils; use option::OptionTrait; use starknet::ContractAddress; use starknet::contract_address_const; @@ -235,7 +235,7 @@ fn test_renounceOwnership_from_nonowner() { fn assert_event_ownership_transferred(previous_owner: ContractAddress, new_owner: ContractAddress) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.previous_owner == previous_owner, 'Invalid previous_owner'); - assert(event.new_owner == new_owner, 'Invalid new_owner'); + assert(event.previous_owner == previous_owner, 'Invalid `previous_owner`'); + assert(event.new_owner == new_owner, 'Invalid `new_owner`'); utils::assert_no_events_left(ZERO()); } From 4473243bdb513f9e57868700a46d5c48b1fe12cf Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 16 Aug 2023 00:28:57 +0200 Subject: [PATCH 081/124] Add testing for Pausable events (#676) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add testing for events * feat: add tests for ownable events * feat: add tests for pausable events * Update src/openzeppelin/tests/security/test_pausable.cairo Co-authored-by: Andrew Fleming * feat: improve tests * feat: apply review updates * feat: apply review updates --------- Co-authored-by: Andrew Fleming Co-authored-by: Martín Triay --- src/tests/security/test_pausable.cairo | 38 ++++++++++++++++++++++++++ src/tests/utils/constants.cairo | 4 +++ 2 files changed, 42 insertions(+) diff --git a/src/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo index ac84fedc2..7f3feb8e7 100644 --- a/src/tests/security/test_pausable.cairo +++ b/src/tests/security/test_pausable.cairo @@ -1,6 +1,18 @@ use openzeppelin::security::pausable::Pausable::InternalImpl; use openzeppelin::security::pausable::Pausable::PausableImpl; +use openzeppelin::security::pausable::Pausable::Paused; +use openzeppelin::security::pausable::Pausable::Unpaused; use openzeppelin::security::pausable::Pausable; +use openzeppelin::tests::utils::constants::{CALLER, ZERO}; +use openzeppelin::tests::utils; +use option::OptionTrait; +use starknet::contract_address_const; +use starknet::ContractAddress; +use starknet::testing; + +// +// Setup +// fn STATE() -> Pausable::ContractState { Pausable::contract_state_for_testing() @@ -71,7 +83,11 @@ fn test_assert_not_paused_when_not_paused() { #[available_gas(2000000)] fn test_pause_when_unpaused() { let mut state = STATE(); + testing::set_caller_address(CALLER()); + InternalImpl::_pause(ref state); + + assert_event_paused(CALLER()); assert(PausableImpl::is_paused(@state), 'Should be paused'); } @@ -92,8 +108,14 @@ fn test_pause_when_paused() { #[available_gas(2000000)] fn test_unpause_when_paused() { let mut state = STATE(); + testing::set_caller_address(CALLER()); + InternalImpl::_pause(ref state); + testing::pop_log_raw(ZERO()); + InternalImpl::_unpause(ref state); + + assert_event_unpaused(CALLER()); assert(!PausableImpl::is_paused(@state), 'Should not be paused'); } @@ -105,3 +127,19 @@ fn test_unpause_when_unpaused() { assert(!PausableImpl::is_paused(@state), 'Should be paused'); InternalImpl::_unpause(ref state); } + +// +// Helpers +// + +fn assert_event_paused(account: ContractAddress) { + let event = testing::pop_log::(ZERO()).unwrap(); + assert(event.account == account, 'Invalid `account`'); + utils::assert_no_events_left(ZERO()); +} + +fn assert_event_unpaused(account: ContractAddress) { + let event = testing::pop_log::(ZERO()).unwrap(); + assert(event.account == account, 'Invalid `account`'); + utils::assert_no_events_left(ZERO()); +} diff --git a/src/tests/utils/constants.cairo b/src/tests/utils/constants.cairo index 84cc4eae4..f6fc94a3f 100644 --- a/src/tests/utils/constants.cairo +++ b/src/tests/utils/constants.cairo @@ -16,6 +16,10 @@ fn ZERO() -> ContractAddress { contract_address_const::<0>() } +fn CALLER() -> ContractAddress { + contract_address_const::<'CALLER'>() +} + fn OWNER() -> ContractAddress { contract_address_const::<'OWNER'>() } From e95def8d88cdfcea9e54ba5270ec63b5b0085e66 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 16 Aug 2023 00:39:44 +0200 Subject: [PATCH 082/124] Add testing for ERC20 events (#677) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add testing for events * feat: add tests for ownable events * feat: add tests for pausable events * feat: add tests for erc20 events * Update src/openzeppelin/tests/security/test_pausable.cairo Co-authored-by: Andrew Fleming * feat: apply review updates * feat: improve tests * feat: apply review updates * feat: apply review updates * feat: apply review updates --------- Co-authored-by: Andrew Fleming Co-authored-by: Martín Triay --- src/tests/token/test_erc20.cairo | 157 ++++++++++++++++++++----------- src/tests/utils/constants.cairo | 13 +++ 2 files changed, 117 insertions(+), 53 deletions(-) diff --git a/src/tests/token/test_erc20.cairo b/src/tests/token/test_erc20.cairo index 1303c3e1c..dd31d8e4d 100644 --- a/src/tests/token/test_erc20.cairo +++ b/src/tests/token/test_erc20.cairo @@ -1,46 +1,35 @@ use integer::BoundedInt; use integer::u256; use integer::u256_from_felt252; +use openzeppelin::tests::utils::constants::{ + ZERO, OWNER, SPENDER, RECIPIENT, NAME, SYMBOL, DECIMALS, SUPPLY, VALUE +}; +use openzeppelin::tests::utils; +use openzeppelin::token::erc20::ERC20::Approval; use openzeppelin::token::erc20::ERC20::ERC20CamelOnlyImpl; use openzeppelin::token::erc20::ERC20::ERC20Impl; use openzeppelin::token::erc20::ERC20::InternalImpl; +use openzeppelin::token::erc20::ERC20::Transfer; use openzeppelin::token::erc20::ERC20; +use option::OptionTrait; use starknet::ContractAddress; use starknet::contract_address_const; -use starknet::testing::set_caller_address; +use starknet::testing; use traits::Into; use zeroable::Zeroable; // -// Constants +// Setup // -const NAME: felt252 = 111; -const SYMBOL: felt252 = 222; -const DECIMALS: u8 = 18_u8; -const SUPPLY: u256 = 2000; -const VALUE: u256 = 300; - fn STATE() -> ERC20::ContractState { ERC20::contract_state_for_testing() } -fn OWNER() -> ContractAddress { - contract_address_const::<1>() -} -fn SPENDER() -> ContractAddress { - contract_address_const::<2>() -} -fn RECIPIENT() -> ContractAddress { - contract_address_const::<3>() -} - -// -// Setup -// fn setup() -> ERC20::ContractState { let mut state = STATE(); ERC20::constructor(ref state, NAME, SYMBOL, SUPPLY, OWNER()); + testing::pop_log_raw(ZERO()); state } @@ -67,6 +56,8 @@ fn test_constructor() { let mut state = STATE(); ERC20::constructor(ref state, NAME, SYMBOL, SUPPLY, OWNER()); + assert_only_event_transfer(ZERO(), OWNER(), SUPPLY); + assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY, 'Should eq inital_supply'); assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Should eq inital_supply'); assert(ERC20Impl::name(@state) == NAME, 'Name should be NAME'); @@ -114,7 +105,7 @@ fn test_balanceOf() { #[available_gas(2000000)] fn test_allowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE, 'Should eq VALUE'); @@ -128,8 +119,10 @@ fn test_allowance() { #[available_gas(2000000)] fn test_approve() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); assert(ERC20Impl::approve(ref state, SPENDER(), VALUE), 'Should return true'); + + assert_only_event_approval(OWNER(), SPENDER(), VALUE); assert( ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly' ); @@ -148,7 +141,7 @@ fn test_approve_from_zero() { #[should_panic(expected: ('ERC20: approve to 0', ))] fn test_approve_to_zero() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, Zeroable::zero(), VALUE); } @@ -156,9 +149,10 @@ fn test_approve_to_zero() { #[available_gas(2000000)] fn test__approve() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); InternalImpl::_approve(ref state, OWNER(), SPENDER(), VALUE); + assert_only_event_approval(OWNER(), SPENDER(), VALUE); assert( ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly' ); @@ -177,7 +171,7 @@ fn test__approve_from_zero() { #[should_panic(expected: ('ERC20: approve to 0', ))] fn test__approve_to_zero() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); InternalImpl::_approve(ref state, OWNER(), Zeroable::zero(), VALUE); } @@ -189,9 +183,10 @@ fn test__approve_to_zero() { #[available_gas(2000000)] fn test_transfer() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); assert(ERC20Impl::transfer(ref state, RECIPIENT(), VALUE), 'Should return true'); + assert_only_event_transfer(OWNER(), RECIPIENT(), VALUE); assert(ERC20Impl::balance_of(@state, RECIPIENT()) == VALUE, 'Balance should eq VALUE'); assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY - VALUE, 'Should eq supply - VALUE'); assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Total supply should not change'); @@ -203,6 +198,8 @@ fn test__transfer() { let mut state = setup(); InternalImpl::_transfer(ref state, OWNER(), RECIPIENT(), VALUE); + + assert_only_event_transfer(OWNER(), RECIPIENT(), VALUE); assert(ERC20Impl::balance_of(@state, RECIPIENT()) == VALUE, 'Balance should eq amount'); assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY - VALUE, 'Should eq supply - amount'); assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Total supply should not change'); @@ -213,7 +210,7 @@ fn test__transfer() { #[should_panic(expected: ('u256_sub Overflow', ))] fn test__transfer_not_enough_balance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); let balance_plus_one = SUPPLY + 1; InternalImpl::_transfer(ref state, OWNER(), RECIPIENT(), balance_plus_one); @@ -243,12 +240,16 @@ fn test__transfer_to_zero() { #[available_gas(2000000)] fn test_transfer_from() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); + testing::pop_log_raw(ZERO()); - set_caller_address(SPENDER()); + testing::set_caller_address(SPENDER()); assert(ERC20Impl::transfer_from(ref state, OWNER(), RECIPIENT(), VALUE), 'Should return true'); + assert_event_approval(OWNER(), SPENDER(), 0); + assert_only_event_transfer(OWNER(), RECIPIENT(), VALUE); + assert(ERC20Impl::balance_of(@state, RECIPIENT()) == VALUE, 'Should eq amount'); assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY - VALUE, 'Should eq suppy - amount'); assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == 0, 'Should eq 0'); @@ -259,10 +260,10 @@ fn test_transfer_from() { #[available_gas(2000000)] fn test_transfer_from_doesnt_consume_infinite_allowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), BoundedInt::max()); - set_caller_address(SPENDER()); + testing::set_caller_address(SPENDER()); ERC20Impl::transfer_from(ref state, OWNER(), RECIPIENT(), VALUE); assert( @@ -276,10 +277,10 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { #[should_panic(expected: ('u256_sub Overflow', ))] fn test_transfer_from_greater_than_allowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - set_caller_address(SPENDER()); + testing::set_caller_address(SPENDER()); let allowance_plus_one = VALUE + 1; ERC20Impl::transfer_from(ref state, OWNER(), RECIPIENT(), allowance_plus_one); } @@ -289,10 +290,10 @@ fn test_transfer_from_greater_than_allowance() { #[should_panic(expected: ('ERC20: transfer to 0', ))] fn test_transfer_from_to_zero_address() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - set_caller_address(SPENDER()); + testing::set_caller_address(SPENDER()); ERC20Impl::transfer_from(ref state, OWNER(), Zeroable::zero(), VALUE); } @@ -308,15 +309,19 @@ fn test_transfer_from_from_zero_address() { #[available_gas(2000000)] fn test_transferFrom() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); + testing::pop_log_raw(ZERO()); - set_caller_address(SPENDER()); - + testing::set_caller_address(SPENDER()); assert( ERC20CamelOnlyImpl::transferFrom(ref state, OWNER(), RECIPIENT(), VALUE), 'Should return true' ); + + assert_event_approval(OWNER(), SPENDER(), 0); + assert_only_event_transfer(OWNER(), RECIPIENT(), VALUE); + assert(ERC20CamelOnlyImpl::balanceOf(@state, RECIPIENT()) == VALUE, 'Should eq amount'); assert( ERC20CamelOnlyImpl::balanceOf(@state, OWNER()) == SUPPLY - VALUE, 'Should eq suppy - amount' @@ -329,10 +334,10 @@ fn test_transferFrom() { #[available_gas(2000000)] fn test_transferFrom_doesnt_consume_infinite_allowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), BoundedInt::max()); - set_caller_address(SPENDER()); + testing::set_caller_address(SPENDER()); ERC20CamelOnlyImpl::transferFrom(ref state, OWNER(), RECIPIENT(), VALUE); assert( @@ -346,10 +351,10 @@ fn test_transferFrom_doesnt_consume_infinite_allowance() { #[should_panic(expected: ('u256_sub Overflow', ))] fn test_transferFrom_greater_than_allowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - set_caller_address(SPENDER()); + testing::set_caller_address(SPENDER()); let allowance_plus_one = VALUE + 1; ERC20CamelOnlyImpl::transferFrom(ref state, OWNER(), RECIPIENT(), allowance_plus_one); } @@ -359,10 +364,10 @@ fn test_transferFrom_greater_than_allowance() { #[should_panic(expected: ('ERC20: transfer to 0', ))] fn test_transferFrom_to_zero_address() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - set_caller_address(SPENDER()); + testing::set_caller_address(SPENDER()); ERC20CamelOnlyImpl::transferFrom(ref state, OWNER(), Zeroable::zero(), VALUE); } @@ -382,10 +387,13 @@ fn test_transferFrom_from_zero_address() { #[available_gas(2000000)] fn test_increase_allowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); + testing::pop_log_raw(ZERO()); assert(ERC20::increase_allowance(ref state, SPENDER(), VALUE), 'Should return true'); + + assert_only_event_approval(OWNER(), SPENDER(), VALUE * 2); assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); } @@ -394,7 +402,7 @@ fn test_increase_allowance() { #[should_panic(expected: ('ERC20: approve to 0', ))] fn test_increase_allowance_to_zero_address() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20::increase_allowance(ref state, Zeroable::zero(), VALUE); } @@ -410,10 +418,13 @@ fn test_increase_allowance_from_zero_address() { #[available_gas(2000000)] fn test_increaseAllowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); + testing::pop_log_raw(ZERO()); assert(ERC20::increaseAllowance(ref state, SPENDER(), VALUE), 'Should return true'); + + assert_only_event_approval(OWNER(), SPENDER(), 2 * VALUE); assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); } @@ -422,7 +433,7 @@ fn test_increaseAllowance() { #[should_panic(expected: ('ERC20: approve to 0', ))] fn test_increaseAllowance_to_zero_address() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20::increaseAllowance(ref state, Zeroable::zero(), VALUE); } @@ -442,10 +453,13 @@ fn test_increaseAllowance_from_zero_address() { #[available_gas(2000000)] fn test_decrease_allowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); + testing::pop_log_raw(ZERO()); assert(ERC20::decrease_allowance(ref state, SPENDER(), VALUE), 'Should return true'); + + assert_only_event_approval(OWNER(), SPENDER(), 0); assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); } @@ -454,7 +468,7 @@ fn test_decrease_allowance() { #[should_panic(expected: ('u256_sub Overflow', ))] fn test_decrease_allowance_to_zero_address() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20::decrease_allowance(ref state, Zeroable::zero(), VALUE); } @@ -470,10 +484,13 @@ fn test_decrease_allowance_from_zero_address() { #[available_gas(2000000)] fn test_decreaseAllowance() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); + testing::pop_log_raw(ZERO()); assert(ERC20::decreaseAllowance(ref state, SPENDER(), VALUE), 'Should return true'); + + assert_only_event_approval(OWNER(), SPENDER(), 0); assert(ERC20Impl::allowance(@state, OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); } @@ -482,7 +499,7 @@ fn test_decreaseAllowance() { #[should_panic(expected: ('u256_sub Overflow', ))] fn test_decreaseAllowance_to_zero_address() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC20::decreaseAllowance(ref state, Zeroable::zero(), VALUE); } @@ -504,7 +521,11 @@ fn test__spend_allowance_not_unlimited() { let mut state = setup(); InternalImpl::_approve(ref state, OWNER(), SPENDER(), SUPPLY); + testing::pop_log_raw(ZERO()); + InternalImpl::_spend_allowance(ref state, OWNER(), SPENDER(), VALUE); + + assert_only_event_approval(OWNER(), SPENDER(), SUPPLY - VALUE); assert( ERC20Impl::allowance(@state, OWNER(), SPENDER()) == SUPPLY - VALUE, 'Should eq supply - amount' @@ -536,6 +557,7 @@ fn test__mint() { let mut state = STATE(); InternalImpl::_mint(ref state, OWNER(), VALUE); + assert_only_event_transfer(ZERO(), OWNER(), VALUE); assert(ERC20Impl::balance_of(@state, OWNER()) == VALUE, 'Should eq amount'); assert(ERC20Impl::total_supply(@state) == VALUE, 'Should eq total supply'); } @@ -558,6 +580,7 @@ fn test__burn() { let mut state = setup(); InternalImpl::_burn(ref state, OWNER(), VALUE); + assert_only_event_transfer(OWNER(), ZERO(), VALUE); assert(ERC20Impl::total_supply(@state) == SUPPLY - VALUE, 'Should eq supply - amount'); assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY - VALUE, 'Should eq supply - amount'); } @@ -569,3 +592,31 @@ fn test__burn_from_zero() { let mut state = setup(); InternalImpl::_burn(ref state, Zeroable::zero(), VALUE); } + +// +// Helpers +// + +fn assert_event_approval(owner: ContractAddress, spender: ContractAddress, value: u256) { + let event = testing::pop_log::(ZERO()).unwrap(); + assert(event.owner == owner, 'Invalid `owner`'); + assert(event.spender == spender, 'Invalid `spender`'); + assert(event.value == value, 'Invalid `value`'); +} + +fn assert_only_event_approval(owner: ContractAddress, spender: ContractAddress, value: u256) { + assert_event_approval(owner, spender, value); + utils::assert_no_events_left(ZERO()); +} + +fn assert_event_transfer(from: ContractAddress, to: ContractAddress, value: u256) { + let event = testing::pop_log::(ZERO()).unwrap(); + assert(event.from == from, 'Invalid `from`'); + assert(event.to == to, 'Invalid `to`'); + assert(event.value == value, 'Invalid `value`'); +} + +fn assert_only_event_transfer(from: ContractAddress, to: ContractAddress, value: u256) { + assert_event_transfer(from, to, value); + utils::assert_no_events_left(ZERO()); +} diff --git a/src/tests/utils/constants.cairo b/src/tests/utils/constants.cairo index f6fc94a3f..c27c2f1ce 100644 --- a/src/tests/utils/constants.cairo +++ b/src/tests/utils/constants.cairo @@ -1,6 +1,11 @@ use starknet::ContractAddress; use starknet::contract_address_const; +const NAME: felt252 = 'NAME'; +const SYMBOL: felt252 = 'SYMBOL'; +const DECIMALS: u8 = 18_u8; +const SUPPLY: u256 = 2000; +const VALUE: u256 = 300; const ROLE: felt252 = 'ROLE'; const OTHER_ROLE: felt252 = 'OTHER_ROLE'; @@ -35,3 +40,11 @@ fn OTHER() -> ContractAddress { fn OTHER_ADMIN() -> ContractAddress { contract_address_const::<'OTHER_ADMIN'>() } + +fn SPENDER() -> ContractAddress { + contract_address_const::<'SPENDER'>() +} + +fn RECIPIENT() -> ContractAddress { + contract_address_const::<'RECIPIENT'>() +} From 77089c151cc99e94ed5f34bd8372fe6af59893cd Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 15 Aug 2023 18:45:56 -0400 Subject: [PATCH 083/124] Add mint to erc721 preset constructor (#700) * add _mint to constructor * add constructor assertions * fix formatting --- src/tests/token/test_erc721.cairo | 5 +++-- src/token/erc721/erc721.cairo | 9 ++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index 45bd6c39e..51731a13b 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -104,11 +104,12 @@ fn setup_camel_account() -> ContractAddress { #[available_gas(20000000)] fn test_constructor() { let mut state = STATE(); - ERC721::constructor(ref state, NAME, SYMBOL); + ERC721::constructor(ref state, NAME, SYMBOL, OWNER(), TOKEN_ID); assert(ERC721MetadataImpl::name(@state) == NAME, 'Name should be NAME'); assert(ERC721MetadataImpl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC721Impl::balance_of(@state, OWNER()) == 0, 'Balance should be zero'); + assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance should be one'); + assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'OWNER should be owner'); assert( SRC5Impl::supports_interface(@state, erc721::interface::IERC721_ID), 'Missing interface ID' diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index 5a5b56b51..32a265c06 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -61,8 +61,15 @@ mod ERC721 { } #[constructor] - fn constructor(ref self: ContractState, name: felt252, symbol: felt252) { + fn constructor( + ref self: ContractState, + name: felt252, + symbol: felt252, + recipient: ContractAddress, + token_id: u256 + ) { self.initializer(name, symbol); + self._mint(recipient, token_id); } // From 3e08fa6d262d7c50422b760b6b945aa2bfaa6cbb Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 17 Aug 2023 00:50:04 +0200 Subject: [PATCH 084/124] Add testing for ERC721 events (#678) * feat: add testing for events * feat: add tests for ownable events * feat: add tests for pausable events * feat: add tests for erc20 events * feat: add tests for erc721 events * Update src/openzeppelin/tests/security/test_pausable.cairo Co-authored-by: Andrew Fleming * feat: apply review updates * feat: add test helper for events * feat: improve tests * feat: apply review updates * feat: apply review updates * feat: apply review updates * feat: apply review updates * feat: apply review updates --------- Co-authored-by: Andrew Fleming --- src/tests/access/test_accesscontrol.cairo | 10 +- .../access/test_dual_accesscontrol.cairo | 4 +- src/tests/access/test_ownable.cairo | 4 +- src/tests/security/test_pausable.cairo | 6 +- src/tests/token/test_erc20.cairo | 20 +- src/tests/token/test_erc721.cairo | 396 +++++++++++------- src/tests/utils.cairo | 6 +- src/tests/utils/constants.cairo | 7 + 8 files changed, 272 insertions(+), 181 deletions(-) diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index cea50e7d4..8dd4af473 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -27,7 +27,7 @@ fn STATE() -> AccessControl::ContractState { fn setup() -> AccessControl::ContractState { let mut state = STATE(); InternalImpl::_grant_role(ref state, DEFAULT_ADMIN_ROLE, ADMIN()); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); state } @@ -224,7 +224,7 @@ fn test_revoke_role_for_granted_role() { testing::set_caller_address(ADMIN()); AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); @@ -239,7 +239,7 @@ fn test_revokeRole_for_granted_role() { testing::set_caller_address(ADMIN()); AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); @@ -320,7 +320,7 @@ fn test_renounce_role_for_granted_role() { testing::set_caller_address(ADMIN()); AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); testing::set_caller_address(AUTHORIZED()); AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); @@ -336,7 +336,7 @@ fn test_renounceRole_for_granted_role() { testing::set_caller_address(ADMIN()); AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); testing::set_caller_address(AUTHORIZED()); AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index 2d6a17be4..094f44a21 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -1,10 +1,10 @@ use array::ArrayTrait; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; -use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; -use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; +use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index c27af64d6..214329b9b 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -1,9 +1,9 @@ -use openzeppelin::access::ownable::Ownable; use openzeppelin::access::ownable::Ownable::InternalImpl; use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; use openzeppelin::access::ownable::Ownable::OwnableImpl; use openzeppelin::access::ownable::Ownable::OwnershipTransferred; use openzeppelin::access::ownable::Ownable::_owner::InternalContractStateTrait; +use openzeppelin::access::ownable::Ownable; use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; use openzeppelin::tests::utils; use option::OptionTrait; @@ -23,7 +23,7 @@ fn STATE() -> Ownable::ContractState { fn setup() -> Ownable::ContractState { let mut state = STATE(); InternalImpl::initializer(ref state, OWNER()); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); state } diff --git a/src/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo index 7f3feb8e7..f48a2904b 100644 --- a/src/tests/security/test_pausable.cairo +++ b/src/tests/security/test_pausable.cairo @@ -111,7 +111,7 @@ fn test_unpause_when_paused() { testing::set_caller_address(CALLER()); InternalImpl::_pause(ref state); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); InternalImpl::_unpause(ref state); @@ -133,13 +133,13 @@ fn test_unpause_when_unpaused() { // fn assert_event_paused(account: ContractAddress) { - let event = testing::pop_log::(ZERO()).unwrap(); + let event = utils::pop_log::(ZERO()).unwrap(); assert(event.account == account, 'Invalid `account`'); utils::assert_no_events_left(ZERO()); } fn assert_event_unpaused(account: ContractAddress) { - let event = testing::pop_log::(ZERO()).unwrap(); + let event = utils::pop_log::(ZERO()).unwrap(); assert(event.account == account, 'Invalid `account`'); utils::assert_no_events_left(ZERO()); } diff --git a/src/tests/token/test_erc20.cairo b/src/tests/token/test_erc20.cairo index dd31d8e4d..a2e609a1b 100644 --- a/src/tests/token/test_erc20.cairo +++ b/src/tests/token/test_erc20.cairo @@ -29,7 +29,7 @@ fn STATE() -> ERC20::ContractState { fn setup() -> ERC20::ContractState { let mut state = STATE(); ERC20::constructor(ref state, NAME, SYMBOL, SUPPLY, OWNER()); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); state } @@ -242,7 +242,7 @@ fn test_transfer_from() { let mut state = setup(); testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); testing::set_caller_address(SPENDER()); assert(ERC20Impl::transfer_from(ref state, OWNER(), RECIPIENT(), VALUE), 'Should return true'); @@ -311,7 +311,7 @@ fn test_transferFrom() { let mut state = setup(); testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); testing::set_caller_address(SPENDER()); assert( @@ -389,7 +389,7 @@ fn test_increase_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); assert(ERC20::increase_allowance(ref state, SPENDER(), VALUE), 'Should return true'); @@ -420,7 +420,7 @@ fn test_increaseAllowance() { let mut state = setup(); testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); assert(ERC20::increaseAllowance(ref state, SPENDER(), VALUE), 'Should return true'); @@ -455,7 +455,7 @@ fn test_decrease_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); assert(ERC20::decrease_allowance(ref state, SPENDER(), VALUE), 'Should return true'); @@ -486,7 +486,7 @@ fn test_decreaseAllowance() { let mut state = setup(); testing::set_caller_address(OWNER()); ERC20Impl::approve(ref state, SPENDER(), VALUE); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); assert(ERC20::decreaseAllowance(ref state, SPENDER(), VALUE), 'Should return true'); @@ -521,7 +521,7 @@ fn test__spend_allowance_not_unlimited() { let mut state = setup(); InternalImpl::_approve(ref state, OWNER(), SPENDER(), SUPPLY); - testing::pop_log_raw(ZERO()); + utils::drop_event(ZERO()); InternalImpl::_spend_allowance(ref state, OWNER(), SPENDER(), VALUE); @@ -598,7 +598,7 @@ fn test__burn_from_zero() { // fn assert_event_approval(owner: ContractAddress, spender: ContractAddress, value: u256) { - let event = testing::pop_log::(ZERO()).unwrap(); + let event = utils::pop_log::(ZERO()).unwrap(); assert(event.owner == owner, 'Invalid `owner`'); assert(event.spender == spender, 'Invalid `spender`'); assert(event.value == value, 'Invalid `value`'); @@ -610,7 +610,7 @@ fn assert_only_event_approval(owner: ContractAddress, spender: ContractAddress, } fn assert_event_transfer(from: ContractAddress, to: ContractAddress, value: u256) { - let event = testing::pop_log::(ZERO()).unwrap(); + let event = utils::pop_log::(ZERO()).unwrap(); assert(event.from == from, 'Invalid `from`'); assert(event.to == to, 'Invalid `to`'); assert(event.value == value, 'Invalid `value`'); diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index 51731a13b..b39b24a01 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -1,9 +1,9 @@ use ERC721::_owners::InternalContractStateTrait as OwnersTrait; use ERC721::_token_approvals::InternalContractStateTrait as TokenApprovalsTrait; + use array::ArrayTrait; use integer::u256; use integer::u256_from_felt252; - use openzeppelin::account::Account; use openzeppelin::introspection::src5; use openzeppelin::introspection; @@ -13,50 +13,23 @@ use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; use openzeppelin::tests::mocks::erc721_receiver::FAILURE; use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils::constants::{ + ZERO, OWNER, RECIPIENT, SPENDER, OPERATOR, OTHER, NAME, SYMBOL, URI, TOKEN_ID, PUBKEY, +}; use openzeppelin::tests::utils; -use openzeppelin::token::erc721::ERC721::ERC721CamelOnlyImpl; -use openzeppelin::token::erc721::ERC721::ERC721Impl; -use openzeppelin::token::erc721::ERC721::ERC721MetadataCamelOnlyImpl; -use openzeppelin::token::erc721::ERC721::ERC721MetadataImpl; -use openzeppelin::token::erc721::ERC721::InternalImpl; -use openzeppelin::token::erc721::ERC721::SRC5CamelImpl; -use openzeppelin::token::erc721::ERC721::SRC5Impl; +use openzeppelin::token::erc721::ERC721::{ + Approval, ApprovalForAll, ERC721CamelOnlyImpl, ERC721Impl, ERC721MetadataCamelOnlyImpl, + ERC721MetadataImpl, InternalImpl, SRC5CamelImpl, SRC5Impl, Transfer, +}; use openzeppelin::token::erc721::ERC721; use openzeppelin::token::erc721; -use starknet::ContractAddress; +use option::OptionTrait; use starknet::contract_address_const; -use starknet::testing::set_caller_address; +use starknet::ContractAddress; +use starknet::testing; use traits::Into; use zeroable::Zeroable; -const NAME: felt252 = 111; -const SYMBOL: felt252 = 222; -const URI: felt252 = 333; -const TOKEN_ID: u256 = 7; -const PUBKEY: felt252 = 444; - -fn STATE() -> ERC721::ContractState { - ERC721::contract_state_for_testing() -} -fn ZERO() -> ContractAddress { - Zeroable::zero() -} -fn OWNER() -> ContractAddress { - contract_address_const::<10>() -} -fn RECIPIENT() -> ContractAddress { - contract_address_const::<20>() -} -fn SPENDER() -> ContractAddress { - contract_address_const::<30>() -} -fn OPERATOR() -> ContractAddress { - contract_address_const::<40>() -} -fn OTHER() -> ContractAddress { - contract_address_const::<50>() -} - fn DATA(success: bool) -> Span { let mut data = array![]; if success { @@ -71,10 +44,15 @@ fn DATA(success: bool) -> Span { // Setup // +fn STATE() -> ERC721::ContractState { + ERC721::contract_state_for_testing() +} + fn setup() -> ERC721::ContractState { let mut state = STATE(); InternalImpl::initializer(ref state, NAME, SYMBOL); InternalImpl::_mint(ref state, OWNER(), TOKEN_ID); + utils::drop_event(ZERO()); state } @@ -235,8 +213,10 @@ fn test__exists() { fn test_approve_from_owner() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721Impl::approve(ref state, SPENDER(), TOKEN_ID); + assert_event_approval(OWNER(), SPENDER(), TOKEN_ID); + assert( ERC721Impl::get_approved(@state, TOKEN_ID) == SPENDER(), 'Spender not approved correctly' ); @@ -247,11 +227,14 @@ fn test_approve_from_owner() { fn test_approve_from_operator() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721Impl::approve(ref state, SPENDER(), TOKEN_ID); + assert_event_approval(OWNER(), SPENDER(), TOKEN_ID); + assert( ERC721Impl::get_approved(@state, TOKEN_ID) == SPENDER(), 'Spender not approved correctly' ); @@ -263,7 +246,7 @@ fn test_approve_from_operator() { fn test_approve_from_unauthorized() { let mut state = setup(); - set_caller_address(OTHER()); + testing::set_caller_address(OTHER()); ERC721Impl::approve(ref state, SPENDER(), TOKEN_ID); } @@ -273,7 +256,7 @@ fn test_approve_from_unauthorized() { fn test_approve_to_owner() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721Impl::approve(ref state, OWNER(), TOKEN_ID); } @@ -290,6 +273,8 @@ fn test_approve_nonexistent() { fn test__approve() { let mut state = setup(); InternalImpl::_approve(ref state, SPENDER(), TOKEN_ID); + assert_event_approval(OWNER(), SPENDER(), TOKEN_ID); + assert( ERC721Impl::get_approved(@state, TOKEN_ID) == SPENDER(), 'Spender not approved correctly' ); @@ -319,17 +304,21 @@ fn test__approve_nonexistent() { #[available_gas(20000000)] fn test_set_approval_for_all() { let mut state = STATE(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); assert(!ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), 'Invalid default value'); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + assert_event_approval_for_all(OWNER(), OPERATOR(), true); + assert( ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), 'Operator not approved correctly' ); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), false); + assert_event_approval_for_all(OWNER(), OPERATOR(), false); + assert( !ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), 'Approval not revoked correctly' @@ -341,7 +330,7 @@ fn test_set_approval_for_all() { #[should_panic(expected: ('ERC721: self approval', ))] fn test_set_approval_for_all_owner_equal_operator_true() { let mut state = STATE(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721Impl::set_approval_for_all(ref state, OWNER(), true); } @@ -350,7 +339,7 @@ fn test_set_approval_for_all_owner_equal_operator_true() { #[should_panic(expected: ('ERC721: self approval', ))] fn test_set_approval_for_all_owner_equal_operator_false() { let mut state = STATE(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721Impl::set_approval_for_all(ref state, OWNER(), false); } @@ -361,12 +350,16 @@ fn test__set_approval_for_all() { assert(!ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), 'Invalid default value'); InternalImpl::_set_approval_for_all(ref state, OWNER(), OPERATOR(), true); + assert_event_approval_for_all(OWNER(), OPERATOR(), true); + assert( ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), 'Operator not approved correctly' ); InternalImpl::_set_approval_for_all(ref state, OWNER(), OPERATOR(), false); + assert_event_approval_for_all(OWNER(), OPERATOR(), false); + assert( !ERC721Impl::is_approved_for_all(@state, OWNER(), OPERATOR()), 'Operator not approved correctly' @@ -402,14 +395,16 @@ fn test_transfer_from_owner() { let recipient = RECIPIENT(); // set approval to check reset InternalImpl::_approve(ref state, OTHER(), token_id); + utils::drop_event(ZERO()); - assert_state_before_transfer(token_id, owner, recipient); + assert_state_before_transfer(owner, recipient, token_id); assert(ERC721Impl::get_approved(@state, token_id) == OTHER(), 'Approval not implicitly reset'); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::transfer_from(ref state, owner, recipient, token_id); + assert_event_transfer(owner, recipient, token_id); - assert_state_after_transfer(token_id, owner, recipient); + assert_state_after_transfer(owner, recipient, token_id); } #[test] @@ -421,14 +416,16 @@ fn test_transferFrom_owner() { let recipient = RECIPIENT(); // set approval to check reset InternalImpl::_approve(ref state, OTHER(), token_id); + utils::drop_event(ZERO()); - assert_state_before_transfer(token_id, owner, recipient); + assert_state_before_transfer(owner, recipient, token_id); assert(ERC721Impl::get_approved(@state, token_id) == OTHER(), 'Approval not implicitly reset'); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::transferFrom(ref state, owner, recipient, token_id); + assert_event_transfer(owner, recipient, token_id); - assert_state_after_transfer(token_id, owner, recipient); + assert_state_after_transfer(owner, recipient, token_id); } #[test] @@ -452,7 +449,7 @@ fn test_transferFrom_nonexistent() { #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test_transfer_from_to_zero() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721Impl::transfer_from(ref state, OWNER(), ZERO(), TOKEN_ID); } @@ -462,7 +459,7 @@ fn test_transfer_from_to_zero() { fn test_transferFrom_to_zero() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721CamelOnlyImpl::transferFrom(ref state, OWNER(), ZERO(), TOKEN_ID); } @@ -474,8 +471,9 @@ fn test_transfer_from_to_owner() { assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership before'); assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner before'); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721Impl::transfer_from(ref state, OWNER(), OWNER(), TOKEN_ID); + assert_event_transfer(OWNER(), OWNER(), TOKEN_ID); assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership after'); assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner after'); @@ -489,8 +487,9 @@ fn test_transferFrom_to_owner() { assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership before'); assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner before'); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721CamelOnlyImpl::transferFrom(ref state, OWNER(), OWNER(), TOKEN_ID); + assert_event_transfer(OWNER(), OWNER(), TOKEN_ID); assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership after'); assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner after'); @@ -503,15 +502,17 @@ fn test_transfer_from_approved() { let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); - assert_state_before_transfer(token_id, owner, recipient); + assert_state_before_transfer(owner, recipient, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::approve(ref state, OPERATOR(), token_id); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721Impl::transfer_from(ref state, owner, recipient, token_id); + assert_event_transfer(owner, recipient, token_id); - assert_state_after_transfer(token_id, owner, recipient); + assert_state_after_transfer(owner, recipient, token_id); } #[test] @@ -521,15 +522,17 @@ fn test_transferFrom_approved() { let token_id = TOKEN_ID; let owner = OWNER(); let recipient = RECIPIENT(); - assert_state_before_transfer(token_id, owner, recipient); + assert_state_before_transfer(owner, recipient, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::approve(ref state, OPERATOR(), token_id); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721CamelOnlyImpl::transferFrom(ref state, owner, recipient, token_id); + assert_event_transfer(owner, recipient, token_id); - assert_state_after_transfer(token_id, owner, recipient); + assert_state_after_transfer(owner, recipient, token_id); } #[test] @@ -540,15 +543,17 @@ fn test_transfer_from_approved_for_all() { let owner = OWNER(); let recipient = RECIPIENT(); - assert_state_before_transfer(token_id, owner, recipient); + assert_state_before_transfer(owner, recipient, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721Impl::transfer_from(ref state, owner, recipient, token_id); + assert_event_transfer(owner, recipient, token_id); - assert_state_after_transfer(token_id, owner, recipient); + assert_state_after_transfer(owner, recipient, token_id); } #[test] @@ -559,15 +564,17 @@ fn test_transferFrom_approved_for_all() { let owner = OWNER(); let recipient = RECIPIENT(); - assert_state_before_transfer(token_id, owner, recipient); + assert_state_before_transfer(owner, recipient, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721CamelOnlyImpl::transferFrom(ref state, owner, recipient, token_id); + assert_event_transfer(owner, recipient, token_id); - assert_state_after_transfer(token_id, owner, recipient); + assert_state_after_transfer(owner, recipient, token_id); } #[test] @@ -575,7 +582,7 @@ fn test_transferFrom_approved_for_all() { #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_transfer_from_unauthorized() { let mut state = setup(); - set_caller_address(OTHER()); + testing::set_caller_address(OTHER()); ERC721Impl::transfer_from(ref state, OWNER(), RECIPIENT(), TOKEN_ID); } @@ -584,7 +591,7 @@ fn test_transfer_from_unauthorized() { #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_transferFrom_unauthorized() { let mut state = setup(); - set_caller_address(OTHER()); + testing::set_caller_address(OTHER()); ERC721CamelOnlyImpl::transferFrom(ref state, OWNER(), RECIPIENT(), TOKEN_ID); } @@ -600,12 +607,13 @@ fn test_safe_transfer_from_to_account() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, account); + assert_state_before_transfer(owner, account, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, account, token_id, DATA(true)); + assert_event_transfer(owner, account, token_id); - assert_state_after_transfer(token_id, owner, account); + assert_state_after_transfer(owner, account, token_id); } #[test] @@ -616,12 +624,13 @@ fn test_safeTransferFrom_to_account() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, account); + assert_state_before_transfer(owner, account, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, account, token_id, DATA(true)); + assert_event_transfer(owner, account, token_id); - assert_state_after_transfer(token_id, owner, account); + assert_state_after_transfer(owner, account, token_id); } #[test] @@ -632,12 +641,13 @@ fn test_safe_transfer_from_to_account_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, account); + assert_state_before_transfer(owner, account, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, account, token_id, DATA(true)); + assert_event_transfer(owner, account, token_id); - assert_state_after_transfer(token_id, owner, account); + assert_state_after_transfer(owner, account, token_id); } #[test] @@ -648,12 +658,13 @@ fn test_safeTransferFrom_to_account_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, account); + assert_state_before_transfer(owner, account, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, account, token_id, DATA(true)); + assert_event_transfer(owner, account, token_id); - assert_state_after_transfer(token_id, owner, account); + assert_state_after_transfer(owner, account, token_id); } #[test] @@ -664,12 +675,13 @@ fn test_safe_transfer_from_to_receiver() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -680,12 +692,13 @@ fn test_safeTransferFrom_to_receiver() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -696,12 +709,13 @@ fn test_safe_transfer_from_to_receiver_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -712,12 +726,13 @@ fn test_safeTransferFrom_to_receiver_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -729,7 +744,7 @@ fn test_safe_transfer_from_to_receiver_failure() { let token_id = TOKEN_ID; let owner = OWNER(); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(false)); } @@ -742,7 +757,7 @@ fn test_safeTransferFrom_to_receiver_failure() { let token_id = TOKEN_ID; let owner = OWNER(); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(false)); } @@ -755,7 +770,7 @@ fn test_safe_transfer_from_to_receiver_failure_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(false)); } @@ -768,7 +783,7 @@ fn test_safeTransferFrom_to_receiver_failure_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(false)); } @@ -781,7 +796,7 @@ fn test_safe_transfer_from_to_non_receiver() { let token_id = TOKEN_ID; let owner = OWNER(); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, recipient, token_id, DATA(true)); } @@ -794,7 +809,7 @@ fn test_safeTransferFrom_to_non_receiver() { let token_id = TOKEN_ID; let owner = OWNER(); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, recipient, token_id, DATA(true)); } @@ -819,7 +834,7 @@ fn test_safeTransferFrom_nonexistent() { #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test_safe_transfer_from_to_zero() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721Impl::safe_transfer_from(ref state, OWNER(), ZERO(), TOKEN_ID, DATA(true)); } @@ -828,7 +843,7 @@ fn test_safe_transfer_from_to_zero() { #[should_panic(expected: ('ERC721: invalid receiver', ))] fn test_safeTransferFrom_to_zero() { let mut state = setup(); - set_caller_address(OWNER()); + testing::set_caller_address(OWNER()); ERC721CamelOnlyImpl::safeTransferFrom(ref state, OWNER(), ZERO(), TOKEN_ID, DATA(true)); } @@ -840,12 +855,14 @@ fn test_safe_transfer_from_to_owner() { let owner = setup_receiver(); InternalImpl::initializer(ref state, NAME, SYMBOL); InternalImpl::_mint(ref state, owner, token_id); + utils::drop_event(ZERO()); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, owner, token_id, DATA(true)); + assert_event_transfer(owner, owner, token_id); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership after'); assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner after'); @@ -859,12 +876,14 @@ fn test_safeTransferFrom_to_owner() { let owner = setup_receiver(); InternalImpl::initializer(ref state, NAME, SYMBOL); InternalImpl::_mint(ref state, owner, token_id); + utils::drop_event(ZERO()); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, owner, token_id, DATA(true)); + assert_event_transfer(owner, owner, token_id); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership after'); assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner after'); @@ -878,12 +897,14 @@ fn test_safe_transfer_from_to_owner_camel() { let owner = setup_camel_receiver(); InternalImpl::initializer(ref state, NAME, SYMBOL); InternalImpl::_mint(ref state, owner, token_id); + utils::drop_event(ZERO()); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::safe_transfer_from(ref state, owner, owner, token_id, DATA(true)); + assert_event_transfer(owner, owner, token_id); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership after'); assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner after'); @@ -897,12 +918,14 @@ fn test_safeTransferFrom_to_owner_camel() { let owner = setup_camel_receiver(); InternalImpl::initializer(ref state, NAME, SYMBOL); InternalImpl::_mint(ref state, owner, token_id); + utils::drop_event(ZERO()); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner before'); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, owner, token_id, DATA(true)); + assert_event_transfer(owner, owner, token_id); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership after'); assert(ERC721Impl::balance_of(@state, owner) == 1, 'Balance of owner after'); @@ -916,15 +939,17 @@ fn test_safe_transfer_from_approved() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::approve(ref state, OPERATOR(), token_id); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -935,15 +960,17 @@ fn test_safeTransferFrom_approved() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::approve(ref state, OPERATOR(), token_id); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -954,15 +981,17 @@ fn test_safe_transfer_from_approved_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::approve(ref state, OPERATOR(), token_id); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -973,15 +1002,17 @@ fn test_safeTransferFrom_approved_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::approve(ref state, OPERATOR(), token_id); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -992,15 +1023,17 @@ fn test_safe_transfer_from_approved_for_all() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -1011,15 +1044,17 @@ fn test_safeTransferFrom_approved_for_all() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -1030,15 +1065,17 @@ fn test_safe_transfer_from_approved_for_all_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721Impl::safe_transfer_from(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -1049,15 +1086,17 @@ fn test_safeTransferFrom_approved_for_all_camel() { let token_id = TOKEN_ID; let owner = OWNER(); - assert_state_before_transfer(token_id, owner, receiver); + assert_state_before_transfer(owner, receiver, token_id); - set_caller_address(owner); + testing::set_caller_address(owner); ERC721Impl::set_approval_for_all(ref state, OPERATOR(), true); + utils::drop_event(ZERO()); - set_caller_address(OPERATOR()); + testing::set_caller_address(OPERATOR()); ERC721CamelOnlyImpl::safeTransferFrom(ref state, owner, receiver, token_id, DATA(true)); + assert_event_transfer(owner, receiver, token_id); - assert_state_after_transfer(token_id, owner, receiver); + assert_state_after_transfer(owner, receiver, token_id); } #[test] @@ -1065,7 +1104,7 @@ fn test_safeTransferFrom_approved_for_all_camel() { #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_safe_transfer_from_unauthorized() { let mut state = setup(); - set_caller_address(OTHER()); + testing::set_caller_address(OTHER()); ERC721Impl::safe_transfer_from(ref state, OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } @@ -1074,7 +1113,7 @@ fn test_safe_transfer_from_unauthorized() { #[should_panic(expected: ('ERC721: unauthorized caller', ))] fn test_safeTransferFrom_unauthorized() { let mut state = setup(); - set_caller_address(OTHER()); + testing::set_caller_address(OTHER()); ERC721CamelOnlyImpl::safeTransferFrom(ref state, OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } @@ -1090,9 +1129,12 @@ fn test__transfer() { let owner = OWNER(); let recipient = RECIPIENT(); - assert_state_before_transfer(token_id, owner, recipient); + assert_state_before_transfer(owner, recipient, token_id); + InternalImpl::_transfer(ref state, owner, recipient, token_id); - assert_state_after_transfer(token_id, owner, recipient); + assert_event_transfer(owner, recipient, token_id); + + assert_state_after_transfer(owner, recipient, token_id); } #[test] @@ -1131,8 +1173,10 @@ fn test__mint() { let token_id = TOKEN_ID; assert_state_before_mint(recipient); - InternalImpl::_mint(ref state, RECIPIENT(), TOKEN_ID); - assert_state_after_mint(token_id, recipient); + InternalImpl::_mint(ref state, recipient, TOKEN_ID); + assert_event_transfer(ZERO(), recipient, token_id); + + assert_state_after_mint(recipient, token_id); } #[test] @@ -1164,7 +1208,9 @@ fn test__safe_mint_to_receiver() { assert_state_before_mint(recipient); InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(true)); - assert_state_after_mint(token_id, recipient); + assert_event_transfer(ZERO(), recipient, token_id); + + assert_state_after_mint(recipient, token_id); } #[test] @@ -1176,7 +1222,9 @@ fn test__safe_mint_to_receiver_camel() { assert_state_before_mint(recipient); InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(true)); - assert_state_after_mint(token_id, recipient); + assert_event_transfer(ZERO(), recipient, token_id); + + assert_state_after_mint(recipient, token_id); } #[test] @@ -1188,7 +1236,9 @@ fn test__safe_mint_to_account() { assert_state_before_mint(account); InternalImpl::_safe_mint(ref state, account, token_id, DATA(true)); - assert_state_after_mint(token_id, account); + assert_event_transfer(ZERO(), account, token_id); + + assert_state_after_mint(account, token_id); } #[test] @@ -1200,7 +1250,9 @@ fn test__safe_mint_to_account_camel() { assert_state_before_mint(account); InternalImpl::_safe_mint(ref state, account, token_id, DATA(true)); - assert_state_after_mint(token_id, account); + assert_event_transfer(ZERO(), account, token_id); + + assert_state_after_mint(account, token_id); } #[test] @@ -1213,7 +1265,7 @@ fn test__safe_mint_to_non_receiver() { assert_state_before_mint(recipient); InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(true)); - assert_state_after_mint(token_id, recipient); + assert_state_after_mint(recipient, token_id); } #[test] @@ -1226,7 +1278,7 @@ fn test__safe_mint_to_receiver_failure() { assert_state_before_mint(recipient); InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(false)); - assert_state_after_mint(token_id, recipient); + assert_state_after_mint(recipient, token_id); } #[test] @@ -1239,7 +1291,7 @@ fn test__safe_mint_to_receiver_failure_camel() { assert_state_before_mint(recipient); InternalImpl::_safe_mint(ref state, recipient, token_id, DATA(false)); - assert_state_after_mint(token_id, recipient); + assert_state_after_mint(recipient, token_id); } #[test] @@ -1268,12 +1320,14 @@ fn test__burn() { let mut state = setup(); InternalImpl::_approve(ref state, OTHER(), TOKEN_ID); + utils::drop_event(ZERO()); assert(ERC721Impl::owner_of(@state, TOKEN_ID) == OWNER(), 'Ownership before'); assert(ERC721Impl::balance_of(@state, OWNER()) == 1, 'Balance of owner before'); assert(ERC721Impl::get_approved(@state, TOKEN_ID) == OTHER(), 'Approval before'); InternalImpl::_burn(ref state, TOKEN_ID); + assert_event_transfer(OWNER(), ZERO(), TOKEN_ID); assert(state._owners.read(TOKEN_ID) == ZERO(), 'Ownership after'); assert(ERC721Impl::balance_of(@state, OWNER()) == 0, 'Balance of owner after'); @@ -1315,7 +1369,7 @@ fn test__set_token_uri_nonexistent() { // fn assert_state_before_transfer( - token_id: u256, owner: ContractAddress, recipient: ContractAddress + owner: ContractAddress, recipient: ContractAddress, token_id: u256 ) { let state = STATE(); assert(ERC721Impl::owner_of(@state, token_id) == owner, 'Ownership before'); @@ -1323,7 +1377,7 @@ fn assert_state_before_transfer( assert(ERC721Impl::balance_of(@state, recipient) == 0, 'Balance of recipient before'); } -fn assert_state_after_transfer(token_id: u256, owner: ContractAddress, recipient: ContractAddress) { +fn assert_state_after_transfer(owner: ContractAddress, recipient: ContractAddress, token_id: u256) { let state = STATE(); assert(ERC721Impl::owner_of(@state, token_id) == recipient, 'Ownership after'); assert(ERC721Impl::balance_of(@state, owner) == 0, 'Balance of owner after'); @@ -1336,9 +1390,35 @@ fn assert_state_before_mint(recipient: ContractAddress) { assert(ERC721Impl::balance_of(@state, recipient) == 0, 'Balance of recipient before'); } -fn assert_state_after_mint(token_id: u256, recipient: ContractAddress) { +fn assert_state_after_mint(recipient: ContractAddress, token_id: u256) { let state = STATE(); assert(ERC721Impl::owner_of(@state, token_id) == recipient, 'Ownership after'); assert(ERC721Impl::balance_of(@state, recipient) == 1, 'Balance of recipient after'); assert(ERC721Impl::get_approved(@state, token_id) == ZERO(), 'Approval implicitly set'); } + +fn assert_event_approval_for_all( + owner: ContractAddress, operator: ContractAddress, approved: bool +) { + let event = utils::pop_log::(ZERO()).unwrap(); + assert(event.owner == owner, 'Invalid `owner`'); + assert(event.operator == operator, 'Invalid `operator`'); + assert(event.approved == approved, 'Invalid `approved`'); + utils::assert_no_events_left(ZERO()); +} + +fn assert_event_approval(owner: ContractAddress, approved: ContractAddress, token_id: u256) { + let event = utils::pop_log::(ZERO()).unwrap(); + assert(event.owner == owner, 'Invalid `owner`'); + assert(event.approved == approved, 'Invalid `approved`'); + assert(event.token_id == token_id, 'Invalid `token_id`'); + utils::assert_no_events_left(ZERO()); +} + +fn assert_event_transfer(from: ContractAddress, to: ContractAddress, token_id: u256) { + let event = utils::pop_log::(ZERO()).unwrap(); + assert(event.from == from, 'Invalid `from`'); + assert(event.to == to, 'Invalid `to`'); + assert(event.token_id == token_id, 'Invalid `token_id`'); + utils::assert_no_events_left(ZERO()); +} diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index 084e685e7..77d711c53 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -18,7 +18,7 @@ fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAdd } /// Pop the earliest unpopped logged event for the contract as the requested type -/// and checks there's no more data left on the event, preventing missing extra params. +/// and checks there's no more data left on the event, preventing unaccounted params. /// Indexed event members are currently not supported, so they are ignored. fn pop_log, impl TEvent: starknet::Event>( address: ContractAddress @@ -32,3 +32,7 @@ fn pop_log, impl TEvent: starknet::Event>( fn assert_no_events_left(address: ContractAddress) { assert(testing::pop_log_raw(address).is_none(), 'Events remaining on queue'); } + +fn drop_event(address: ContractAddress) { + testing::pop_log_raw(address); +} diff --git a/src/tests/utils/constants.cairo b/src/tests/utils/constants.cairo index c27c2f1ce..a66b6e721 100644 --- a/src/tests/utils/constants.cairo +++ b/src/tests/utils/constants.cairo @@ -8,6 +8,9 @@ const SUPPLY: u256 = 2000; const VALUE: u256 = 300; const ROLE: felt252 = 'ROLE'; const OTHER_ROLE: felt252 = 'OTHER_ROLE'; +const URI: felt252 = 'URI'; +const TOKEN_ID: u256 = 21; +const PUBKEY: felt252 = 'PUBKEY'; fn ADMIN() -> ContractAddress { contract_address_const::<'ADMIN'>() @@ -48,3 +51,7 @@ fn SPENDER() -> ContractAddress { fn RECIPIENT() -> ContractAddress { contract_address_const::<'RECIPIENT'>() } + +fn OPERATOR() -> ContractAddress { + contract_address_const::<'OPERATOR'>() +} From 83076441b0d7b965f9c533c774f5c3d7b39381cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Fri, 18 Aug 2023 18:18:23 -0300 Subject: [PATCH 085/124] Update README and fix scarb package (#688) * update README to cairo-2 and scarb usage. bump scarb package version * update readme fix linter issues fix linter issues fix linter issues update readme * add main to CI * update readme * update readme * rename starknet * fix linter * update readme * Update README.md Co-authored-by: Andrew Fleming * Update README.md Co-authored-by: Andrew Fleming * update CONTRIBUTING * fix linting * Update CONTRIBUTING.md Co-authored-by: Andrew Fleming * Update CONTRIBUTING.md Co-authored-by: Andrew Fleming * apply review changes * fix linter * fix typo --------- Co-authored-by: Andrew Fleming --- .github/workflows/test.yml | 2 + CONTRIBUTING.md | 91 ++---------- README.md | 292 ++++++++++--------------------------- Scarb.toml | 2 +- 4 files changed, 98 insertions(+), 289 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0a9921611..ef91ff089 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,9 +3,11 @@ name: Lint and test on: pull_request: branches: + - main - cairo-2 push: branches: + - main - cairo-2 jobs: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49e9b88d0..8adb5ee4b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,69 +6,11 @@ We really appreciate and value contributions to OpenZeppelin Contracts for Cairo Before starting development, please [create an issue](https://github.com/OpenZeppelin/cairo-contracts/issues/new/choose) to open the discussion, validate that the PR is wanted, and coordinate overall implementation details. -Also, consider that snake case is used for Cairo development in general due to its strong Python bias. -This project follows our [Extensibility pattern](https://docs.openzeppelin.com/contracts-cairo/extensibility), camelCasing all exposed function names and their parameters: - -```cairo -@external -func exposedFunc(paramOne, paramTwo){ -} -``` - -All internal and otherwise unexposed functions should resort to snake_case: - -```cairo -func internal_func(param_one, param_two){ -} -``` - -Compare our preset contracts with the libraries from which they're derived such as the [ERC20 preset](src/token/erc20/presets/ERC20.cairo) and [ERC20 library](src/token/erc20/presets/ERC20.cairo) for full examples. -See [Function names and coding style](https://docs.openzeppelin.com/contracts-cairo/0.4.0/extensibility#function_names_and_coding_style) for more information. - -And make sure to always include tests and documentation for the new developments. Please consider the following conventions: - -- Naming - - Libraries should be named `library.cairo`, e.g. `erc20/library.cairo` - - Contracts should be PascalCased i.e. `MyContract.cairo` - - Interfaces should be prefixed with an `I`, as in `IAccount.cairo` - - Test modules should begin with `test_` followed by the contract name i.e. `test_MyContract.py` - -- Structure - - Libraries should cede their names to their parent directory and are named `library.cairo` instead - - Interfaces should be alongside the library that the interface defines - - Preset contracts should be within a `presets` directory of the library to which they are a preset - - Here are example paths: - - `openzeppelin.token.erc20.library` - - `openzeppelin.token.erc20.IERC20` - - `openzeppelin.token.erc20.presets.ERC20Mintable` - - And a visual guide: - -```python - openzeppelin - └──token - └── erc20 - ├── library.cairo - ├── IERC20.cairo - └── presets - └── ERC20Mintable.cairo -``` - -- Preset contract testing - - Though, inheritance is not possible in Cairo, this repo utilizes inheritance for testing. This proves useful for testing multiple contracts that stem from the same base library. For example, the preset contracts [ERC20Mintable](src/token/erc20/presets/ERC20Mintable.cairo) and [ERC20Burnable](src/token/erc20/presets/ERC20Burnable.cairo) both share the base ERC20 functionality. To reduce code repetition, we follow these guidelines: - - `BaseSuites` - - module names are not prefixed with `test_` - - set base tests inside a class - - class name should not be prefixed with `Test`; otherwise, these tests run twice - - - test modules - - define the base fixture (`contract_factory`) and any other fixtures not used in the base suite i.e. `erc721_minted` - - define the test class and inherit the base class i.e. `class TestERC20(OwnableBase)` - - add tests specific to the preset flavor within the test class - - - fixtures - - are not defined in the base suite but are passed, unpacked, and used - - are defined in the tests where they are used - - for modularity, the basic contract factory fixture is always called `contract_factory` +### Coding style + +After a few radical changes in the Cairo language (mainly the transition to Cairo 1), our coding style guidelines became automatically deprecated. +That's why [we're working on setting new ones](https://github.com/OpenZeppelin/cairo-contracts/issues/696). +Feel free to read, contribute, discuss, and ask questions in the issue. ## Creating Pull Requests (PRs) @@ -98,32 +40,29 @@ As a contributor, you are expected to fork this repository, work on your own for 3. Make your changes, add your files, update documentation ([see Documentation section](#documentation)), commit, and push to your fork. ```sh - git add SomeFile.js + git add src/file.cairo git commit "Fix some bug short description #123" git push origin fix/some-bug-short-description-#123 ``` -4. Run tests, linter, etc. This can be done by running local continuous integration and make sure it passes. We recommend to use a [python virtual environment](https://docs.python.org/3/tutorial/venv.html). +4. Run tests and linter. This can be done by running local continuous integration and make sure it passes. ```bash - # install tox from testing dependencies - pip install .[testing] # '.[testing]' in zsh - # run tests - tox + scarb test - # stop the build if there are Markdown documentation errors - tox -e lint + # run linter + scarb fmt --check ``` -5. Go to [github.com/OpenZeppelin/cairo-contracts](https://github.com/OpenZeppelin/cairo-contracts) in your web browser and issue a new pull request. +5. Go to [OpenZeppelin/cairo-contracts](https://github.com/OpenZeppelin/cairo-contracts) in your web browser and issue a new pull request. Begin the body of the PR with "Fixes #123" or "Resolves #123" to link the PR to the issue that it is resolving. *IMPORTANT* Read the PR template very carefully and make sure to follow all the instructions. These instructions refer to some very important conditions that your PR must meet in order to be accepted, such as making sure that all PR checks pass. 6. Maintainers will review your code and possibly ask for changes before your code is pulled in to the main repository. We'll check that all tests pass, review the coding style, and check for general code correctness. If everything is OK, we'll merge your pull request and your code will be part of OpenZeppelin Contracts for Cairo. - *IMPORTANT* Please pay attention to the maintainer's feedback, since its a necessary step to keep up with the standards OpenZeppelin Contracts attains to. + *IMPORTANT* Please pay attention to the maintainer's feedback, since it's a necessary step to keep up with the standards OpenZeppelin Contracts attains to. ## Documentation @@ -145,15 +84,13 @@ If you want to run the documentation UI locally: ## Integration tests -Currently, [starknet's test suite](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/testing/starknet.py) has important differences with public networks. Like [not checking signature hints toward the end of the tx flow](https://github.com/OpenZeppelin/cairo-contracts/issues/386). - -That's why we strongly suggest testing new features against a testnet before submitting the PR, to make sure that everything works as expected in a real environment. +Currently, Starknet's test suite has important differences with public networks. We strongly suggest testing new features against a testnet before submitting the PR, to make sure that everything works as expected in a real environment. We are looking into defining a better process for these integration tests, but for now the PR author/contributor must suggest an approach to test the feature when applicable, which has to be agreed and reproduced by the reviewer. ## All set -If you have any questions, feel free to post them to github.com/OpenZeppelin/cairo-contracts/issues. +If you have any questions, feel free to post them as an [issue](https://github.com/OpenZeppelin/cairo-contracts/issues). Finally, if you're looking to collaborate and want to find easy tasks to start, look at the issues we marked as ["Good first issue"](https://github.com/OpenZeppelin/cairo-contracts/labels/good%20first%20issue). diff --git a/README.md b/README.md index c5efd3044..3ac087332 100644 --- a/README.md +++ b/README.md @@ -1,117 +1,107 @@ # OpenZeppelin Contracts for Cairo -[![Tests and linter](https://github.com/OpenZeppelin/cairo-contracts/actions/workflows/coverage.yml/badge.svg)](https://github.com/OpenZeppelin/cairo-contracts/actions/workflows/coverage.yml) -[![codecov](https://codecov.io/github/OpenZeppelin/cairo-contracts/branch/main/graph/badge.svg?token=LFSZH8RPOL)](https://codecov.io/github/OpenZeppelin/cairo-contracts) +[![Lint and test](https://github.com/OpenZeppelin/cairo-contracts/actions/workflows/test.yml/badge.svg)](https://github.com/OpenZeppelin/cairo-contracts/actions/workflows/test.yml) -**A library for secure smart contract development** written in Cairo for [StarkNet](https://starkware.co/product/starknet/), a decentralized ZK Rollup. +**A library for secure smart contract development** written in Cairo for [Starknet](https://starkware.co/product/starknet/), a decentralized ZK Rollup. -## Usage - -> ## ⚠️ WARNING! ⚠️ -> +> **Warning** > This repo contains highly experimental code. -> Expect rapid iteration. +> It has no code coverage checks. +> It hasn't been audited. > **Use at your own risk.** -### First time? +## Usage -Before installing Cairo on your machine, you need to install `gmp`: +> **Warning** +> Expect rapid iteration. +> Some contracts or features are not ready to be deployed. +> Check the **Unsupported** section below. -```bash -sudo apt install -y libgmp3-dev # linux -brew install gmp # mac -``` +### Prepare the environment -> If you have any troubles installing gmp on your Apple M1 computer, [here’s a list of potential solutions](https://github.com/OpenZeppelin/nile/issues/22). +Simply [install Cairo and scarb](https://docs.swmansion.com/scarb/download). ### Set up your project -Create a directory for your project, then `cd` into it and create a Python virtual environment. +Create a new project and `cd` into it. ```bash -mkdir my-project -cd my-project -python3 -m venv env -source env/bin/activate +scarb new my_project && cd my_project ``` -Install the [Nile](https://github.com/OpenZeppelin/nile) development environment and then run `init` to kickstart a new project. Nile will create the project directory structure and install [the Cairo language](https://www.cairo-lang.org/docs/quickstart.html), a [local network](https://github.com/Shard-Labs/starknet-devnet/), and a [testing framework](https://docs.pytest.org/en/6.2.x/). +The contents of `my_project` should look like this: ```bash -pip install cairo-nile -nile init -``` - -### Install the library +$ ls -```bash -pip install openzeppelin-cairo-contracts +Scarb.toml src ``` -> ⚠️ Warning! ⚠️ -Installing directly the `main` branch may contain incomplete or breaking implementations, download [official releases](https://github.com/OpenZeppelin/cairo-contracts/releases/) only. - -### Use a basic preset +### Install the library -Presets are ready-to-use contracts that you can deploy right away. They also serve as examples of how to use library modules. [Read more about presets](https://docs.openzeppelin.com/contracts-cairo/0.6.1/extensibility#presets). +Edit `scarb.toml` and add: -```cairo -// contracts/MyToken.cairo - -%lang starknet - -from openzeppelin.token.erc20.presets.ERC20 import ( - constructor, - name, - symbol, - totalSupply, - decimals, - balanceOf, - allowance, - transfer, - transferFrom, - approve, - increaseAllowance, - decreaseAllowance -) +```toml +[dependencies] +openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.7.0" } ``` -Compile and deploy it right away: +Build the project to download it: ```bash -nile compile +$ scarb build -nile deploy MyToken --alias my_token +Updating git repository https://github.com/OpenZeppelin/cairo-contracts +Compiling my_project v0.1.0 (~/my_project/Scarb.toml) +Finished release target(s) in 6 seconds ``` -> Note that `` is expected to be two integers i.e. `1` `0`. See [Uint256](https://docs.openzeppelin.com/contracts-cairo/0.6.1/utilities#uint256) for more information. +### Using the library -### Write a custom contract using library modules +Open `src/lib.cairo` and write your contract. -[Read more about libraries](https://docs.openzeppelin.com/contracts-cairo/0.6.1/extensibility#libraries). +For example, this how to extend the ERC20 standard contract: ```cairo -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 -from openzeppelin.security.pausable.library import Pausable -from openzeppelin.token.erc20.library import ERC20 - -(...) - -@external -func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 -) -> (success: felt) { - Pausable.assert_not_paused(); - return ERC20.transfer(recipient, amount); +#[starknet::contract] +mod MyToken { + use starknet::ContractAddress; + use openzeppelin::token::erc20::ERC20; + + #[storage] + struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + initial_supply: u256, + recipient: ContractAddress + ) { + let name = 'MyToken'; + let symbol = 'MTK'; + + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::InternalImpl::initializer(ref unsafe_state, name, symbol); + ERC20::InternalImpl::_mint(ref unsafe_state, recipient, initial_supply); + } + + #[external(v0)] + fn name(self: @ContractState) -> felt252 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::name(@unsafe_state) + } + + ... } ``` +### Unsupported + +`DualCase` dispatchers rely on Sierra's ability to catch a revert to resume execution. Currently, Starknet live chains (testnets and mainnet) don't implement that behavior. Starknet's testing framework does support it. + ## Learn -### Documentation + ### Cairo -- [StarkNet official documentation](https://www.cairo-lang.org/docs/hello_starknet/index.html#hello-starknet) -- [Cairo language documentation](https://www.cairo-lang.org/docs/hello_cairo/index.html#hello-cairo) -- Perama's [Cairo by example](https://perama-v.github.io/cairo/by-example/) -- [Cairo 101 workshops](https://www.youtube.com/playlist?list=PLcIyXLwiPilV5RBZj43AX1FY4FJMWHFTY) +- [Cairo book](https://book.cairo-lang.org/) +- [Cairo language documentation](https://docs.cairo-lang.org/) +- [Starknet book](https://book.starknet.io/) +- [Starknet documentation](https://docs.starknet.io/documentation/) +- [Cairo 1.0 mini-docs](https://github.com/Starknet-Africa-Edu/Cairo1.0) +- [Cairopractice](https://cairopractice.com/) -### Nile +### Tooling -- [Getting started with StarkNet using Nile](https://medium.com/coinmonks/starknet-tutorial-for-beginners-using-nile-6af9c2270c15) -- [How to manage smart contract deployments with Nile](https://medium.com/@martriay/manage-your-starknet-deployments-with-nile-%EF%B8%8F-e849d40546dd) +- [Scarb](https://docs.swmansion.com/scarb) ## Development ### Set up the project -Clone the repository +Clone the repository: ```bash git clone git@github.com:OpenZeppelin/cairo-contracts.git ``` -`cd` into it and create a Python virtual environment: - -```bash -cd cairo-contracts -python3 -m venv env -source env/bin/activate -``` - -Install dependencies: +`cd` into it and build: ```bash -python -m pip install . -``` - -### Compile the contracts +$ cd cairo-contracts +$ scarb build -```bash -nile compile --directory src - -🤖 Compiling all Cairo contracts in the src directory -🔨 Compiling src/openzeppelin/token/erc20/library.cairo -🔨 Compiling src/openzeppelin/token/erc20/presets/ERC20Mintable.cairo -🔨 Compiling src/openzeppelin/token/erc20/presets/ERC20Pausable.cairo -🔨 Compiling src/openzeppelin/token/erc20/presets/ERC20Upgradeable.cairo -🔨 Compiling src/openzeppelin/token/erc20/presets/ERC20.cairo -🔨 Compiling src/openzeppelin/token/erc20/IERC20.cairo -🔨 Compiling src/openzeppelin/token/erc721/enumerable/library.cairo -🔨 Compiling src/openzeppelin/token/erc721/library.cairo -🔨 Compiling src/openzeppelin/token/erc721/utils/ERC721Holder.cairo -🔨 Compiling src/openzeppelin/token/erc721/presets/ERC721MintablePausable.cairo -🔨 Compiling src/openzeppelin/token/erc721/presets/ERC721MintableBurnable.cairo -🔨 Compiling src/openzeppelin/token/erc721/presets/ERC721EnumerableMintableBurnable.cairo -🔨 Compiling src/openzeppelin/token/erc721/IERC721.cairo -🔨 Compiling src/openzeppelin/token/erc721/IERC721Metadata.cairo -🔨 Compiling src/openzeppelin/token/erc721/IERC721Receiver.cairo -🔨 Compiling src/openzeppelin/token/erc721/enumerable/IERC721Enumerable.cairo -🔨 Compiling src/openzeppelin/access/ownable/library.cairo -🔨 Compiling src/openzeppelin/security/reentrancyguard/library.cairo -🔨 Compiling src/openzeppelin/security/safemath/library.cairo -🔨 Compiling src/openzeppelin/security/pausable/library.cairo -🔨 Compiling src/openzeppelin/security/initializable/library.cairo -🔨 Compiling src/openzeppelin/utils/constants/library.cairo -🔨 Compiling src/openzeppelin/introspection/erc165/library.cairo -🔨 Compiling src/openzeppelin/introspection/erc165/IERC165.cairo -🔨 Compiling src/openzeppelin/upgrades/library.cairo -🔨 Compiling src/openzeppelin/upgrades/presets/Proxy.cairo -🔨 Compiling src/openzeppelin/account/library.cairo -🔨 Compiling src/openzeppelin/account/presets/EthAccount.cairo -🔨 Compiling src/openzeppelin/account/presets/Account.cairo -🔨 Compiling src/openzeppelin/account/presets/AddressRegistry.cairo -🔨 Compiling src/openzeppelin/account/IAccount.cairo -✅ Done +Compiling lib(openzeppelin) openzeppelin v0.7.0 (~/cairo-contracts/Scarb.toml) +Compiling starknet-contract(openzeppelin) openzeppelin v0.7.0 (~/cairo-contracts/Scarb.toml) +Finished release target(s) in 16 seconds ``` ### Run tests -Run tests using [tox](https://tox.wiki/en/latest/), tox automatically creates an isolated testing environment: - -```bash -tox - -====================== test session starts ====================== -platform linux -- Python 3.7.2, pytest-7.1.2, py-1.11.0, pluggy-1.0.0 -rootdir: /home/readme/cairo-contracts, configfile: tox.ini -plugins: asyncio-0.18.3, xdist-2.5.0, forked-1.4.0, web3-5.29.0, typeguard-2.13.3 -asyncio: mode=auto -gw0 [185] / gw1 [185] -...................................................................................... -...................................................................................... -............ [100%] -``` - -### Run Tests in Docker - -For M1 users or those who are having trouble with library/python versions you can alternatively run the tests within a docker container. Using the following as a Dockerfile placed in the root directory of the project: - -```dockerfile -FROM python:3.7 - -RUN pip install tox -RUN mkdir cairo-contracts -COPY . cairo-contracts -WORKDIR cairo-contracts -ENTRYPOINT tox -``` - -After its placed there run: - ```bash -docker build -t cairo-tests . -docker run cairo-tests -``` - -### Parallel Testing - -This repo utilizes the [pytest-xdist](https://pytest-xdist.readthedocs.io/en/latest/) plugin which runs tests in parallel. This feature increases testing speed; however, conflicts with a shared state can occur since tests do not run in order. To overcome this, independent cached versions of contracts being tested should be provisioned to each test case. Here's a simple fixture example: - -```python -from utils import get_contract_class, cached_contract - -@pytest.fixture -def foo_factory(): - # get contract class - foo_cls = get_contract_class('Foo') - - # deploy contract - starknet = await Starknet.empty() - foo = await starknet.deploy(contract_class=foo_cls) - - # copy the state and cache contract - state = starknet.state.copy() - cached_foo = cached_contract(state, foo_cls, foo) - - return cached_foo +scarb test ``` -See [Memoization](https://docs.openzeppelin.com/contracts-cairo/0.6.1/utilities#memoization) in the Utilities documentation for a more thorough example on caching contracts. - -> Note that this does not apply for stateless libraries such as SafeMath. - ## Security > ⚠️ Warning! ⚠️ @@ -277,24 +165,6 @@ Refer to [SECURITY.md](SECURITY.md) for more details. OpenZeppelin Contracts for Cairo exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the [contribution](CONTRIBUTING.md) guide! -### Markdown linter - -To keep the markdown files neat and easy to edit, we utilize DavidAnson's [markdownlint](https://github.com/DavidAnson/markdownlint) linter. You can find the listed rules [here](https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md). Note that the following rules are disabled: - -- `MD013: line length` - - - to enable paragraphs without internal line breaks - -- `MD033: inline HTML` - - - to enable .md files to have duplicate headers and separate them by identifiers - -Before creating a PR, check that documentation changes are compliant with our markdown rules by running: - -```bash -tox -e lint -``` - ## License OpenZeppelin Contracts for Cairo is released under the [MIT License](LICENSE). diff --git a/Scarb.toml b/Scarb.toml index e36e29c60..bf42b24ee 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,6 +1,6 @@ [package] name = "openzeppelin" -version = "0.1.0" +version = "0.7.0" cairo-version = "2.1.0-rc1" authors = ["OpenZeppelin Community "] description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" From cece32ba90a6d4e1e01a9a09040c3bad3275d27b Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 22 Aug 2023 23:49:22 -0400 Subject: [PATCH 086/124] Bump scarb and fix dual721 test context (#703) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bump scarb and cairo version * fix testing context --------- Co-authored-by: Martín Triay --- .github/workflows/test.yml | 2 +- Scarb.toml | 4 ++-- src/tests/token/test_dual721.cairo | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ef91ff089..8357486b9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v3 - uses: software-mansion/setup-scarb@v1 with: - scarb-version: "0.6.0-alpha.1" + scarb-version: "0.6.2" - name: Markdown lint uses: DavidAnson/markdownlint-cli2-action@5b7c9f74fec47e6b15667b2cc23c63dff11e449e # v9 with: diff --git a/Scarb.toml b/Scarb.toml index bf42b24ee..d07fbd1b3 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,7 +1,7 @@ [package] name = "openzeppelin" version = "0.7.0" -cairo-version = "2.1.0-rc1" +cairo-version = "2.1.1" authors = ["OpenZeppelin Community "] description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" documentation = "https://docs.openzeppelin.com/contracts-cairo" @@ -11,7 +11,7 @@ license-file = "LICENSE" keywords = ["openzeppelin", "starknet", "cairo", "contracts", "security", "standards"] [dependencies] -starknet = ">=2.1.0-rc0" +starknet = ">=2.1.1" [lib] diff --git a/src/tests/token/test_dual721.cairo b/src/tests/token/test_dual721.cairo index 55349de11..b5f02f7e9 100644 --- a/src/tests/token/test_dual721.cairo +++ b/src/tests/token/test_dual721.cairo @@ -62,7 +62,7 @@ fn setup_snake() -> (DualCaseERC721, IERC721Dispatcher) { calldata.append_serde(SYMBOL); calldata.append_serde(TOKEN_ID); calldata.append_serde(URI); - set_caller_address(OWNER()); + set_contract_address(OWNER()); let target = utils::deploy(SnakeERC721Mock::TEST_CLASS_HASH, calldata); (DualCaseERC721 { contract_address: target }, IERC721Dispatcher { contract_address: target }) } @@ -73,7 +73,7 @@ fn setup_camel() -> (DualCaseERC721, IERC721CamelOnlyDispatcher) { calldata.append_serde(SYMBOL); calldata.append_serde(TOKEN_ID); calldata.append_serde(URI); - set_caller_address(OWNER()); + set_contract_address(OWNER()); let target = utils::deploy(CamelERC721Mock::TEST_CLASS_HASH, calldata); ( DualCaseERC721 { From 32f99742c86cffb29319167133cd416e496759cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Wed, 23 Aug 2023 00:51:29 -0300 Subject: [PATCH 087/124] add rc version (#708) --- Scarb.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarb.toml b/Scarb.toml index d07fbd1b3..73083f109 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,6 +1,6 @@ [package] name = "openzeppelin" -version = "0.7.0" +version = "0.7.0-rc.0" cairo-version = "2.1.1" authors = ["OpenZeppelin Community "] description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" From b40c35b5ca82598ae5bd9610aa3ffd0ded1f3c5f Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 22 Aug 2023 23:52:11 -0400 Subject: [PATCH 088/124] remove unused imports (#707) --- src/tests/mocks/camel_accesscontrol_mock.cairo | 1 - src/tests/mocks/snake_accesscontrol_mock.cairo | 1 - 2 files changed, 2 deletions(-) diff --git a/src/tests/mocks/camel_accesscontrol_mock.cairo b/src/tests/mocks/camel_accesscontrol_mock.cairo index 55835f50c..09e2fbf92 100644 --- a/src/tests/mocks/camel_accesscontrol_mock.cairo +++ b/src/tests/mocks/camel_accesscontrol_mock.cairo @@ -4,7 +4,6 @@ mod CamelAccessControlMock { use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use starknet::ContractAddress; - use starknet::get_caller_address; #[storage] struct Storage {} diff --git a/src/tests/mocks/snake_accesscontrol_mock.cairo b/src/tests/mocks/snake_accesscontrol_mock.cairo index 48b291979..614b00627 100644 --- a/src/tests/mocks/snake_accesscontrol_mock.cairo +++ b/src/tests/mocks/snake_accesscontrol_mock.cairo @@ -4,7 +4,6 @@ mod SnakeAccessControlMock { use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use starknet::ContractAddress; - use starknet::get_caller_address; #[storage] struct Storage {} From fbdd7593681a1515dabcbf722fb99c88edf200fe Mon Sep 17 00:00:00 2001 From: "Bal7hazar @ Carbonable" Date: Thu, 24 Aug 2023 23:04:41 +0200 Subject: [PATCH 089/124] Upgrade Cairo version and Scarb version to latest releases (#712) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 👽️ Update code due to breaking changes * ⬆️ Upgrade scarb and cairo versions * 💄 Code format --- .github/workflows/test.yml | 2 +- Scarb.toml | 4 +- src/account/account.cairo | 2 +- src/tests/access/test_accesscontrol.cairo | 20 ++--- .../access/test_dual_accesscontrol.cairo | 57 +++++------- src/tests/access/test_dual_ownable.cairo | 30 +++---- src/tests/access/test_ownable.cairo | 26 +++--- src/tests/account/test_account.cairo | 8 +- src/tests/account/test_dual_account.cairo | 45 ++++------ src/tests/introspection/test_dual_src5.cairo | 13 ++- src/tests/introspection/test_src5.cairo | 2 +- src/tests/mocks/reentrancy_mock.cairo | 5 +- src/tests/security/test_initializable.cairo | 2 +- src/tests/security/test_pausable.cairo | 8 +- src/tests/security/test_reentrancyguard.cairo | 4 +- src/tests/token/test_dual20.cairo | 38 ++++---- src/tests/token/test_dual721.cairo | 80 ++++++++--------- src/tests/token/test_dual721_receiver.cairo | 27 ++---- src/tests/token/test_erc20.cairo | 46 +++++----- src/tests/token/test_erc721.cairo | 90 +++++++++---------- src/tests/upgrades/test_upgradeable.cairo | 4 +- src/token/erc721/erc721.cairo | 9 +- src/upgrades/upgradeable.cairo | 2 +- 23 files changed, 239 insertions(+), 285 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8357486b9..1dccc55bf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v3 - uses: software-mansion/setup-scarb@v1 with: - scarb-version: "0.6.2" + scarb-version: "0.7.0" - name: Markdown lint uses: DavidAnson/markdownlint-cli2-action@5b7c9f74fec47e6b15667b2cc23c63dff11e449e # v9 with: diff --git a/Scarb.toml b/Scarb.toml index 73083f109..13ffeb95c 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,7 +1,7 @@ [package] name = "openzeppelin" version = "0.7.0-rc.0" -cairo-version = "2.1.1" +cairo-version = "2.2.0" authors = ["OpenZeppelin Community "] description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" documentation = "https://docs.openzeppelin.com/contracts-cairo" @@ -11,7 +11,7 @@ license-file = "LICENSE" keywords = ["openzeppelin", "starknet", "cairo", "contracts", "security", "standards"] [dependencies] -starknet = ">=2.1.1" +starknet = ">=2.2.0" [lib] diff --git a/src/account/account.cairo b/src/account/account.cairo index 8fffb55ea..3bda0e34a 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -241,6 +241,6 @@ mod Account { #[internal] fn _execute_single_call(call: Call) -> Span { let Call{to, selector, calldata } = call; - starknet::call_contract_syscall(to, selector, calldata.span()).unwrap_syscall() + starknet::call_contract_syscall(to, selector, calldata.span()).unwrap() } } diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index 8dd4af473..c8aeab26b 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -111,7 +111,7 @@ fn test_assert_only_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] +#[should_panic(expected: ('Caller is missing role',))] fn test_assert_only_role_unauthorized() { let state = setup(); testing::set_caller_address(OTHER()); @@ -120,7 +120,7 @@ fn test_assert_only_role_unauthorized() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] +#[should_panic(expected: ('Caller is missing role',))] fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { let mut state = setup(); AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); @@ -181,7 +181,7 @@ fn test_grantRole_multiple_times_for_granted_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] +#[should_panic(expected: ('Caller is missing role',))] fn test_grant_role_unauthorized() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); @@ -190,7 +190,7 @@ fn test_grant_role_unauthorized() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] +#[should_panic(expected: ('Caller is missing role',))] fn test_grantRole_unauthorized() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); @@ -277,7 +277,7 @@ fn test_revokeRole_multiple_times_for_granted_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] +#[should_panic(expected: ('Caller is missing role',))] fn test_revoke_role_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -286,7 +286,7 @@ fn test_revoke_role_unauthorized() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] +#[should_panic(expected: ('Caller is missing role',))] fn test_revokeRole_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -380,7 +380,7 @@ fn test_renounceRole_multiple_times_for_granted_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Can only renounce role for self', ))] +#[should_panic(expected: ('Can only renounce role for self',))] fn test_renounce_role_unauthorized() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -392,7 +392,7 @@ fn test_renounce_role_unauthorized() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Can only renounce role for self', ))] +#[should_panic(expected: ('Can only renounce role for self',))] fn test_renounceRole_unauthorized() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -456,7 +456,7 @@ fn test_new_admin_can_revoke_roles() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] +#[should_panic(expected: ('Caller is missing role',))] fn test_previous_admin_cannot_grant_roles() { let mut state = setup(); InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); @@ -466,7 +466,7 @@ fn test_previous_admin_cannot_grant_roles() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is missing role', ))] +#[should_panic(expected: ('Caller is missing role',))] fn test_previous_admin_cannot_revoke_roles() { let mut state = setup(); InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index 094f44a21..0a2f3527d 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -28,11 +28,8 @@ fn setup_snake() -> (DualCaseAccessControl, IAccessControlDispatcher) { calldata.append_serde(ADMIN()); let target = utils::deploy(SnakeAccessControlMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccessControl { - contract_address: target - }, IAccessControlDispatcher { - contract_address: target - } + DualCaseAccessControl { contract_address: target }, + IAccessControlDispatcher { contract_address: target } ) } @@ -41,11 +38,8 @@ fn setup_camel() -> (DualCaseAccessControl, IAccessControlCamelDispatcher) { calldata.append_serde(ADMIN()); let target = utils::deploy(CamelAccessControlMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccessControl { - contract_address: target - }, IAccessControlCamelDispatcher { - contract_address: target - } + DualCaseAccessControl { contract_address: target }, + IAccessControlCamelDispatcher { contract_address: target } ) } @@ -58,11 +52,8 @@ fn setup_accesscontrol_panic() -> (DualCaseAccessControl, DualCaseAccessControl) let snake_target = utils::deploy(SnakeAccessControlPanicMock::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelAccessControlPanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseAccessControl { - contract_address: snake_target - }, DualCaseAccessControl { - contract_address: camel_target - } + DualCaseAccessControl { contract_address: snake_target }, + DualCaseAccessControl { contract_address: camel_target } ) } @@ -79,7 +70,7 @@ fn test_dual_supports_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_supports_interface() { let dispatcher = setup_non_accesscontrol(); dispatcher.supports_interface(IACCESSCONTROL_ID); @@ -87,7 +78,7 @@ fn test_dual_no_supports_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_supports_interface_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.supports_interface(IACCESSCONTROL_ID); @@ -102,7 +93,7 @@ fn test_dual_has_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_has_role() { let dispatcher = setup_non_accesscontrol(); dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); @@ -110,7 +101,7 @@ fn test_dual_no_has_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_has_role_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); @@ -125,7 +116,7 @@ fn test_dual_get_role_admin() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_get_role_admin() { let dispatcher = setup_non_accesscontrol(); dispatcher.get_role_admin(ROLE); @@ -133,7 +124,7 @@ fn test_dual_no_get_role_admin() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_get_role_admin_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.get_role_admin(ROLE); @@ -150,7 +141,7 @@ fn test_dual_grant_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_grant_role() { let dispatcher = setup_non_accesscontrol(); dispatcher.grant_role(ROLE, AUTHORIZED()); @@ -158,7 +149,7 @@ fn test_dual_no_grant_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_grant_role_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.grant_role(ROLE, AUTHORIZED()); @@ -175,7 +166,7 @@ fn test_dual_revoke_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_revoke_role() { let dispatcher = setup_non_accesscontrol(); dispatcher.revoke_role(ROLE, AUTHORIZED()); @@ -183,7 +174,7 @@ fn test_dual_no_revoke_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_revoke_role_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.revoke_role(ROLE, AUTHORIZED()); @@ -200,7 +191,7 @@ fn test_dual_renounce_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_renounce_role() { let dispatcher = setup_non_accesscontrol(); dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); @@ -208,7 +199,7 @@ fn test_dual_no_renounce_role() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_renounce_role_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); @@ -227,7 +218,7 @@ fn test_dual_supportsInterface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.supports_interface(IACCESSCONTROL_ID); @@ -242,7 +233,7 @@ fn test_dual_hasRole() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_hasRole_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); @@ -257,7 +248,7 @@ fn test_dual_getRoleAdmin() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_getRoleAdmin_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.get_role_admin(ROLE); @@ -274,7 +265,7 @@ fn test_dual_grantRole() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_grantRole_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.grant_role(ROLE, AUTHORIZED()); @@ -292,7 +283,7 @@ fn test_dual_revokeRole() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_revokeRole_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.revoke_role(ROLE, AUTHORIZED()); @@ -309,7 +300,7 @@ fn test_dual_renounceRole() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_renounceRole_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); diff --git a/src/tests/access/test_dual_ownable.cairo b/src/tests/access/test_dual_ownable.cairo index 380672757..8055bd1fc 100644 --- a/src/tests/access/test_dual_ownable.cairo +++ b/src/tests/access/test_dual_ownable.cairo @@ -45,11 +45,8 @@ fn setup_camel() -> (DualCaseOwnable, IOwnableCamelOnlyDispatcher) { calldata.append_serde(OWNER()); let target = utils::deploy(CamelOwnableMock::TEST_CLASS_HASH, calldata); ( - DualCaseOwnable { - contract_address: target - }, IOwnableCamelOnlyDispatcher { - contract_address: target - } + DualCaseOwnable { contract_address: target }, + IOwnableCamelOnlyDispatcher { contract_address: target } ) } @@ -63,11 +60,8 @@ fn setup_ownable_panic() -> (DualCaseOwnable, DualCaseOwnable) { let snake_target = utils::deploy(SnakeOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); let camel_target = utils::deploy(CamelOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); ( - DualCaseOwnable { - contract_address: snake_target - }, DualCaseOwnable { - contract_address: camel_target - } + DualCaseOwnable { contract_address: snake_target }, + DualCaseOwnable { contract_address: camel_target } ) } @@ -86,7 +80,7 @@ fn test_dual_owner() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_owner() { let dispatcher = setup_non_ownable(); dispatcher.owner(); @@ -94,7 +88,7 @@ fn test_dual_no_owner() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_owner_exists_and_panics() { let (dispatcher, _) = setup_ownable_panic(); dispatcher.owner(); @@ -115,7 +109,7 @@ fn test_dual_transfer_ownership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_transfer_ownership() { let dispatcher = setup_non_ownable(); dispatcher.transfer_ownership(NEW_OWNER()); @@ -123,7 +117,7 @@ fn test_dual_no_transfer_ownership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_transfer_ownership_exists_and_panics() { let (dispatcher, _) = setup_ownable_panic(); dispatcher.transfer_ownership(NEW_OWNER()); @@ -141,7 +135,7 @@ fn test_dual_renounce_ownership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_renounce_ownership() { let dispatcher = setup_non_ownable(); dispatcher.renounce_ownership(); @@ -149,7 +143,7 @@ fn test_dual_no_renounce_ownership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_renounce_ownership_exists_and_panics() { let (dispatcher, _) = setup_ownable_panic(); dispatcher.renounce_ownership(); @@ -170,7 +164,7 @@ fn test_dual_transferOwnership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_transferOwnership_exists_and_panics() { let (_, dispatcher) = setup_ownable_panic(); dispatcher.transfer_ownership(NEW_OWNER()); @@ -187,7 +181,7 @@ fn test_dual_renounceOwnership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_renounceOwnership_exists_and_panics() { let (_, dispatcher) = setup_ownable_panic(); dispatcher.renounce_ownership(); diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index 214329b9b..04b9033a2 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -2,7 +2,7 @@ use openzeppelin::access::ownable::Ownable::InternalImpl; use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; use openzeppelin::access::ownable::Ownable::OwnableImpl; use openzeppelin::access::ownable::Ownable::OwnershipTransferred; -use openzeppelin::access::ownable::Ownable::_owner::InternalContractStateTrait; +use openzeppelin::access::ownable::Ownable::_owner::InternalContractMemberStateTrait; use openzeppelin::access::ownable::Ownable; use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; use openzeppelin::tests::utils; @@ -57,7 +57,7 @@ fn test_assert_only_owner() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is not the owner', ))] +#[should_panic(expected: ('Caller is not the owner',))] fn test_assert_only_owner_when_not_owner() { let state = setup(); testing::set_caller_address(OTHER()); @@ -66,7 +66,7 @@ fn test_assert_only_owner_when_not_owner() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is the zero address', ))] +#[should_panic(expected: ('Caller is the zero address',))] fn test_assert_only_owner_when_caller_zero() { let state = setup(); InternalImpl::assert_only_owner(@state); @@ -105,7 +105,7 @@ fn test_transfer_ownership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('New owner is the zero address', ))] +#[should_panic(expected: ('New owner is the zero address',))] fn test_transfer_ownership_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -114,7 +114,7 @@ fn test_transfer_ownership_to_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is the zero address', ))] +#[should_panic(expected: ('Caller is the zero address',))] fn test_transfer_ownership_from_zero() { let mut state = setup(); OwnableImpl::transfer_ownership(ref state, OTHER()); @@ -122,7 +122,7 @@ fn test_transfer_ownership_from_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is not the owner', ))] +#[should_panic(expected: ('Caller is not the owner',))] fn test_transfer_ownership_from_nonowner() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -143,7 +143,7 @@ fn test_transferOwnership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('New owner is the zero address', ))] +#[should_panic(expected: ('New owner is the zero address',))] fn test_transferOwnership_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -152,7 +152,7 @@ fn test_transferOwnership_to_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is the zero address', ))] +#[should_panic(expected: ('Caller is the zero address',))] fn test_transferOwnership_from_zero() { let mut state = setup(); OwnableCamelOnlyImpl::transferOwnership(ref state, OTHER()); @@ -160,7 +160,7 @@ fn test_transferOwnership_from_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is not the owner', ))] +#[should_panic(expected: ('Caller is not the owner',))] fn test_transferOwnership_from_nonowner() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -185,7 +185,7 @@ fn test_renounce_ownership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is the zero address', ))] +#[should_panic(expected: ('Caller is the zero address',))] fn test_renounce_ownership_from_zero_address() { let mut state = setup(); OwnableImpl::renounce_ownership(ref state); @@ -193,7 +193,7 @@ fn test_renounce_ownership_from_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is not the owner', ))] +#[should_panic(expected: ('Caller is not the owner',))] fn test_renounce_ownership_from_nonowner() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -214,7 +214,7 @@ fn test_renounceOwnership() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is the zero address', ))] +#[should_panic(expected: ('Caller is the zero address',))] fn test_renounceOwnership_from_zero_address() { let mut state = setup(); OwnableCamelOnlyImpl::renounceOwnership(ref state); @@ -222,7 +222,7 @@ fn test_renounceOwnership_from_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Caller is not the owner', ))] +#[should_panic(expected: ('Caller is not the owner',))] fn test_renounceOwnership_from_nonowner() { let mut state = setup(); testing::set_caller_address(OTHER()); diff --git a/src/tests/account/test_account.cairo b/src/tests/account/test_account.cairo index d66e9fbfe..83bea533b 100644 --- a/src/tests/account/test_account.cairo +++ b/src/tests/account/test_account.cairo @@ -423,7 +423,7 @@ fn test_multicall_zero_calls() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Account: invalid caller', ))] +#[should_panic(expected: ('Account: invalid caller',))] fn test_account_called_from_contract() { let calls = array![]; let caller = contract_address_const::<0x123>(); @@ -465,7 +465,7 @@ fn test_public_key_setter_and_getter() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Account: unauthorized', ))] +#[should_panic(expected: ('Account: unauthorized',))] fn test_public_key_setter_different_account() { let mut state = STATE(); let caller = contract_address_const::<0x123>(); @@ -506,7 +506,7 @@ fn test_public_key_setter_and_getter_camel() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Account: unauthorized', ))] +#[should_panic(expected: ('Account: unauthorized',))] fn test_public_key_setter_different_account_camel() { let mut state = STATE(); let caller = contract_address_const::<0x123>(); @@ -543,7 +543,7 @@ fn test_assert_only_self_true() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Account: unauthorized', ))] +#[should_panic(expected: ('Account: unauthorized',))] fn test_assert_only_self_false() { testing::set_contract_address(ACCOUNT_ADDRESS()); let other = contract_address_const::<0x4567>(); diff --git a/src/tests/account/test_dual_account.cairo b/src/tests/account/test_dual_account.cairo index f38c308c5..2c2156ed6 100644 --- a/src/tests/account/test_dual_account.cairo +++ b/src/tests/account/test_dual_account.cairo @@ -29,11 +29,8 @@ fn setup_snake() -> (DualCaseAccount, AccountABIDispatcher) { let mut calldata = array![PUBLIC_KEY]; let target = utils::deploy(SnakeAccountMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccount { - contract_address: target - }, AccountABIDispatcher { - contract_address: target - } + DualCaseAccount { contract_address: target }, + AccountABIDispatcher { contract_address: target } ) } @@ -41,11 +38,8 @@ fn setup_camel() -> (DualCaseAccount, AccountCamelABIDispatcher) { let mut calldata = array![PUBLIC_KEY]; let target = utils::deploy(CamelAccountMock::TEST_CLASS_HASH, calldata); ( - DualCaseAccount { - contract_address: target - }, AccountCamelABIDispatcher { - contract_address: target - } + DualCaseAccount { contract_address: target }, + AccountCamelABIDispatcher { contract_address: target } ) } @@ -59,11 +53,8 @@ fn setup_account_panic() -> (DualCaseAccount, DualCaseAccount) { let snake_target = utils::deploy(SnakeAccountPanicMock::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelAccountPanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseAccount { - contract_address: snake_target - }, DualCaseAccount { - contract_address: camel_target - } + DualCaseAccount { contract_address: snake_target }, + DualCaseAccount { contract_address: camel_target } ) } @@ -84,7 +75,7 @@ fn test_dual_set_public_key() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_set_public_key() { let dispatcher = setup_non_account(); dispatcher.set_public_key(NEW_PUBLIC_KEY); @@ -92,7 +83,7 @@ fn test_dual_no_set_public_key() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_set_public_key_exists_and_panics() { let (dispatcher, _) = setup_account_panic(); dispatcher.set_public_key(NEW_PUBLIC_KEY); @@ -107,7 +98,7 @@ fn test_dual_get_public_key() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_get_public_key() { let dispatcher = setup_non_account(); dispatcher.get_public_key(); @@ -115,7 +106,7 @@ fn test_dual_no_get_public_key() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_get_public_key_exists_and_panics() { let (dispatcher, _) = setup_account_panic(); dispatcher.get_public_key(); @@ -139,7 +130,7 @@ fn test_dual_is_valid_signature() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_is_valid_signature() { let hash = 0x0; let signature = array![]; @@ -150,7 +141,7 @@ fn test_dual_no_is_valid_signature() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_is_valid_signature_exists_and_panics() { let hash = 0x0; let signature = array![]; @@ -168,7 +159,7 @@ fn test_dual_supports_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_supports_interface() { let dispatcher = setup_non_account(); dispatcher.supports_interface(ISRC5_ID); @@ -176,7 +167,7 @@ fn test_dual_no_supports_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_supports_interface_exists_and_panics() { let (dispatcher, _) = setup_account_panic(); dispatcher.supports_interface(ISRC5_ID); @@ -199,7 +190,7 @@ fn test_dual_setPublicKey() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_setPublicKey_exists_and_panics() { let (_, dispatcher) = setup_account_panic(); dispatcher.set_public_key(NEW_PUBLIC_KEY); @@ -214,7 +205,7 @@ fn test_dual_getPublicKey() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_getPublicKey_exists_and_panics() { let (_, dispatcher) = setup_account_panic(); dispatcher.get_public_key(); @@ -238,7 +229,7 @@ fn test_dual_isValidSignature() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_isValidSignature_exists_and_panics() { let hash = 0x0; let signature = array![]; @@ -256,7 +247,7 @@ fn test_dual_supportsInterface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_account_panic(); dispatcher.supports_interface(ISRC5_ID); diff --git a/src/tests/introspection/test_dual_src5.cairo b/src/tests/introspection/test_dual_src5.cairo index 84157605b..f2122f2e1 100644 --- a/src/tests/introspection/test_dual_src5.cairo +++ b/src/tests/introspection/test_dual_src5.cairo @@ -39,11 +39,8 @@ fn setup_src5_panic() -> (DualCaseSRC5, DualCaseSRC5) { let snake_target = utils::deploy(SnakeSRC5PanicMock::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelSRC5PanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseSRC5 { - contract_address: snake_target - }, DualCaseSRC5 { - contract_address: camel_target - } + DualCaseSRC5 { contract_address: snake_target }, + DualCaseSRC5 { contract_address: camel_target } ) } @@ -60,7 +57,7 @@ fn test_dual_supports_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_supports_interface() { let dispatcher = setup_non_src5(); dispatcher.supports_interface(ISRC5_ID); @@ -68,7 +65,7 @@ fn test_dual_no_supports_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_supports_interface_exists_and_panics() { let (dispatcher, _) = setup_src5_panic(); dispatcher.supports_interface(ISRC5_ID); @@ -87,7 +84,7 @@ fn test_dual_supportsInterface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_src5_panic(); dispatcher.supports_interface(ISRC5_ID); diff --git a/src/tests/introspection/test_src5.cairo b/src/tests/introspection/test_src5.cairo index d81cf3e37..a8ca2b699 100644 --- a/src/tests/introspection/test_src5.cairo +++ b/src/tests/introspection/test_src5.cairo @@ -44,7 +44,7 @@ fn test_deregister_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('SRC5: invalid id', ))] +#[should_panic(expected: ('SRC5: invalid id',))] fn test_deregister_default_interface() { let mut state = STATE(); InternalImpl::deregister_interface(ref state, ISRC5_ID); diff --git a/src/tests/mocks/reentrancy_mock.cairo b/src/tests/mocks/reentrancy_mock.cairo index 1204afa47..dc81bb9ea 100644 --- a/src/tests/mocks/reentrancy_mock.cairo +++ b/src/tests/mocks/reentrancy_mock.cairo @@ -72,9 +72,8 @@ mod ReentrancyMock { if n != 0 { self.count(); let this: ContractAddress = get_contract_address(); - IReentrancyGuardedDispatcher { - contract_address: this - }.count_external_recursive(n - 1) + IReentrancyGuardedDispatcher { contract_address: this } + .count_external_recursive(n - 1) } ReentrancyGuard::InternalImpl::end(ref unsafe_state); diff --git a/src/tests/security/test_initializable.cairo b/src/tests/security/test_initializable.cairo index 66d2b89dc..cd34ea375 100644 --- a/src/tests/security/test_initializable.cairo +++ b/src/tests/security/test_initializable.cairo @@ -16,7 +16,7 @@ fn test_initialize() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Initializable: is initialized', ))] +#[should_panic(expected: ('Initializable: is initialized',))] fn test_initialize_when_initialized() { let mut state = STATE(); InternalImpl::initialize(ref state); diff --git a/src/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo index f48a2904b..26497e121 100644 --- a/src/tests/security/test_pausable.cairo +++ b/src/tests/security/test_pausable.cairo @@ -49,7 +49,7 @@ fn test_assert_paused_when_paused() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Pausable: not paused', ))] +#[should_panic(expected: ('Pausable: not paused',))] fn test_assert_paused_when_not_paused() { let state = STATE(); InternalImpl::assert_paused(@state); @@ -61,7 +61,7 @@ fn test_assert_paused_when_not_paused() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Pausable: paused', ))] +#[should_panic(expected: ('Pausable: paused',))] fn test_assert_not_paused_when_paused() { let mut state = STATE(); InternalImpl::_pause(ref state); @@ -93,7 +93,7 @@ fn test_pause_when_unpaused() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Pausable: paused', ))] +#[should_panic(expected: ('Pausable: paused',))] fn test_pause_when_paused() { let mut state = STATE(); InternalImpl::_pause(ref state); @@ -121,7 +121,7 @@ fn test_unpause_when_paused() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Pausable: not paused', ))] +#[should_panic(expected: ('Pausable: not paused',))] fn test_unpause_when_unpaused() { let mut state = STATE(); assert(!PausableImpl::is_paused(@state), 'Should be paused'); diff --git a/src/tests/security/test_reentrancyguard.cairo b/src/tests/security/test_reentrancyguard.cairo index b608706db..b5aa84056 100644 --- a/src/tests/security/test_reentrancyguard.cairo +++ b/src/tests/security/test_reentrancyguard.cairo @@ -1,5 +1,5 @@ use openzeppelin::security::reentrancyguard::ReentrancyGuard::InternalImpl; -use openzeppelin::security::reentrancyguard::ReentrancyGuard::entered::InternalContractStateTrait; +use openzeppelin::security::reentrancyguard::ReentrancyGuard::entered::InternalContractMemberStateTrait; use openzeppelin::security::reentrancyguard::ReentrancyGuard; use openzeppelin::tests::mocks::reentrancy_attacker_mock::Attacker; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; @@ -33,7 +33,7 @@ fn test_reentrancy_guard_start() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ReentrancyGuard: reentrant call', ))] +#[should_panic(expected: ('ReentrancyGuard: reentrant call',))] fn test_reentrancy_guard_start_when_started() { let mut state = STATE(); diff --git a/src/tests/token/test_dual20.cairo b/src/tests/token/test_dual20.cairo index 6e1e5dc86..08eaf82c7 100644 --- a/src/tests/token/test_dual20.cairo +++ b/src/tests/token/test_dual20.cairo @@ -90,7 +90,7 @@ fn test_dual_name() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_name() { let dispatcher = setup_non_erc20(); dispatcher.name(); @@ -98,7 +98,7 @@ fn test_dual_no_name() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_name_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.name(); @@ -115,7 +115,7 @@ fn test_dual_symbol() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_symbol() { let dispatcher = setup_non_erc20(); dispatcher.symbol(); @@ -123,7 +123,7 @@ fn test_dual_no_symbol() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_symbol_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.symbol(); @@ -140,7 +140,7 @@ fn test_dual_decimals() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_decimals() { let dispatcher = setup_non_erc20(); dispatcher.decimals(); @@ -148,7 +148,7 @@ fn test_dual_no_decimals() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_decimals_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.decimals(); @@ -170,7 +170,7 @@ fn test_dual_transfer() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_transfer() { let dispatcher = setup_non_erc20(); dispatcher.transfer(RECIPIENT(), VALUE); @@ -178,7 +178,7 @@ fn test_dual_no_transfer() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_transfer_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.transfer(RECIPIENT(), VALUE); @@ -200,7 +200,7 @@ fn test_dual_approve() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_approve() { let dispatcher = setup_non_erc20(); dispatcher.approve(SPENDER(), VALUE); @@ -208,7 +208,7 @@ fn test_dual_no_approve() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_approve_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.approve(SPENDER(), VALUE); @@ -227,7 +227,7 @@ fn test_dual_total_supply() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_total_supply() { let dispatcher = setup_non_erc20(); dispatcher.total_supply(); @@ -235,7 +235,7 @@ fn test_dual_no_total_supply() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_total_supply_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.total_supply(); @@ -250,7 +250,7 @@ fn test_dual_balance_of() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_balance_of() { let dispatcher = setup_non_erc20(); dispatcher.balance_of(OWNER()); @@ -258,7 +258,7 @@ fn test_dual_no_balance_of() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_balance_of_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.balance_of(OWNER()); @@ -278,7 +278,7 @@ fn test_dual_transfer_from() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_transfer_from() { let dispatcher = setup_non_erc20(); dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); @@ -286,7 +286,7 @@ fn test_dual_no_transfer_from() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_transfer_from_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); @@ -305,7 +305,7 @@ fn test_dual_totalSupply() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_totalSupply_exists_and_panics() { let (_, dispatcher) = setup_erc20_panic(); dispatcher.total_supply(); @@ -320,7 +320,7 @@ fn test_dual_balanceOf() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_balanceOf_exists_and_panics() { let (_, dispatcher) = setup_erc20_panic(); dispatcher.balance_of(OWNER()); @@ -340,7 +340,7 @@ fn test_dual_transferFrom() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_transferFrom_exists_and_panics() { let (_, dispatcher) = setup_erc20_panic(); dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); diff --git a/src/tests/token/test_dual721.cairo b/src/tests/token/test_dual721.cairo index b5f02f7e9..6c1744258 100644 --- a/src/tests/token/test_dual721.cairo +++ b/src/tests/token/test_dual721.cairo @@ -76,11 +76,8 @@ fn setup_camel() -> (DualCaseERC721, IERC721CamelOnlyDispatcher) { set_contract_address(OWNER()); let target = utils::deploy(CamelERC721Mock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721 { - contract_address: target - }, IERC721CamelOnlyDispatcher { - contract_address: target - } + DualCaseERC721 { contract_address: target }, + IERC721CamelOnlyDispatcher { contract_address: target } ) } @@ -94,11 +91,8 @@ fn setup_erc721_panic() -> (DualCaseERC721, DualCaseERC721) { let snake_target = utils::deploy(SnakeERC721PanicMock::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelERC721PanicMock::TEST_CLASS_HASH, array![]); ( - DualCaseERC721 { - contract_address: snake_target - }, DualCaseERC721 { - contract_address: camel_target - } + DualCaseERC721 { contract_address: snake_target }, + DualCaseERC721 { contract_address: camel_target } ) } @@ -121,7 +115,7 @@ fn test_dual_name() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_name() { let dispatcher = setup_non_erc721(); dispatcher.name(); @@ -129,7 +123,7 @@ fn test_dual_no_name() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_name_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.name(); @@ -146,7 +140,7 @@ fn test_dual_symbol() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_symbol() { let dispatcher = setup_non_erc721(); dispatcher.symbol(); @@ -154,7 +148,7 @@ fn test_dual_no_symbol() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_symbol_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.symbol(); @@ -176,7 +170,7 @@ fn test_dual_approve() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_approve() { let dispatcher = setup_non_erc721(); dispatcher.approve(SPENDER(), TOKEN_ID); @@ -184,7 +178,7 @@ fn test_dual_no_approve() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_approve_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.approve(SPENDER(), TOKEN_ID); @@ -203,7 +197,7 @@ fn test_dual_balance_of() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_balance_of() { let dispatcher = setup_non_erc721(); dispatcher.balance_of(OWNER()); @@ -211,7 +205,7 @@ fn test_dual_no_balance_of() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_balance_of_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.balance_of(OWNER()); @@ -226,7 +220,7 @@ fn test_dual_owner_of() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_owner_of() { let dispatcher = setup_non_erc721(); dispatcher.owner_of(TOKEN_ID); @@ -234,7 +228,7 @@ fn test_dual_no_owner_of() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_owner_of_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.owner_of(TOKEN_ID); @@ -250,7 +244,7 @@ fn test_dual_transfer_from() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_transfer_from() { let dispatcher = setup_non_erc721(); dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); @@ -258,7 +252,7 @@ fn test_dual_no_transfer_from() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_transfer_from_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); @@ -275,7 +269,7 @@ fn test_dual_safe_transfer_from() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_safe_transfer_from() { let dispatcher = setup_non_erc721(); dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); @@ -283,7 +277,7 @@ fn test_dual_no_safe_transfer_from() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_safe_transfer_from_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); @@ -300,7 +294,7 @@ fn test_dual_get_approved() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_get_approved() { let dispatcher = setup_non_erc721(); dispatcher.get_approved(TOKEN_ID); @@ -308,7 +302,7 @@ fn test_dual_no_get_approved() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_get_approved_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.get_approved(TOKEN_ID); @@ -325,7 +319,7 @@ fn test_dual_set_approval_for_all() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_set_approval_for_all() { let dispatcher = setup_non_erc721(); dispatcher.set_approval_for_all(OPERATOR(), true); @@ -333,7 +327,7 @@ fn test_dual_no_set_approval_for_all() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_set_approval_for_all_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.set_approval_for_all(OPERATOR(), true); @@ -350,7 +344,7 @@ fn test_dual_is_approved_for_all() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_is_approved_for_all() { let dispatcher = setup_non_erc721(); dispatcher.is_approved_for_all(OWNER(), OPERATOR()); @@ -358,7 +352,7 @@ fn test_dual_no_is_approved_for_all() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_is_approved_for_all_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.is_approved_for_all(OWNER(), OPERATOR()); @@ -373,7 +367,7 @@ fn test_dual_token_uri() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_token_uri() { let dispatcher = setup_non_erc721(); dispatcher.token_uri(TOKEN_ID); @@ -381,7 +375,7 @@ fn test_dual_no_token_uri() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_token_uri_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.token_uri(TOKEN_ID); @@ -396,7 +390,7 @@ fn test_dual_supports_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_supports_interface() { let dispatcher = setup_non_erc721(); dispatcher.supports_interface(IERC721_ID); @@ -404,7 +398,7 @@ fn test_dual_no_supports_interface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_supports_interface_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.supports_interface(IERC721_ID); @@ -423,7 +417,7 @@ fn test_dual_balanceOf() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_balanceOf_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.balance_of(OWNER()); @@ -438,7 +432,7 @@ fn test_dual_ownerOf() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_ownerOf_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.owner_of(TOKEN_ID); @@ -455,7 +449,7 @@ fn test_dual_transferFrom() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_transferFrom_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); @@ -472,7 +466,7 @@ fn test_dual_safeTransferFrom() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_safeTransferFrom_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); @@ -489,7 +483,7 @@ fn test_dual_getApproved() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_getApproved_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.get_approved(TOKEN_ID); @@ -506,7 +500,7 @@ fn test_dual_setApprovalForAll() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_setApprovalForAll_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.set_approval_for_all(OPERATOR(), true); @@ -523,7 +517,7 @@ fn test_dual_isApprovedForAll() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_isApprovedForAll_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.is_approved_for_all(OWNER(), OPERATOR()); @@ -538,7 +532,7 @@ fn test_dual_tokenUri() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_tokenUri_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.token_uri(TOKEN_ID); @@ -553,7 +547,7 @@ fn test_dual_supportsInterface() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.supports_interface(IERC721_ID); diff --git a/src/tests/token/test_dual721_receiver.cairo b/src/tests/token/test_dual721_receiver.cairo index 9fde537c0..876661b8c 100644 --- a/src/tests/token/test_dual721_receiver.cairo +++ b/src/tests/token/test_dual721_receiver.cairo @@ -49,11 +49,8 @@ fn setup_snake() -> (DualCaseERC721Receiver, IERC721ReceiverDispatcher) { let mut calldata = ArrayTrait::new(); let target = utils::deploy(SnakeERC721ReceiverMock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721Receiver { - contract_address: target - }, IERC721ReceiverDispatcher { - contract_address: target - } + DualCaseERC721Receiver { contract_address: target }, + IERC721ReceiverDispatcher { contract_address: target } ) } @@ -61,11 +58,8 @@ fn setup_camel() -> (DualCaseERC721Receiver, IERC721ReceiverCamelDispatcher) { let mut calldata = ArrayTrait::new(); let target = utils::deploy(CamelERC721ReceiverMock::TEST_CLASS_HASH, calldata); ( - DualCaseERC721Receiver { - contract_address: target - }, IERC721ReceiverCamelDispatcher { - contract_address: target - } + DualCaseERC721Receiver { contract_address: target }, + IERC721ReceiverCamelDispatcher { contract_address: target } ) } @@ -83,11 +77,8 @@ fn setup_erc721_receiver_panic() -> (DualCaseERC721Receiver, DualCaseERC721Recei CamelERC721ReceiverPanicMock::TEST_CLASS_HASH, ArrayTrait::new() ); ( - DualCaseERC721Receiver { - contract_address: snake_target - }, DualCaseERC721Receiver { - contract_address: camel_target - } + DualCaseERC721Receiver { contract_address: snake_target }, + DualCaseERC721Receiver { contract_address: camel_target } ) } @@ -108,7 +99,7 @@ fn test_dual_on_erc721_received() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_on_erc721_received() { let dispatcher = setup_non_erc721_receiver(); dispatcher.on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); @@ -116,7 +107,7 @@ fn test_dual_no_on_erc721_received() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_on_erc721_received_exists_and_panics() { let (dispatcher, _) = setup_erc721_receiver_panic(); dispatcher.on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); @@ -139,7 +130,7 @@ fn test_dual_onERC721Received() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] fn test_dual_onERC721Received_exists_and_panics() { let (_, dispatcher) = setup_erc721_receiver_panic(); dispatcher.on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); diff --git a/src/tests/token/test_erc20.cairo b/src/tests/token/test_erc20.cairo index a2e609a1b..4109e909a 100644 --- a/src/tests/token/test_erc20.cairo +++ b/src/tests/token/test_erc20.cairo @@ -130,7 +130,7 @@ fn test_approve() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve from 0', ))] +#[should_panic(expected: ('ERC20: approve from 0',))] fn test_approve_from_zero() { let mut state = setup(); ERC20Impl::approve(ref state, SPENDER(), VALUE); @@ -138,7 +138,7 @@ fn test_approve_from_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve to 0', ))] +#[should_panic(expected: ('ERC20: approve to 0',))] fn test_approve_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -160,7 +160,7 @@ fn test__approve() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve from 0', ))] +#[should_panic(expected: ('ERC20: approve from 0',))] fn test__approve_from_zero() { let mut state = setup(); InternalImpl::_approve(ref state, Zeroable::zero(), SPENDER(), VALUE); @@ -168,7 +168,7 @@ fn test__approve_from_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve to 0', ))] +#[should_panic(expected: ('ERC20: approve to 0',))] fn test__approve_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -207,7 +207,7 @@ fn test__transfer() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test__transfer_not_enough_balance() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -218,7 +218,7 @@ fn test__transfer_not_enough_balance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: transfer from 0', ))] +#[should_panic(expected: ('ERC20: transfer from 0',))] fn test__transfer_from_zero() { let mut state = setup(); InternalImpl::_transfer(ref state, Zeroable::zero(), RECIPIENT(), VALUE); @@ -226,7 +226,7 @@ fn test__transfer_from_zero() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: transfer to 0', ))] +#[should_panic(expected: ('ERC20: transfer to 0',))] fn test__transfer_to_zero() { let mut state = setup(); InternalImpl::_transfer(ref state, OWNER(), Zeroable::zero(), VALUE); @@ -274,7 +274,7 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test_transfer_from_greater_than_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -287,7 +287,7 @@ fn test_transfer_from_greater_than_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: transfer to 0', ))] +#[should_panic(expected: ('ERC20: transfer to 0',))] fn test_transfer_from_to_zero_address() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -299,7 +299,7 @@ fn test_transfer_from_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test_transfer_from_from_zero_address() { let mut state = setup(); ERC20Impl::transfer_from(ref state, Zeroable::zero(), RECIPIENT(), VALUE); @@ -348,7 +348,7 @@ fn test_transferFrom_doesnt_consume_infinite_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test_transferFrom_greater_than_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -361,7 +361,7 @@ fn test_transferFrom_greater_than_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: transfer to 0', ))] +#[should_panic(expected: ('ERC20: transfer to 0',))] fn test_transferFrom_to_zero_address() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -373,7 +373,7 @@ fn test_transferFrom_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test_transferFrom_from_zero_address() { let mut state = setup(); ERC20CamelOnlyImpl::transferFrom(ref state, Zeroable::zero(), RECIPIENT(), VALUE); @@ -399,7 +399,7 @@ fn test_increase_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve to 0', ))] +#[should_panic(expected: ('ERC20: approve to 0',))] fn test_increase_allowance_to_zero_address() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -408,7 +408,7 @@ fn test_increase_allowance_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve from 0', ))] +#[should_panic(expected: ('ERC20: approve from 0',))] fn test_increase_allowance_from_zero_address() { let mut state = setup(); ERC20::increase_allowance(ref state, SPENDER(), VALUE); @@ -430,7 +430,7 @@ fn test_increaseAllowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve to 0', ))] +#[should_panic(expected: ('ERC20: approve to 0',))] fn test_increaseAllowance_to_zero_address() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -439,7 +439,7 @@ fn test_increaseAllowance_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: approve from 0', ))] +#[should_panic(expected: ('ERC20: approve from 0',))] fn test_increaseAllowance_from_zero_address() { let mut state = setup(); ERC20::increaseAllowance(ref state, SPENDER(), VALUE); @@ -465,7 +465,7 @@ fn test_decrease_allowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test_decrease_allowance_to_zero_address() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -474,7 +474,7 @@ fn test_decrease_allowance_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test_decrease_allowance_from_zero_address() { let mut state = setup(); ERC20::decrease_allowance(ref state, SPENDER(), VALUE); @@ -496,7 +496,7 @@ fn test_decreaseAllowance() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test_decreaseAllowance_to_zero_address() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -505,7 +505,7 @@ fn test_decreaseAllowance_to_zero_address() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('u256_sub Overflow', ))] +#[should_panic(expected: ('u256_sub Overflow',))] fn test_decreaseAllowance_from_zero_address() { let mut state = setup(); ERC20::decreaseAllowance(ref state, SPENDER(), VALUE); @@ -564,7 +564,7 @@ fn test__mint() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: mint to 0', ))] +#[should_panic(expected: ('ERC20: mint to 0',))] fn test__mint_to_zero() { let mut state = STATE(); InternalImpl::_mint(ref state, Zeroable::zero(), VALUE); @@ -587,7 +587,7 @@ fn test__burn() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ERC20: burn from 0', ))] +#[should_panic(expected: ('ERC20: burn from 0',))] fn test__burn_from_zero() { let mut state = setup(); InternalImpl::_burn(ref state, Zeroable::zero(), VALUE); diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index b39b24a01..1351e0385 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -1,5 +1,5 @@ -use ERC721::_owners::InternalContractStateTrait as OwnersTrait; -use ERC721::_token_approvals::InternalContractStateTrait as TokenApprovalsTrait; +use ERC721::_owners::InternalContractMemberStateTrait as OwnersTrait; +use ERC721::_token_approvals::InternalContractMemberStateTrait as TokenApprovalsTrait; use array::ArrayTrait; use integer::u256; @@ -138,7 +138,7 @@ fn test_balance_of() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid account', ))] +#[should_panic(expected: ('ERC721: invalid account',))] fn test_balance_of_zero() { ERC721Impl::balance_of(@STATE(), ZERO()); } @@ -152,14 +152,14 @@ fn test_owner_of() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test_owner_of_non_minted() { ERC721Impl::owner_of(@STATE(), u256_from_felt252(7)); } #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test_token_uri_non_minted() { ERC721MetadataImpl::token_uri(@STATE(), u256_from_felt252(7)); } @@ -178,7 +178,7 @@ fn test_get_approved() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test_get_approved_nonexistent() { ERC721Impl::get_approved(@STATE(), u256_from_felt252(7)); } @@ -242,7 +242,7 @@ fn test_approve_from_operator() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: unauthorized caller', ))] +#[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_approve_from_unauthorized() { let mut state = setup(); @@ -252,7 +252,7 @@ fn test_approve_from_unauthorized() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: approval to owner', ))] +#[should_panic(expected: ('ERC721: approval to owner',))] fn test_approve_to_owner() { let mut state = setup(); @@ -262,7 +262,7 @@ fn test_approve_to_owner() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test_approve_nonexistent() { let mut state = STATE(); ERC721Impl::approve(ref state, SPENDER(), TOKEN_ID); @@ -282,7 +282,7 @@ fn test__approve() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: approval to owner', ))] +#[should_panic(expected: ('ERC721: approval to owner',))] fn test__approve_to_owner() { let mut state = setup(); InternalImpl::_approve(ref state, OWNER(), TOKEN_ID); @@ -290,7 +290,7 @@ fn test__approve_to_owner() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test__approve_nonexistent() { let mut state = STATE(); InternalImpl::_approve(ref state, SPENDER(), TOKEN_ID); @@ -327,7 +327,7 @@ fn test_set_approval_for_all() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: self approval', ))] +#[should_panic(expected: ('ERC721: self approval',))] fn test_set_approval_for_all_owner_equal_operator_true() { let mut state = STATE(); testing::set_caller_address(OWNER()); @@ -336,7 +336,7 @@ fn test_set_approval_for_all_owner_equal_operator_true() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: self approval', ))] +#[should_panic(expected: ('ERC721: self approval',))] fn test_set_approval_for_all_owner_equal_operator_false() { let mut state = STATE(); testing::set_caller_address(OWNER()); @@ -368,7 +368,7 @@ fn test__set_approval_for_all() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: self approval', ))] +#[should_panic(expected: ('ERC721: self approval',))] fn test__set_approval_for_all_owner_equal_operator_true() { let mut state = STATE(); InternalImpl::_set_approval_for_all(ref state, OWNER(), OWNER(), true); @@ -376,7 +376,7 @@ fn test__set_approval_for_all_owner_equal_operator_true() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: self approval', ))] +#[should_panic(expected: ('ERC721: self approval',))] fn test__set_approval_for_all_owner_equal_operator_false() { let mut state = STATE(); InternalImpl::_set_approval_for_all(ref state, OWNER(), OWNER(), false); @@ -430,7 +430,7 @@ fn test_transferFrom_owner() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test_transfer_from_nonexistent() { let mut state = STATE(); ERC721Impl::transfer_from(ref state, ZERO(), RECIPIENT(), TOKEN_ID); @@ -438,7 +438,7 @@ fn test_transfer_from_nonexistent() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test_transferFrom_nonexistent() { let mut state = STATE(); ERC721CamelOnlyImpl::transferFrom(ref state, ZERO(), RECIPIENT(), TOKEN_ID); @@ -446,7 +446,7 @@ fn test_transferFrom_nonexistent() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid receiver', ))] +#[should_panic(expected: ('ERC721: invalid receiver',))] fn test_transfer_from_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -455,7 +455,7 @@ fn test_transfer_from_to_zero() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid receiver', ))] +#[should_panic(expected: ('ERC721: invalid receiver',))] fn test_transferFrom_to_zero() { let mut state = setup(); @@ -579,7 +579,7 @@ fn test_transferFrom_approved_for_all() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: unauthorized caller', ))] +#[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_transfer_from_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -588,7 +588,7 @@ fn test_transfer_from_unauthorized() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: unauthorized caller', ))] +#[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_transferFrom_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -737,7 +737,7 @@ fn test_safeTransferFrom_to_receiver_camel() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: safe transfer failed', ))] +#[should_panic(expected: ('ERC721: safe transfer failed',))] fn test_safe_transfer_from_to_receiver_failure() { let mut state = setup(); let receiver = setup_receiver(); @@ -750,7 +750,7 @@ fn test_safe_transfer_from_to_receiver_failure() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: safe transfer failed', ))] +#[should_panic(expected: ('ERC721: safe transfer failed',))] fn test_safeTransferFrom_to_receiver_failure() { let mut state = setup(); let receiver = setup_receiver(); @@ -763,7 +763,7 @@ fn test_safeTransferFrom_to_receiver_failure() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: safe transfer failed', ))] +#[should_panic(expected: ('ERC721: safe transfer failed',))] fn test_safe_transfer_from_to_receiver_failure_camel() { let mut state = setup(); let receiver = setup_camel_receiver(); @@ -776,7 +776,7 @@ fn test_safe_transfer_from_to_receiver_failure_camel() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: safe transfer failed', ))] +#[should_panic(expected: ('ERC721: safe transfer failed',))] fn test_safeTransferFrom_to_receiver_failure_camel() { let mut state = setup(); let receiver = setup_camel_receiver(); @@ -789,7 +789,7 @@ fn test_safeTransferFrom_to_receiver_failure_camel() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_safe_transfer_from_to_non_receiver() { let mut state = setup(); let recipient = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, array![]); @@ -802,7 +802,7 @@ fn test_safe_transfer_from_to_non_receiver() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_safeTransferFrom_to_non_receiver() { let mut state = setup(); let recipient = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, array![]); @@ -815,7 +815,7 @@ fn test_safeTransferFrom_to_non_receiver() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test_safe_transfer_from_nonexistent() { let mut state = STATE(); ERC721Impl::safe_transfer_from(ref state, ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); @@ -823,7 +823,7 @@ fn test_safe_transfer_from_nonexistent() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test_safeTransferFrom_nonexistent() { let mut state = STATE(); ERC721CamelOnlyImpl::safeTransferFrom(ref state, ZERO(), RECIPIENT(), TOKEN_ID, DATA(true)); @@ -831,7 +831,7 @@ fn test_safeTransferFrom_nonexistent() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid receiver', ))] +#[should_panic(expected: ('ERC721: invalid receiver',))] fn test_safe_transfer_from_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -840,7 +840,7 @@ fn test_safe_transfer_from_to_zero() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid receiver', ))] +#[should_panic(expected: ('ERC721: invalid receiver',))] fn test_safeTransferFrom_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -1101,7 +1101,7 @@ fn test_safeTransferFrom_approved_for_all_camel() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: unauthorized caller', ))] +#[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_safe_transfer_from_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -1110,7 +1110,7 @@ fn test_safe_transfer_from_unauthorized() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: unauthorized caller', ))] +#[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_safeTransferFrom_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); @@ -1139,7 +1139,7 @@ fn test__transfer() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test__transfer_nonexistent() { let mut state = STATE(); InternalImpl::_transfer(ref state, ZERO(), RECIPIENT(), TOKEN_ID); @@ -1147,7 +1147,7 @@ fn test__transfer_nonexistent() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid receiver', ))] +#[should_panic(expected: ('ERC721: invalid receiver',))] fn test__transfer_to_zero() { let mut state = setup(); InternalImpl::_transfer(ref state, OWNER(), ZERO(), TOKEN_ID); @@ -1155,7 +1155,7 @@ fn test__transfer_to_zero() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: wrong sender', ))] +#[should_panic(expected: ('ERC721: wrong sender',))] fn test__transfer_from_invalid_owner() { let mut state = setup(); InternalImpl::_transfer(ref state, RECIPIENT(), OWNER(), TOKEN_ID); @@ -1181,7 +1181,7 @@ fn test__mint() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid receiver', ))] +#[should_panic(expected: ('ERC721: invalid receiver',))] fn test__mint_to_zero() { let mut state = STATE(); InternalImpl::_mint(ref state, ZERO(), TOKEN_ID); @@ -1189,7 +1189,7 @@ fn test__mint_to_zero() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: token already minted', ))] +#[should_panic(expected: ('ERC721: token already minted',))] fn test__mint_already_exist() { let mut state = setup(); InternalImpl::_mint(ref state, RECIPIENT(), TOKEN_ID); @@ -1257,7 +1257,7 @@ fn test__safe_mint_to_account_camel() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test__safe_mint_to_non_receiver() { let mut state = STATE(); let recipient = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, array![]); @@ -1270,7 +1270,7 @@ fn test__safe_mint_to_non_receiver() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: safe mint failed', ))] +#[should_panic(expected: ('ERC721: safe mint failed',))] fn test__safe_mint_to_receiver_failure() { let mut state = STATE(); let recipient = setup_receiver(); @@ -1283,7 +1283,7 @@ fn test__safe_mint_to_receiver_failure() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: safe mint failed', ))] +#[should_panic(expected: ('ERC721: safe mint failed',))] fn test__safe_mint_to_receiver_failure_camel() { let mut state = STATE(); let recipient = setup_camel_receiver(); @@ -1296,7 +1296,7 @@ fn test__safe_mint_to_receiver_failure_camel() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid receiver', ))] +#[should_panic(expected: ('ERC721: invalid receiver',))] fn test__safe_mint_to_zero() { let mut state = STATE(); InternalImpl::_safe_mint(ref state, ZERO(), TOKEN_ID, DATA(true)); @@ -1304,7 +1304,7 @@ fn test__safe_mint_to_zero() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: token already minted', ))] +#[should_panic(expected: ('ERC721: token already minted',))] fn test__safe_mint_already_exist() { let mut state = setup(); InternalImpl::_safe_mint(ref state, RECIPIENT(), TOKEN_ID, DATA(true)); @@ -1336,7 +1336,7 @@ fn test__burn() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test__burn_nonexistent() { let mut state = STATE(); InternalImpl::_burn(ref state, TOKEN_ID); @@ -1358,7 +1358,7 @@ fn test__set_token_uri() { #[test] #[available_gas(20000000)] -#[should_panic(expected: ('ERC721: invalid token ID', ))] +#[should_panic(expected: ('ERC721: invalid token ID',))] fn test__set_token_uri_nonexistent() { let mut state = STATE(); InternalImpl::_set_token_uri(ref state, TOKEN_ID, URI); diff --git a/src/tests/upgrades/test_upgradeable.cairo b/src/tests/upgrades/test_upgradeable.cairo index 66de7a2a7..20b9c48c3 100644 --- a/src/tests/upgrades/test_upgradeable.cairo +++ b/src/tests/upgrades/test_upgradeable.cairo @@ -46,7 +46,7 @@ fn deploy_v1() -> IUpgradesV1Dispatcher { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('Class hash cannot be zero', 'ENTRYPOINT_FAILED', ))] +#[should_panic(expected: ('Class hash cannot be zero', 'ENTRYPOINT_FAILED',))] fn test_upgrade_with_class_hash_zero() { let v1 = deploy_v1(); v1.upgrade(CLASS_HASH_ZERO()); @@ -95,7 +95,7 @@ fn test_remove_selector_passes_in_v1() { #[test] #[available_gas(2000000)] -#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', ))] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_remove_selector_fails_in_v2() { let v1 = deploy_v1(); v1.upgrade(V2_CLASS_HASH()); diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index 32a265c06..70ae7cd39 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -351,12 +351,9 @@ mod ERC721 { fn _check_on_erc721_received( from: ContractAddress, to: ContractAddress, token_id: u256, data: Span ) -> bool { - if (DualCaseSRC5 { - contract_address: to - }.supports_interface(interface::IERC721_RECEIVER_ID)) { - DualCaseERC721Receiver { - contract_address: to - } + if (DualCaseSRC5 { contract_address: to } + .supports_interface(interface::IERC721_RECEIVER_ID)) { + DualCaseERC721Receiver { contract_address: to } .on_erc721_received( get_caller_address(), from, token_id, data ) == interface::IERC721_RECEIVER_ID diff --git a/src/upgrades/upgradeable.cairo b/src/upgrades/upgradeable.cairo index 444cf36b7..b10978d85 100644 --- a/src/upgrades/upgradeable.cairo +++ b/src/upgrades/upgradeable.cairo @@ -22,7 +22,7 @@ mod Upgradeable { impl InternalImpl of InternalState { fn _upgrade(ref self: ContractState, new_class_hash: ClassHash) { assert(!new_class_hash.is_zero(), 'Class hash cannot be zero'); - starknet::replace_class_syscall(new_class_hash).unwrap_syscall(); + starknet::replace_class_syscall(new_class_hash).unwrap(); self.emit(Upgraded { class_hash: new_class_hash }); } } From 05429e4fd34a250ce7a01450190c53275e5c1c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Mon, 28 Aug 2023 12:48:00 -0300 Subject: [PATCH 090/124] bump antora (#715) --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index f75680009..ceea1e622 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: contracts-cairo title: Contracts for Cairo -version: 0.6.1 +version: 0.7.0 nav: - modules/ROOT/nav.adoc From adac09f7943bc9c13e4fba5963162ecb53e7268b Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 8 Sep 2023 16:36:49 -0400 Subject: [PATCH 091/124] Add selector inline macro/fix `tokenURI` (#724) * update selectors * use inline selector * remove selectors file * remove import * fix camel tokenURI * fix formatting * re-add selectors mod * import from selectors mod * fix formatting * import selector --- src/tests/mocks/camel721_mock.cairo | 4 +- src/tests/mocks/erc721_panic_mock.cairo | 2 +- src/tests/token/test_dual721.cairo | 4 +- src/token/erc721/dual721.cairo | 2 +- src/token/erc721/erc721.cairo | 2 +- src/token/erc721/interface.cairo | 2 +- src/utils/selectors.cairo | 108 +++++++++++------------- 7 files changed, 57 insertions(+), 67 deletions(-) diff --git a/src/tests/mocks/camel721_mock.cairo b/src/tests/mocks/camel721_mock.cairo index 9fcbbb248..2117697d8 100644 --- a/src/tests/mocks/camel721_mock.cairo +++ b/src/tests/mocks/camel721_mock.cairo @@ -38,9 +38,9 @@ mod CamelERC721Mock { } #[external(v0)] - fn tokenUri(self: @ContractState, tokenId: u256) -> felt252 { + fn tokenURI(self: @ContractState, tokenId: u256) -> felt252 { let unsafe_state = ERC721::unsafe_new_contract_state(); - ERC721::ERC721MetadataCamelOnlyImpl::tokenUri(@unsafe_state, tokenId) + ERC721::ERC721MetadataCamelOnlyImpl::tokenURI(@unsafe_state, tokenId) } #[external(v0)] diff --git a/src/tests/mocks/erc721_panic_mock.cairo b/src/tests/mocks/erc721_panic_mock.cairo index 6d172c379..ace550d33 100644 --- a/src/tests/mocks/erc721_panic_mock.cairo +++ b/src/tests/mocks/erc721_panic_mock.cairo @@ -107,7 +107,7 @@ mod CamelERC721PanicMock { } #[external(v0)] - fn tokenUri(self: @ContractState, tokenId: u256) -> felt252 { + fn tokenURI(self: @ContractState, tokenId: u256) -> felt252 { panic_with_felt252('Some error'); 3 } diff --git a/src/tests/token/test_dual721.cairo b/src/tests/token/test_dual721.cairo index 6c1744258..fc65cc426 100644 --- a/src/tests/token/test_dual721.cairo +++ b/src/tests/token/test_dual721.cairo @@ -525,7 +525,7 @@ fn test_dual_isApprovedForAll_exists_and_panics() { #[test] #[available_gas(2000000)] -fn test_dual_tokenUri() { +fn test_dual_tokenURI() { let (dispatcher, target) = setup_camel(); assert(dispatcher.token_uri(TOKEN_ID) == URI, 'Should return URI'); } @@ -533,7 +533,7 @@ fn test_dual_tokenUri() { #[test] #[available_gas(2000000)] #[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] -fn test_dual_tokenUri_exists_and_panics() { +fn test_dual_tokenURI_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.token_uri(TOKEN_ID); } diff --git a/src/token/erc721/dual721.cairo b/src/token/erc721/dual721.cairo index 88cc35abd..041f267a2 100644 --- a/src/token/erc721/dual721.cairo +++ b/src/token/erc721/dual721.cairo @@ -56,7 +56,7 @@ impl DualCaseERC721Impl of DualCaseERC721Trait { args.append_serde(token_id); try_selector_with_fallback( - *self.contract_address, selectors::token_uri, selectors::tokenUri, args.span() + *self.contract_address, selectors::token_uri, selectors::tokenURI, args.span() ) .unwrap_and_cast() } diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index 70ae7cd39..0abffb4d1 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -110,7 +110,7 @@ mod ERC721 { #[external(v0)] impl ERC721MetadataCamelOnlyImpl of interface::IERC721MetadataCamelOnly { - fn tokenUri(self: @ContractState, tokenId: u256) -> felt252 { + fn tokenURI(self: @ContractState, tokenId: u256) -> felt252 { assert(self._exists(tokenId), 'ERC721: invalid token ID'); self._token_uri.read(tokenId) } diff --git a/src/token/erc721/interface.cairo b/src/token/erc721/interface.cairo index 4aff670b8..86125721d 100644 --- a/src/token/erc721/interface.cairo +++ b/src/token/erc721/interface.cairo @@ -60,7 +60,7 @@ trait IERC721Metadata { #[starknet::interface] trait IERC721MetadataCamelOnly { - fn tokenUri(self: @TState, tokenId: u256) -> felt252; + fn tokenURI(self: @TState, tokenId: u256) -> felt252; } // diff --git a/src/utils/selectors.cairo b/src/utils/selectors.cairo index 1695e17cb..505a35374 100644 --- a/src/utils/selectors.cairo +++ b/src/utils/selectors.cairo @@ -5,64 +5,57 @@ // AccessControl // -const get_role_admin: felt252 = 0x302e0454f48778e0ca3a2e714a289c4e8d8e03d614b370130abb1a524a47f22; -const getRoleAdmin: felt252 = 0x2034da88f3e3f3382ab0faf97fe5f74fe34d551ddff7fda974d756bf12130a0; -const grant_role: felt252 = 0x18a2f881894a5eb15a2a00f598839abaa75bd7f1fea1a37e42779d7fbcd9cf8; -const grantRole: felt252 = 0x37322ff1aabefe50aec25a14eb84b168b7be4f2d66fbbdb5dd8135e8234c37a; -const has_role: felt252 = 0x30559321b47d576b645ed7bd24089943dd5fd3a359ecdd6fa8f05c1bab67d6b; -const hasRole: felt252 = 0x35ed3407ba17dc741dd3af821fa1548619ebcdc87c95bcea9e3bc510951fae8; -const renounce_role: felt252 = 0xd80093a4ee6a9e649f2ae3c64963d5096948d50cf4ea055500aa03a342fd43; -const renounceRole: felt252 = 0x3c4022816cd5119ac7938fd7a982062e4cacd4777b4eda6e6a8f64d9e6833; -const revoke_role: felt252 = 0x246116ed358bad337e64a4df51cb57a40929189494ad5905a39872c489136ec; -const revokeRole: felt252 = 0xa7ef1739dec1e216a0ba2987650983a3104c707ad0831a30184a3b1382dd7d; +const get_role_admin: felt252 = selector!("get_role_admin"); +const getRoleAdmin: felt252 = selector!("getRoleAdmin"); +const grant_role: felt252 = selector!("grant_role"); +const grantRole: felt252 = selector!("grantRole"); +const has_role: felt252 = selector!("has_role"); +const hasRole: felt252 = selector!("hasRole"); +const renounce_role: felt252 = selector!("renounce_role"); +const renounceRole: felt252 = selector!("renounceRole"); +const revoke_role: felt252 = selector!("revoke_role"); +const revokeRole: felt252 = selector!("revokeRole"); // // Ownable // -const owner: felt252 = 0x2016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0; -const transfer_ownership: felt252 = - 0x2a3bb1eaa05b77c4b0eeee0116a3177c6d62319dd7149ae148185d9e09de74a; -const transferOwnership: felt252 = - 0x14a390f291e2e1f29874769efdef47ddad94d76f77ff516fad206a385e8995f; -const renounce_ownership: felt252 = 0x52580a92c73f4428f1a260c5d768ef462b25955307de00f99957df119865d; -const renounceOwnership: felt252 = 0xd5d33d590e6660853069b37a2aea67c6fdaa0268626bc760350b590490feb5; +const owner: felt252 = selector!("owner"); +const transfer_ownership: felt252 = selector!("transfer_ownership"); +const transferOwnership: felt252 = selector!("transferOwnership"); +const renounce_ownership: felt252 = selector!("renounce_ownership"); +const renounceOwnership: felt252 = selector!("renounceOwnership"); // // ERC721 // -const name: felt252 = 0x361458367e696363fbcc70777d07ebbd2394e89fd0adcaf147faccd1d294d60; -const symbol: felt252 = 0x216b05c387bab9ac31918a3e61672f4618601f3c598a2f3f2710f37053e1ea4; -const token_uri: felt252 = 0x226ad7e84c1fe08eb4c525ed93cccadf9517670341304571e66f7c4f95cbe54; -const tokenUri: felt252 = 0x362dec5b8b67ab667ad08e83a2c3ba1db7fdb4ab8dc3a33c057c4fddec8d3de; -const balance_of: felt252 = 0x35a73cd311a05d46deda634c5ee045db92f811b4e74bca4437fcb5302b7af33; -const balanceOf: felt252 = 0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e; -const owner_of: felt252 = 0x3552df12bdc6089cf963c40c4cf56fbfd4bd14680c244d1c5494c2790f1ea5c; -const ownerOf: felt252 = 0x2962ba17806af798afa6eaf4aa8c93a9fb60a3e305045b6eea33435086cae9; -const get_approved: felt252 = 0x309065f1424d76d4a4ace2ff671391d59536e0297409434908d38673290a749; -const getApproved: felt252 = 0xb180e2fe9f14914416216da76338ac0beb980443725c802af615f8431fdb1e; -const is_approved_for_all: felt252 = - 0x2aa3ea196f9b8a4f65613b67fcf185e69d8faa9601a3382871d15b3060e30dd; -const isApprovedForAll: felt252 = 0x21cdf9aedfed41bc4485ae779fda471feca12075d9127a0fc70ac6b3b3d9c30; -const approve: felt252 = 0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c; -const set_approval_for_all: felt252 = - 0xd86ca3d41635e20c180181046b11abcf19e1bdef3dcaa4c180300ccca1813f; -const setApprovalForAll: felt252 = - 0x2d4c8ea4c8fb9f571d1f6f9b7692fff8e5ceaf73b1df98e7da8c1109b39ae9a; -const transfer_from: felt252 = 0x3704ffe8fba161be0e994951751a5033b1462b918ff785c0a636be718dfdb68; -const transferFrom: felt252 = 0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20; -const safe_transfer_from: felt252 = - 0x16f0218b33b5cf273196787d7cf139a9ad13d58e6674dcdce722b3bf8389863; -const safeTransferFrom: felt252 = 0x19d59d013d4aa1a8b1ce4c8299086f070733b453c02d0dc46e735edc04d6444; +const name: felt252 = selector!("name"); +const symbol: felt252 = selector!("symbol"); +const token_uri: felt252 = selector!("token_uri"); +const tokenURI: felt252 = selector!("tokenURI"); +const balance_of: felt252 = selector!("balance_of"); +const balanceOf: felt252 = selector!("balanceOf"); +const owner_of: felt252 = selector!("owner_of"); +const ownerOf: felt252 = selector!("ownerOf"); +const get_approved: felt252 = selector!("get_approved"); +const getApproved: felt252 = selector!("getApproved"); +const is_approved_for_all: felt252 = selector!("is_approved_for_all"); +const isApprovedForAll: felt252 = selector!("isApprovedForAll"); +const approve: felt252 = selector!("approve"); +const set_approval_for_all: felt252 = selector!("set_approval_for_all"); +const setApprovalForAll: felt252 = selector!("setApprovalForAll"); +const transfer_from: felt252 = selector!("transfer_from"); +const transferFrom: felt252 = selector!("transferFrom"); +const safe_transfer_from: felt252 = selector!("safe_transfer_from"); +const safeTransferFrom: felt252 = selector!("safeTransferFrom"); // // ERC721Receiver // -const on_erc721_received: felt252 = - 0x38c7ee9f0855dfe219aea022b141d9b2ec0f6b68395d221c3f331c7ca4fb608; -const onERC721Received: felt252 = 0xfa119a8fafc6f1a02deb36fe5efbcc4929ef2021e50cf1cb6d1a780ccd009b; +const on_erc721_received: felt252 = selector!("on_erc721_received"); +const onERC721Received: felt252 = selector!("onERC721Received"); // // ERC20 @@ -70,24 +63,21 @@ const onERC721Received: felt252 = 0xfa119a8fafc6f1a02deb36fe5efbcc4929ef2021e50c // The following ERC20 selectors are already defined in ERC721 above: // name, symbol, balance_of, balanceOf, transfer_from, transferFrom, approve -const decimals: felt252 = 0x4c4fb1ab068f6039d5780c68dd0fa2f8742cceb3426d19667778ca7f3518a9; -const total_supply: felt252 = 0x1557182e4359a1f0c6301278e8f5b35a776ab58d39892581e357578fb287836; -const totalSupply: felt252 = 0x80aa9fdbfaf9615e4afc7f5f722e265daca5ccc655360fa5ccacf9c267936d; -const allowance: felt252 = 0x1e888a1026b19c8c0b57c72d63ed1737106aa10034105b980ba117bd0c29fe1; -const transfer: felt252 = 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e; +const decimals: felt252 = selector!("decimals"); +const total_supply: felt252 = selector!("total_supply"); +const totalSupply: felt252 = selector!("totalSupply"); +const allowance: felt252 = selector!("allowance"); +const transfer: felt252 = selector!("transfer"); // // Account // -const set_public_key: felt252 = 0x2e3e21ff5952b2531241e37999d9c4c8b3034cccc89a202a6bf019bdf5294f9; -const setPublicKey: felt252 = 0xbc0eb87884ab91e330445c3584a50d7ddf4b568f02fbeb456a6242cce3f5d9; -const get_public_key: felt252 = 0x1a35984e05126dbecb7c3bb9929e7dd9106d460c59b1633739a5c733a5fb13b; -const getPublicKey: felt252 = 0x1a6c6a0bdec86cc645c91997d8eea83e87148659e3e61122f72361fd5e94079; -const is_valid_signature: felt252 = - 0x28420862938116cb3bbdbedee07451ccc54d4e9412dbef71142ad1980a30941; -const isValidSignature: felt252 = 0x213dfe25e2ca309c4d615a09cfc95fdb2fc7dc73fbcad12c450fe93b1f2ff9e; -const supports_interface: felt252 = - 0xfe80f537b66d12a00b6d3c072b44afbb716e78dde5c3f0ef116ee93d3e3283; -const supportsInterface: felt252 = - 0x29e211664c0b63c79638fbea474206ca74016b3e9a3dc4f9ac300ffd8bdf2cd; +const set_public_key: felt252 = selector!("set_public_key"); +const setPublicKey: felt252 = selector!("setPublicKey"); +const get_public_key: felt252 = selector!("get_public_key"); +const getPublicKey: felt252 = selector!("getPublicKey"); +const is_valid_signature: felt252 = selector!("is_valid_signature"); +const isValidSignature: felt252 = selector!("isValidSignature"); +const supports_interface: felt252 = selector!("supports_interface"); +const supportsInterface: felt252 = selector!("supportsInterface"); From 90be39f764863864b49f30763eb22f78ed137746 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 14 Sep 2023 07:05:11 +0200 Subject: [PATCH 092/124] fix: naming convention (#732) --- src/tests/token/test_dual20.cairo | 23 +++++++++-------- src/token/erc20/dual20.cairo | 42 +++++++++++++++---------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/tests/token/test_dual20.cairo b/src/tests/token/test_dual20.cairo index 08eaf82c7..aa0bd2306 100644 --- a/src/tests/token/test_dual20.cairo +++ b/src/tests/token/test_dual20.cairo @@ -5,8 +5,8 @@ use openzeppelin::tests::mocks::erc20_panic::SnakeERC20Panic; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::snake20_mock::SnakeERC20Mock; use openzeppelin::tests::utils; -use openzeppelin::token::erc20::dual20::DualERC20; -use openzeppelin::token::erc20::dual20::DualERC20Trait; +use openzeppelin::token::erc20::dual20::DualCaseERC20; +use openzeppelin::token::erc20::dual20::DualCaseERC20Trait; use openzeppelin::token::erc20::interface::IERC20CamelDispatcher; use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait; use openzeppelin::token::erc20::interface::IERC20Dispatcher; @@ -43,36 +43,39 @@ fn OPERATOR() -> ContractAddress { // Setup // -fn setup_snake() -> (DualERC20, IERC20Dispatcher) { +fn setup_snake() -> (DualCaseERC20, IERC20Dispatcher) { let mut calldata = array![]; calldata.append_serde(NAME); calldata.append_serde(SYMBOL); calldata.append_serde(SUPPLY); calldata.append_serde(OWNER()); let target = utils::deploy(SnakeERC20Mock::TEST_CLASS_HASH, calldata); - (DualERC20 { contract_address: target }, IERC20Dispatcher { contract_address: target }) + (DualCaseERC20 { contract_address: target }, IERC20Dispatcher { contract_address: target }) } -fn setup_camel() -> (DualERC20, IERC20CamelDispatcher) { +fn setup_camel() -> (DualCaseERC20, IERC20CamelDispatcher) { let mut calldata = array![]; calldata.append_serde(NAME); calldata.append_serde(SYMBOL); calldata.append_serde(SUPPLY); calldata.append_serde(OWNER()); let target = utils::deploy(CamelERC20Mock::TEST_CLASS_HASH, calldata); - (DualERC20 { contract_address: target }, IERC20CamelDispatcher { contract_address: target }) + (DualCaseERC20 { contract_address: target }, IERC20CamelDispatcher { contract_address: target }) } -fn setup_non_erc20() -> DualERC20 { +fn setup_non_erc20() -> DualCaseERC20 { let calldata = array![]; let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); - DualERC20 { contract_address: target } + DualCaseERC20 { contract_address: target } } -fn setup_erc20_panic() -> (DualERC20, DualERC20) { +fn setup_erc20_panic() -> (DualCaseERC20, DualCaseERC20) { let snake_target = utils::deploy(SnakeERC20Panic::TEST_CLASS_HASH, array![]); let camel_target = utils::deploy(CamelERC20Panic::TEST_CLASS_HASH, array![]); - (DualERC20 { contract_address: snake_target }, DualERC20 { contract_address: camel_target }) + ( + DualCaseERC20 { contract_address: snake_target }, + DualCaseERC20 { contract_address: camel_target } + ) } // diff --git a/src/token/erc20/dual20.cairo b/src/token/erc20/dual20.cairo index 28897c6f5..dfb54584b 100644 --- a/src/token/erc20/dual20.cairo +++ b/src/token/erc20/dual20.cairo @@ -11,44 +11,44 @@ use starknet::SyscallResultTrait; use starknet::call_contract_syscall; #[derive(Copy, Drop)] -struct DualERC20 { +struct DualCaseERC20 { contract_address: ContractAddress } -trait DualERC20Trait { - fn name(self: @DualERC20) -> felt252; - fn symbol(self: @DualERC20) -> felt252; - fn decimals(self: @DualERC20) -> u8; - fn total_supply(self: @DualERC20) -> u256; - fn balance_of(self: @DualERC20, account: ContractAddress) -> u256; - fn allowance(self: @DualERC20, owner: ContractAddress, spender: ContractAddress) -> u256; - fn transfer(self: @DualERC20, recipient: ContractAddress, amount: u256) -> bool; +trait DualCaseERC20Trait { + fn name(self: @DualCaseERC20) -> felt252; + fn symbol(self: @DualCaseERC20) -> felt252; + fn decimals(self: @DualCaseERC20) -> u8; + fn total_supply(self: @DualCaseERC20) -> u256; + fn balance_of(self: @DualCaseERC20, account: ContractAddress) -> u256; + fn allowance(self: @DualCaseERC20, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(self: @DualCaseERC20, recipient: ContractAddress, amount: u256) -> bool; fn transfer_from( - self: @DualERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256 + self: @DualCaseERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256 ) -> bool; - fn approve(self: @DualERC20, spender: ContractAddress, amount: u256) -> bool; + fn approve(self: @DualCaseERC20, spender: ContractAddress, amount: u256) -> bool; } -impl DualERC20Impl of DualERC20Trait { - fn name(self: @DualERC20) -> felt252 { +impl DualCaseERC20Impl of DualCaseERC20Trait { + fn name(self: @DualCaseERC20) -> felt252 { let args = array![]; call_contract_syscall(*self.contract_address, selectors::name, args.span()) .unwrap_and_cast() } - fn symbol(self: @DualERC20) -> felt252 { + fn symbol(self: @DualCaseERC20) -> felt252 { let args = array![]; call_contract_syscall(*self.contract_address, selectors::symbol, args.span()) .unwrap_and_cast() } - fn decimals(self: @DualERC20) -> u8 { + fn decimals(self: @DualCaseERC20) -> u8 { let args = array![]; call_contract_syscall(*self.contract_address, selectors::decimals, args.span()) .unwrap_and_cast() } - fn total_supply(self: @DualERC20) -> u256 { + fn total_supply(self: @DualCaseERC20) -> u256 { let mut args = array![]; try_selector_with_fallback( *self.contract_address, selectors::total_supply, selectors::totalSupply, args.span() @@ -56,7 +56,7 @@ impl DualERC20Impl of DualERC20Trait { .unwrap_and_cast() } - fn balance_of(self: @DualERC20, account: ContractAddress) -> u256 { + fn balance_of(self: @DualCaseERC20, account: ContractAddress) -> u256 { let mut args = array![]; args.append_serde(account); @@ -66,7 +66,7 @@ impl DualERC20Impl of DualERC20Trait { .unwrap_and_cast() } - fn allowance(self: @DualERC20, owner: ContractAddress, spender: ContractAddress) -> u256 { + fn allowance(self: @DualCaseERC20, owner: ContractAddress, spender: ContractAddress) -> u256 { let mut args = array![]; args.append_serde(owner); args.append_serde(spender); @@ -75,7 +75,7 @@ impl DualERC20Impl of DualERC20Trait { .unwrap_and_cast() } - fn transfer(self: @DualERC20, recipient: ContractAddress, amount: u256) -> bool { + fn transfer(self: @DualCaseERC20, recipient: ContractAddress, amount: u256) -> bool { let mut args = array![]; args.append_serde(recipient); args.append_serde(amount); @@ -85,7 +85,7 @@ impl DualERC20Impl of DualERC20Trait { } fn transfer_from( - self: @DualERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256 + self: @DualCaseERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256 ) -> bool { let mut args = array![]; args.append_serde(sender); @@ -98,7 +98,7 @@ impl DualERC20Impl of DualERC20Trait { .unwrap_and_cast() } - fn approve(self: @DualERC20, spender: ContractAddress, amount: u256) -> bool { + fn approve(self: @DualCaseERC20, spender: ContractAddress, amount: u256) -> bool { let mut args = array![]; args.append_serde(spender); args.append_serde(amount); From fcdd6d1b02306f18f1089656f15b87d1701ffde3 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 14 Sep 2023 07:08:21 +0200 Subject: [PATCH 093/124] feat: add Errors modules (#691) --- src/access/accesscontrol/accesscontrol.cairo | 9 +++- src/access/ownable/ownable.cairo | 12 +++-- src/account/account.cairo | 15 ++++-- src/introspection/src5.cairo | 6 ++- src/security/initializable.cairo | 6 ++- src/security/pausable.cairo | 11 ++++- src/security/reentrancyguard.cairo | 6 ++- src/token/erc20/erc20.cairo | 21 ++++++--- src/token/erc721/erc721.cairo | 49 ++++++++++++-------- 9 files changed, 96 insertions(+), 39 deletions(-) diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index 718137ecf..90dfe421c 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -58,6 +58,11 @@ mod AccessControl { new_admin_role: felt252 } + mod Errors { + const INVALID_CALLER: felt252 = 'Can only renounce role for self'; + const MISSING_ROLE: felt252 = 'Caller is missing role'; + } + #[external(v0)] impl SRC5Impl of ISRC5 { fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { @@ -98,7 +103,7 @@ mod AccessControl { fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { let caller: ContractAddress = get_caller_address(); - assert(caller == account, 'Can only renounce role for self'); + assert(caller == account, Errors::INVALID_CALLER); self._revoke_role(role, account); } } @@ -140,7 +145,7 @@ mod AccessControl { fn assert_only_role(self: @ContractState, role: felt252) { let caller: ContractAddress = get_caller_address(); let authorized: bool = AccessControlImpl::has_role(self, role, caller); - assert(authorized, 'Caller is missing role'); + assert(authorized, Errors::MISSING_ROLE); } fn _grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index b249d7528..ee621afa4 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -25,6 +25,12 @@ mod Ownable { new_owner: ContractAddress, } + mod Errors { + const NOT_OWNER: felt252 = 'Caller is not the owner'; + const ZERO_ADDRESS_CALLER: felt252 = 'Caller is the zero address'; + const ZERO_ADDRESS_OWNER: felt252 = 'New owner is the zero address'; + } + #[generate_trait] impl InternalImpl of InternalTrait { fn initializer(ref self: ContractState, owner: ContractAddress) { @@ -34,8 +40,8 @@ mod Ownable { fn assert_only_owner(self: @ContractState) { let owner: ContractAddress = self._owner.read(); let caller: ContractAddress = get_caller_address(); - assert(!caller.is_zero(), 'Caller is the zero address'); - assert(caller == owner, 'Caller is not the owner'); + assert(!caller.is_zero(), Errors::ZERO_ADDRESS_CALLER); + assert(caller == owner, Errors::NOT_OWNER); } fn _transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { @@ -55,7 +61,7 @@ mod Ownable { } fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { - assert(!new_owner.is_zero(), 'New owner is the zero address'); + assert(!new_owner.is_zero(), Errors::ZERO_ADDRESS_OWNER); self.assert_only_owner(); self._transfer_ownership(new_owner); } diff --git a/src/account/account.cairo b/src/account/account.cairo index 3bda0e34a..ce2eb8c2f 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -66,6 +66,13 @@ mod Account { removed_owner_guid: felt252 } + mod Errors { + const INVALID_CALLER: felt252 = 'Account: invalid caller'; + const INVALID_SIGNATURE: felt252 = 'Account: invalid signature'; + const INVALID_TX_VERSION: felt252 = 'Account: invalid tx version'; + const UNAUTHORIZED: felt252 = 'Account: unauthorized'; + } + #[constructor] fn constructor(ref self: ContractState, _public_key: felt252) { self.initializer(_public_key); @@ -81,13 +88,13 @@ mod Account { // Avoid calls from other contracts // https://github.com/OpenZeppelin/cairo-contracts/issues/344 let sender = get_caller_address(); - assert(sender.is_zero(), 'Account: invalid caller'); + assert(sender.is_zero(), Errors::INVALID_CALLER); // Check tx version let tx_info = get_tx_info().unbox(); let version = tx_info.version; if version != TRANSACTION_VERSION { - assert(version == QUERY_VERSION, 'Account: invalid tx version'); + assert(version == QUERY_VERSION, Errors::INVALID_TX_VERSION); } _execute_calls(calls) @@ -190,7 +197,7 @@ mod Account { let tx_info = get_tx_info().unbox(); let tx_hash = tx_info.transaction_hash; let signature = tx_info.signature; - assert(self._is_valid_signature(tx_hash, signature), 'Account: invalid signature'); + assert(self._is_valid_signature(tx_hash, signature), Errors::INVALID_SIGNATURE); starknet::VALIDATED } @@ -218,7 +225,7 @@ mod Account { fn assert_only_self() { let caller = get_caller_address(); let self = get_contract_address(); - assert(self == caller, 'Account: unauthorized'); + assert(self == caller, Errors::UNAUTHORIZED); } #[internal] diff --git a/src/introspection/src5.cairo b/src/introspection/src5.cairo index 75ad1d3b2..51a4e6720 100644 --- a/src/introspection/src5.cairo +++ b/src/introspection/src5.cairo @@ -10,6 +10,10 @@ mod SRC5 { supported_interfaces: LegacyMap } + mod Errors { + const INVALID_ID: felt252 = 'SRC5: invalid id'; + } + #[external(v0)] impl SRC5Impl of interface::ISRC5 { fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { @@ -34,7 +38,7 @@ mod SRC5 { } fn deregister_interface(ref self: ContractState, interface_id: felt252) { - assert(interface_id != interface::ISRC5_ID, 'SRC5: invalid id'); + assert(interface_id != interface::ISRC5_ID, Errors::INVALID_ID); self.supported_interfaces.write(interface_id, false); } } diff --git a/src/security/initializable.cairo b/src/security/initializable.cairo index e0e7e658f..934813276 100644 --- a/src/security/initializable.cairo +++ b/src/security/initializable.cairo @@ -8,6 +8,10 @@ mod Initializable { initialized: bool } + mod Errors { + const INITIALIZED: felt252 = 'Initializable: is initialized'; + } + #[generate_trait] impl InternalImpl of InternalTrait { fn is_initialized(self: @ContractState) -> bool { @@ -15,7 +19,7 @@ mod Initializable { } fn initialize(ref self: ContractState) { - assert(!self.is_initialized(), 'Initializable: is initialized'); + assert(!self.is_initialized(), Errors::INITIALIZED); self.initialized.write(true); } } diff --git a/src/security/pausable.cairo b/src/security/pausable.cairo index 73480add7..7441891a8 100644 --- a/src/security/pausable.cairo +++ b/src/security/pausable.cairo @@ -22,15 +22,22 @@ mod Pausable { Paused: Paused, Unpaused: Unpaused, } + #[derive(Drop, starknet::Event)] struct Paused { account: ContractAddress } + #[derive(Drop, starknet::Event)] struct Unpaused { account: ContractAddress } + mod Errors { + const PAUSED: felt252 = 'Pausable: paused'; + const NOT_PAUSED: felt252 = 'Pausable: not paused'; + } + #[external(v0)] impl PausableImpl of super::IPausable { fn is_paused(self: @ContractState) -> bool { @@ -41,11 +48,11 @@ mod Pausable { #[generate_trait] impl InternalImpl of InternalTrait { fn assert_not_paused(self: @ContractState) { - assert(!self.paused.read(), 'Pausable: paused'); + assert(!self.paused.read(), Errors::PAUSED); } fn assert_paused(self: @ContractState) { - assert(self.paused.read(), 'Pausable: not paused'); + assert(self.paused.read(), Errors::NOT_PAUSED); } fn _pause(ref self: ContractState) { diff --git a/src/security/reentrancyguard.cairo b/src/security/reentrancyguard.cairo index f08713776..d6a218c62 100644 --- a/src/security/reentrancyguard.cairo +++ b/src/security/reentrancyguard.cairo @@ -10,10 +10,14 @@ mod ReentrancyGuard { entered: bool } + mod Errors { + const REENTRANT_CALL: felt252 = 'ReentrancyGuard: reentrant call'; + } + #[generate_trait] impl InternalImpl of InternalTrait { fn start(ref self: ContractState) { - assert(!self.entered.read(), 'ReentrancyGuard: reentrant call'); + assert(!self.entered.read(), Errors::REENTRANT_CALL); self.entered.write(true); } diff --git a/src/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo index 9448b8ef3..df5d1fd25 100644 --- a/src/token/erc20/erc20.cairo +++ b/src/token/erc20/erc20.cairo @@ -40,6 +40,15 @@ mod ERC20 { value: u256 } + mod Errors { + const APPROVE_FROM_ZERO: felt252 = 'ERC20: approve from 0'; + const APPROVE_TO_ZERO: felt252 = 'ERC20: approve to 0'; + const TRANSFER_FROM_ZERO: felt252 = 'ERC20: transfer from 0'; + const TRANSFER_TO_ZERO: felt252 = 'ERC20: transfer to 0'; + const BURN_FROM_ZERO: felt252 = 'ERC20: burn from 0'; + const MINT_TO_ZERO: felt252 = 'ERC20: mint to 0'; + } + #[constructor] fn constructor( ref self: ContractState, @@ -188,14 +197,14 @@ mod ERC20 { } fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { - assert(!recipient.is_zero(), 'ERC20: mint to 0'); + assert(!recipient.is_zero(), Errors::MINT_TO_ZERO); self._total_supply.write(self._total_supply.read() + amount); self._balances.write(recipient, self._balances.read(recipient) + amount); self.emit(Transfer { from: Zeroable::zero(), to: recipient, value: amount }); } fn _burn(ref self: ContractState, account: ContractAddress, amount: u256) { - assert(!account.is_zero(), 'ERC20: burn from 0'); + assert(!account.is_zero(), Errors::BURN_FROM_ZERO); self._total_supply.write(self._total_supply.read() - amount); self._balances.write(account, self._balances.read(account) - amount); self.emit(Transfer { from: account, to: Zeroable::zero(), value: amount }); @@ -204,8 +213,8 @@ mod ERC20 { fn _approve( ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256 ) { - assert(!owner.is_zero(), 'ERC20: approve from 0'); - assert(!spender.is_zero(), 'ERC20: approve to 0'); + assert(!owner.is_zero(), Errors::APPROVE_FROM_ZERO); + assert(!spender.is_zero(), Errors::APPROVE_TO_ZERO); self._allowances.write((owner, spender), amount); self.emit(Approval { owner, spender, value: amount }); } @@ -216,8 +225,8 @@ mod ERC20 { recipient: ContractAddress, amount: u256 ) { - assert(!sender.is_zero(), 'ERC20: transfer from 0'); - assert(!recipient.is_zero(), 'ERC20: transfer to 0'); + assert(!sender.is_zero(), Errors::TRANSFER_FROM_ZERO); + assert(!recipient.is_zero(), Errors::TRANSFER_TO_ZERO); self._balances.write(sender, self._balances.read(sender) - amount); self._balances.write(recipient, self._balances.read(recipient) + amount); self.emit(Transfer { from: sender, to: recipient, value: amount }); diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index 0abffb4d1..559b57c9c 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -60,6 +60,19 @@ mod ERC721 { approved: bool } + mod Errors { + const INVALID_TOKEN_ID: felt252 = 'ERC721: invalid token ID'; + const INVALID_ACCOUNT: felt252 = 'ERC721: invalid account'; + const UNAUTHORIZED: felt252 = 'ERC721: unauthorized caller'; + const APPROVAL_TO_OWNER: felt252 = 'ERC721: approval to owner'; + const SELF_APPROVAL: felt252 = 'ERC721: self approval'; + const INVALID_RECEIVER: felt252 = 'ERC721: invalid receiver'; + const ALREADY_MINTED: felt252 = 'ERC721: token already minted'; + const WRONG_SENDER: felt252 = 'ERC721: wrong sender'; + const SAFE_MINT_FAILED: felt252 = 'ERC721: safe mint failed'; + const SAFE_TRANSFER_FAILED: felt252 = 'ERC721: safe transfer failed'; + } + #[constructor] fn constructor( ref self: ContractState, @@ -103,7 +116,7 @@ mod ERC721 { } fn token_uri(self: @ContractState, token_id: u256) -> felt252 { - assert(self._exists(token_id), 'ERC721: invalid token ID'); + assert(self._exists(token_id), Errors::INVALID_TOKEN_ID); self._token_uri.read(token_id) } } @@ -111,7 +124,7 @@ mod ERC721 { #[external(v0)] impl ERC721MetadataCamelOnlyImpl of interface::IERC721MetadataCamelOnly { fn tokenURI(self: @ContractState, tokenId: u256) -> felt252 { - assert(self._exists(tokenId), 'ERC721: invalid token ID'); + assert(self._exists(tokenId), Errors::INVALID_TOKEN_ID); self._token_uri.read(tokenId) } } @@ -119,7 +132,7 @@ mod ERC721 { #[external(v0)] impl ERC721Impl of interface::IERC721 { fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { - assert(!account.is_zero(), 'ERC721: invalid account'); + assert(!account.is_zero(), Errors::INVALID_ACCOUNT); self._balances.read(account) } @@ -128,7 +141,7 @@ mod ERC721 { } fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress { - assert(self._exists(token_id), 'ERC721: invalid token ID'); + assert(self._exists(token_id), Errors::INVALID_TOKEN_ID); self._token_approvals.read(token_id) } @@ -144,7 +157,7 @@ mod ERC721 { let caller = get_caller_address(); assert( owner == caller || ERC721Impl::is_approved_for_all(@self, owner, caller), - 'ERC721: unauthorized caller' + Errors::UNAUTHORIZED ); self._approve(to, token_id); } @@ -159,8 +172,7 @@ mod ERC721 { ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 ) { assert( - self._is_approved_or_owner(get_caller_address(), token_id), - 'ERC721: unauthorized caller' + self._is_approved_or_owner(get_caller_address(), token_id), Errors::UNAUTHORIZED ); self._transfer(from, to, token_id); } @@ -173,8 +185,7 @@ mod ERC721 { data: Span ) { assert( - self._is_approved_or_owner(get_caller_address(), token_id), - 'ERC721: unauthorized caller' + self._is_approved_or_owner(get_caller_address(), token_id), Errors::UNAUTHORIZED ); self._safe_transfer(from, to, token_id, data); } @@ -242,7 +253,7 @@ mod ERC721 { let owner = self._owners.read(token_id); match owner.is_zero() { bool::False(()) => owner, - bool::True(()) => panic_with_felt252('ERC721: invalid token ID') + bool::True(()) => panic_with_felt252(Errors::INVALID_TOKEN_ID) } } @@ -262,7 +273,7 @@ mod ERC721 { fn _approve(ref self: ContractState, to: ContractAddress, token_id: u256) { let owner = self._owner_of(token_id); - assert(owner != to, 'ERC721: approval to owner'); + assert(owner != to, Errors::APPROVAL_TO_OWNER); self._token_approvals.write(token_id, to); self.emit(Approval { owner, approved: to, token_id }); @@ -274,14 +285,14 @@ mod ERC721 { operator: ContractAddress, approved: bool ) { - assert(owner != operator, 'ERC721: self approval'); + assert(owner != operator, Errors::SELF_APPROVAL); self._operator_approvals.write((owner, operator), approved); self.emit(ApprovalForAll { owner, operator, approved }); } fn _mint(ref self: ContractState, to: ContractAddress, token_id: u256) { - assert(!to.is_zero(), 'ERC721: invalid receiver'); - assert(!self._exists(token_id), 'ERC721: token already minted'); + assert(!to.is_zero(), Errors::INVALID_RECEIVER); + assert(!self._exists(token_id), Errors::ALREADY_MINTED); self._balances.write(to, self._balances.read(to) + 1); self._owners.write(token_id, to); @@ -292,9 +303,9 @@ mod ERC721 { fn _transfer( ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 ) { - assert(!to.is_zero(), 'ERC721: invalid receiver'); + assert(!to.is_zero(), Errors::INVALID_RECEIVER); let owner = self._owner_of(token_id); - assert(from == owner, 'ERC721: wrong sender'); + assert(from == owner, Errors::WRONG_SENDER); // Implicit clear approvals, no need to emit an event self._token_approvals.write(token_id, Zeroable::zero()); @@ -324,7 +335,7 @@ mod ERC721 { self._mint(to, token_id); assert( _check_on_erc721_received(Zeroable::zero(), to, token_id, data), - 'ERC721: safe mint failed' + Errors::SAFE_MINT_FAILED ); } @@ -337,12 +348,12 @@ mod ERC721 { ) { self._transfer(from, to, token_id); assert( - _check_on_erc721_received(from, to, token_id, data), 'ERC721: safe transfer failed' + _check_on_erc721_received(from, to, token_id, data), Errors::SAFE_TRANSFER_FAILED ); } fn _set_token_uri(ref self: ContractState, token_id: u256, token_uri: felt252) { - assert(self._exists(token_id), 'ERC721: invalid token ID'); + assert(self._exists(token_id), Errors::INVALID_TOKEN_ID); self._token_uri.write(token_id, token_uri) } } From 7373daa47cb0442be59e723cf58784e4527b4e90 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 15 Sep 2023 20:55:21 +0200 Subject: [PATCH 094/124] Update account docs (#709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: update format and add api * fix: typo * feat: add counterfactual deployment doc * feat: add API entries * feat: add events * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Andrew Fleming * feat: update from reviews * feat: apply review updates * feat: update docs * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: apply review updates * fix: account casing * feat: add headers * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: add link * feat: move API * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * refactor: update wording * Update docs/antora.yml Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: apply update reviews * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * refactor: UI * fix: UI * feat: focus on SRC6 * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * feat: apply review updates --------- Co-authored-by: Andrew Fleming Co-authored-by: Martín Triay --- docs/antora.yml | 3 + docs/modules/ROOT/nav.adoc | 5 +- docs/modules/ROOT/pages/accounts.adoc | 655 ++---------------- docs/modules/ROOT/pages/api/account.adoc | 246 +++++++ .../modules/ROOT/pages/guides/deployment.adoc | 42 ++ src/account/account.cairo | 4 +- 6 files changed, 359 insertions(+), 596 deletions(-) create mode 100644 docs/modules/ROOT/pages/api/account.adoc create mode 100644 docs/modules/ROOT/pages/guides/deployment.adoc diff --git a/docs/antora.yml b/docs/antora.yml index ceea1e622..011b0fdf6 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -3,3 +3,6 @@ title: Contracts for Cairo version: 0.7.0 nav: - modules/ROOT/nav.adoc +asciidoc: + attributes: + page-sidebar-collapse-default: true diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 3c84b7d03..d78f8a2bd 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -4,6 +4,9 @@ * xref:proxies.adoc[Proxies and Upgrades] * xref:accounts.adoc[Accounts] +** xref:/guides/deployment.adoc[Counterfactual deployments] +** xref:/api/account.adoc[API Reference] + * xref:access.adoc[Access Control] * Tokens @@ -16,4 +19,4 @@ * xref:udc.adoc[Universal Deployer Contract] * xref:utilities.adoc[Utilities] -* xref:contracts::index.adoc[Contracts for Solidity] \ No newline at end of file +* xref:contracts::index.adoc[Contracts for Solidity] diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 55cbbc5e4..101f71f9c 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -1,632 +1,101 @@ :test-signers: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/tests/signers.py +:snip-5: https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md +:snip-6: https://github.com/ericnordelo/SNIPs/blob/feat/standard-account/SNIPS/snip-6.md +:counterfactual: xref:/guides/deployment.adoc[Counterfactual Deployments] = Accounts -Unlike Ethereum where accounts are directly derived from a private key, there's no native account concept on StarkNet. +Unlike Ethereum where accounts are derived from a private key, all Starknet accounts are contracts. This means there's no Externally Owned Account (EOA) +concept on Starknet. -Instead, signature validation has to be done at the contract level. -To relieve smart contract applications such as ERC20 tokens or exchanges from this responsibility, we make use of Account contracts to deal with transaction authentication. +Instead, the network features native account abstraction and signature validation happens at the contract level. -For a general overview of the account abstraction, see StarkWare's https://medium.com/starkware/starknet-alpha-0-10-0-923007290470[StarkNet Alpha 0.10]. -A more detailed discussion on the topic can be found in https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[StarkNet Account Abstraction Part 1]. +For a general overview of account abstraction, see +https://docs.starknet.io/documentation/architecture_and_concepts/Accounts/introduction/[Starknet's documentation]. +A more detailed discussion on the topic can be found in +https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[Starknet Shaman's forum]. -== Table of Contents +TIP: For detailed information on the usage and implementation check the xref:/api/account.adoc[API Reference] section. -* <> -* <> - ** <> -* <> -* <> -** <> - ** <> - ** <> - ** <> -* <> - ** <> - ** <> -* <> -* <> - ** <> - ** <> - ** <> - ** <> - ** <> - ** <> - ** <> - ** <> - ** <> -* <> - ** <> - ** <> -* <> -* <> -* <> -* <> +== Standard Account Interface -== Quickstart +Accounts in Starknet are smart contracts, and so they can be deployed and interacted +with like any other contract, and can be extended to implement any custom logic. However, an account is a special type +of contract that is used to validate and execute transactions. For this reason, it must implement a set of entrypoints +that the protocol uses for this execution flow. The {snip-6}[SNIP-6] proposal defines a standard interface for accounts, +supporting this execution flow and interoperability with DApps in the ecosystem. -The general workflow is: +=== ISRC6 Interface -. Account contract is deployed to StarkNet. -. Signed transactions can now be sent to the Account contract which validates and executes them. - -In Python, this would look as follows: - -[,python] ----- -from starkware.starknet.testing.starknet import Starknet -from utils import get_contract_class -from signers import MockSigner - -signer = MockSigner(123456789987654321) - -starknet = await Starknet.empty() - -# 1. Deploy Account -account = await starknet.deploy( - get_contract_class("Account"), - constructor_calldata=[signer.public_key] -) - -# 2. Send transaction through Account -await signer.send_transaction(account, some_contract_address, 'some_function', [some_parameter]) ----- - -== Account entrypoints - -Account contracts have only three entry points for all user interactions: - -1. <> validates the declaration signature prior to the declaration. -As of Cairo v0.10.0, contract classes should be declared from an Account contract. - -2. <> verifies the transaction signature before executing the transaction with `\\__execute__`. - -3. <> acts as the state-changing entry point for all user interaction with any contract, including managing the account contract itself. -That's why if you want to change the public key controlling the Account, you would send a transaction targeting the very Account contract: - -[,python] ----- -await signer.send_transaction( - account, - account.contract_address, - 'set_public_key', - [NEW_KEY] -) ----- - -Or if you want to update the Account's L1 address on the `AccountRegistry` contract, you would - -[,python] ----- -await signer.send_transaction(account, registry.contract_address, 'set_L1_address', [NEW_ADDRESS]) ----- - -NOTE: You can read more about how messages are structured and hashed in the https://github.com/OpenZeppelin/cairo-contracts/discussions/24[Account message scheme discussion]. -For more information on the design choices and implementation of multicall, you can read the https://github.com/OpenZeppelin/cairo-contracts/discussions/27[How should Account multicall work discussion]. - -The `\\__validate__` and `\\__execute__` methods accept the same arguments; however, `\\__execute__` returns a transaction response: - -[,cairo] ----- -func __validate__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt*) { -} - -func __execute__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* -) -> (response_len: felt, response: felt*) { -} ----- - -Where: - -* `call_array_len` is the number of calls. -* `call_array` is an array representing each `Call`. -* `calldata_len` is the number of calldata parameters. -* `calldata` is an array representing the function parameters. - -NOTE: The scheme of building multicall transactions within the `\\__execute__` method will change once StarkNet allows for pointers in struct arrays. -In which case, multiple transactions can be passed to (as opposed to built within) `\\__execute__`. - -There's a fourth canonical entrypoint for accounts, the `\\__validate_deploy__` method. It is **only callable by the protocol** during the execution of a `DeployAccount` type of transaction, but not by any other contract. This entrypoint is for counterfactual deployments. - -=== Counterfactual Deployments - -Counterfactual means something that hasn't happened. - -A deployment is said to be counterfactual when the deployed contract pays for it. It's called like this because we need to send the funds to the address before deployment. A deployment that hasn't happened. - -The steps are the following: - -1. Precompute the `address` given a `class_hash`, `salt`, and constructor `calldata`. -2. Send funds to `address`. -3. Send a `DeployAccount` type transaction. -4. The protocol will then validate with `\\__validate_deploy__`. -5. If successful, the protocol deploys the contract and the contract itself pays for the transaction. - -Since `address` will ultimately depend on the `class_hash` and `calldata`, it's safe for the protocol to validate the signature and spend the funds on that address. - -== Standard interface - -The https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/account/IAccount.cairo[`IAccount.cairo`] contract interface contains the standard account interface proposed in https://github.com/OpenZeppelin/cairo-contracts/discussions/41[#41] and adopted by OpenZeppelin and Argent. -It implements https://eips.ethereum.org/EIPS/eip-1271[EIP-1271] and it is agnostic of signature validation. Further, nonce management is handled on the protocol level. - -NOTE: `\\__validate_deploy__` is not part of the interface since it's only callable by the protocol. Also contracts don't need to implement it to be considered accounts. - -[,cairo] +[,javascript] ---- +/// Represents a call to a target contract function. struct Call { - to: felt, - selector: felt, - calldata_len: felt, - calldata: felt*, -} - -// Tmp struct introduced while we wait for Cairo to support passing `[Call]` to __execute__ -struct CallArray { - to: felt, - selector: felt, - data_offset: felt, - data_len: felt, + to: ContractAddress, + selector: felt252, + calldata: Array } +/// Standard Account Interface +trait ISRC6 { + /// Executes a transaction through the account. + fn __execute__(calls: Array) -> Array>; -@contract_interface -namespace IAccount { - func supportsInterface(interfaceId: felt) -> (success: felt) { - } - - func isValidSignature(hash: felt, signature_len: felt, signature: felt*) -> (isValid: felt) { - } - - func __validate__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) { - } - - func __validate_declare__(class_hash: felt) { - } - - func __execute__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) -> (response_len: felt, response: felt*) { - } -} - ----- - -== Keys, signatures and signers - -While the interface is agnostic of signature validation schemes, this implementation assumes there's a public-private key pair controlling the Account. -That's why the `constructor` function expects a `public_key` parameter to set it. -Since there's also a `setPublicKey()` method, accounts can be effectively transferred. + /// Asserts whether the transaction is valid to be executed. + fn __validate__(calls: Array) -> felt252; -=== Signature validation - -Signature validation occurs separately from execution as of Cairo v0.10. -Upon receiving transactions, an account contract first calls `\\__validate__`. -An account will only execute a transaction if, and only if, the signature proves valid. -This decoupling allows for a protocol-level distinction between invalid and reverted transactions. -See <>. - -=== Signer - -The signer is responsible for creating a transaction signature with the user's private key for a given transaction. -This implementation utilizes https://github.com/OpenZeppelin/nile/blob/main/src/nile/signer.py[Nile's Signer] class to create transaction signatures through the `Signer` method `sign_transaction`. - -`sign_transaction` expects the following parameters per transaction: - -* `sender` the contract address invoking the tx. -* `calls` a list containing a sublist of each call to be sent. -Each sublist must consist of: - .. `to` the address of the target contract of the message. - .. `selector` the function to be called on the target contract. - .. `calldata` the parameters for the given `selector`. -* `nonce` an unique identifier of this message to prevent transaction replays. -* `max_fee` the maximum fee a user will pay. - -Which returns: - -* `calldata` a list of arguments for each call. -* `sig_r` the transaction signature. -* `sig_s` the transaction signature. - -While the `Signer` class performs much of the work for a transaction to be sent, it neither manages nonces nor invokes the actual transaction on the Account contract. -To simplify Account management, most of this is abstracted away with `MockSigner`. - -=== MockSigner utility - -The `MockSigner` class in {test-signers}[signers.py] is used to perform transactions on a given Account, crafting the transaction and managing nonces. - -NOTE: StarkNet's testing framework does not currently support transaction invocations from account contracts. `MockSigner` therefore utilizes StarkNet's API gateway to manually execute the `InvokeFunction` for testing. - -A `MockSigner` instance exposes the following methods: - -* `send_transaction(account, to, selector_name, calldata, nonce=None, max_fee=0)` returns a link:https://docs.python.org/3/library/asyncio-future.html[future] of a signed transaction, ready to be sent. -* `send_transactions(account, calls, nonce=None, max_fee=0)` returns a future of batched signed transactions, ready to be sent. -* `declare_class(account, contract_name, nonce=None, max_fee=0)` returns a future of a declaration transaction. -* `deploy_account(state, calldata, salt=0, nonce=0, max_fee=0)`: returns a future of a counterfactual deployment. - -To use `MockSigner`, pass a private key when instantiating the class: - -[,python] ----- -from utils import MockSigner - -PRIVATE_KEY = 123456789987654321 -signer = MockSigner(PRIVATE_KEY) ----- - -Then send single transactions with the `send_transaction` method. - -[,python] ----- -await signer.send_transaction(account, contract_address, 'method_name', []) ----- - -If utilizing multicall, send multiple transactions with the `send_transactions` method. - -[,python] ----- -await signer.send_transactions( - account, - [ - (contract_address, 'method_name', [param1, param2]), - (contract_address, 'another_method', []) - ] -) ----- - -Use `declare_class` to declare a contract: - -[,python] ----- -await signer.declare_class(account, "MyToken") ----- - -And `deploy_account` to <> deploy an account: - -[,python] ----- -await signer.deploy_account(state, [signer.public_key]) ----- - - -=== MockEthSigner utility - -The `MockEthSigner` class in {test-signers}[signers.py] is used to perform transactions on a given Account with a secp256k1 curve key pair, crafting the transaction and managing nonces. -It differs from the `MockSigner` implementation by: - -* Not using the public key but its derived address instead (the last 20 bytes of the keccak256 hash of the public key and adding `0x` to the beginning). -* Signing the message with a secp256k1 curve address. - -== `Call` and `AccountCallArray` format - -The idea is for all user intent to be encoded into a `Call` representing a smart contract call. -Users can also pack multiple messages into a single transaction (creating a multicall transaction). -Cairo currently does not support arrays of structs with pointers which means the `\\__execute__` function cannot properly iterate through multiple ``Call``s. -Instead, this implementation utilizes a workaround with the `AccountCallArray` struct. -See <>. - -=== `Call` - -A single `Call` is structured as follows: - -[,cairo] ----- -struct Call { - to: felt - selector: felt - calldata_len: felt - calldata: felt* + /// Asserts whether a given signature for a given hash is valid. + fn is_valid_signature(hash: felt252, signature: Array) -> felt252; } ---- -Where: - -* `to` is the address of the target contract of the message. -* `selector` is the selector of the function to be called on the target contract. -* `calldata_len` is the number of calldata parameters. -* `calldata` is an array representing the function parameters. +{snip-6}[SNIP-6] adds the `is_valid_signature` method. This method is not used by the protocol, but it's useful for +DApps to verify the validity of signatures, supporting features like Sign In with Starknet. -=== `AccountCallArray` +SNIP-6 also defines that compliant accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as +a mechanism for detecting whether a contract is an account or not through introspection. -`AccountCallArray` is structured as: +=== ISRC5 Interface -[,cairo] +[,javascript] ---- -struct AccountCallArray { - to: felt - selector: felt - data_offset: felt - data_len: felt +/// Standard Interface Detection +trait ISRC5 { + /// Queries if a contract implements a given interface. + fn supports_interface(interface_id: felt252) -> bool; } ---- -Where: - -* `to` is the address of the target contract of the message. -* `selector` is the selector of the function to be called on the target contract. -* `data_offset` is the starting position of the calldata array that holds the ``Call``'s calldata. -* `data_len` is the number of calldata elements in the `Call`. - -== Multicall transactions - -A multicall transaction packs the `to`, `selector`, `calldata_offset`, and `calldata_len` of each call into the `AccountCallArray` struct and keeps the cumulative calldata for every call in a separate array. -The `\\__execute__` function rebuilds each message by combining the `AccountCallArray` with its calldata (demarcated by the offset and calldata length specified for that particular call). -The rebuilding logic is set in the internal `_from_call_array_to_call`. - -This is the basic flow: - -First, the user sends the messages for the transaction through a Signer instantiation which looks like this: - -[,python] ----- -await signer.send_transaction( - account, [ - (contract_address, 'contract_method', [arg_1]), - (contract_address, 'another_method', [arg_1, arg_2]) - ] -) ----- - -Then the `from_call_to_call_array` method in link:https://github.com/OpenZeppelin/nile/blob/main/src/nile/signer.py[Nile's signer] converts each call into the `AccountCallArray` format and cumulatively stores the calldata of every call into a single array. -Next, both arrays (as well as the `sender`, `nonce`, and `max_fee`) are used to create the transaction hash. -The Signer then invokes `\__execute__` with the signature and passes `AccountCallArray`, calldata, and nonce as arguments. - -Finally, the `\\__execute__` method takes the `AccountCallArray` and calldata and builds an array of ``Call``s (MultiCall). - -NOTE: Every transaction utilizes `AccountCallArray`. -A single `Call` is treated as a bundle with one message. - -== API Specification - -This in a nutshell is the Account contract public API: - -[,cairo] ----- -namespace Account { - func constructor(publicKey: felt) { - } - - func getPublicKey() -> (publicKey: felt) { - } - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } - - func setPublicKey(newPublicKey: felt) { - } - - func isValidSignature(hash: felt, signature_len: felt, signature: felt*) -> (isValid: felt) { - } - - func __validate__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) -> (response_len: felt, response: felt*) { - } - - func __validate_declare__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) -> (response_len: felt, response: felt*) { - } - - func __execute__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) -> (response_len: felt, response: felt*) { -} ----- - -=== `constructor` - -Initializes and sets the public key for the Account contract. - -Parameters: - -[,cairo] ----- -publicKey: felt ----- - -Returns: None. - -=== `getPublicKey` - -Returns the public key associated with the Account. - -Parameters: None. - -Returns: - -[,cairo] ----- -publicKey: felt ----- - -=== `supportsInterface` - -Returns `TRUE` if this contract implements the interface defined by `interfaceId`. -Account contracts now implement ERC165 through static support (see <>). - -Parameters: - -[,cairo] ----- -interfaceId: felt ----- - -Returns: - -[,cairo] ----- -success: felt ----- - -=== `setPublicKey` - -Sets the public key that will control this Account. -It can be used to rotate keys for security, change them in case of compromised keys or even transferring ownership of the account. - -Parameters: - -[,cairo] ----- -newPublicKey: felt ----- - -Returns: None. - -=== `isValidSignature` - -This function is inspired by https://eips.ethereum.org/EIPS/eip-1271[EIP-1271] and returns `TRUE` if a given signature is valid, otherwise it reverts. -In the future it will return `FALSE` if a given signature is invalid (for more info please check https://github.com/OpenZeppelin/cairo-contracts/issues/327[this issue]). - -Parameters: - -[,cairo] ----- -hash: felt -signature_len: felt -signature: felt* ----- - -Returns: - -[,cairo] ----- -isValid: felt ----- - -NOTE: It may return `FALSE` in the future if a given signature is invalid (follow the discussion on https://github.com/OpenZeppelin/cairo-contracts/issues/327[this issue]). - -=== `\\__validate__` - -Validates the transaction signature and is called prior to `\\__execute__`. - -Parameters: - -[,cairo] ----- -call_array_len: felt -call_array: AccountCallArray* -calldata_len: felt -calldata: felt* ----- - -Returns: None. - -=== `\\__validate_declare__` - -Validates the signature for declaration transactions. - -Parameters: - -[,cairo] ----- -class_hash: felt ----- - -Returns: None. - -=== `\\__validate_deploy__` - -Validates the signature for counterfactual deployment transactions. - -It takes the `class_hash` of the account being deployed along with the `salt` and `calldata`, the latter being expanded. For example if the account is deployed with calldata `[arg_1, ..., arg_n]`: - -Parameters: - -[,cairo] ----- -class_hash: felt -salt: felt -arg_1: felt -... -arg_n: felt ----- - -Returns: None. - -=== `\\__execute__` - -This is the only external entrypoint to interact with the Account contract. -It: - -. Calls the target contract with the intended function selector and calldata parameters. -. Forwards the contract call response data as return value. - -Parameters: - -[,cairo] ----- -call_array_len: felt -call_array: AccountCallArray* -calldata_len: felt -calldata: felt* ----- - -NOTE: The current signature scheme expects a 2-element array like `[sig_r, sig_s]`. - -Returns: - -[,cairo] ----- -response_len: felt -response: felt* ----- - -== Presets - -The following contract presets are ready to deploy and can be used as-is for quick prototyping and testing. -Each preset differs on the signature type being used by the Account. - -=== Account - -The https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/account/presets/Account.cairo[`Account`] preset uses StarkNet keys to validate transactions. - -=== Eth Account - -The https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/account/presets/EthAccount.cairo[`EthAccount`] preset supports Ethereum addresses, validating transactions with secp256k1 keys. - -== Account introspection with ERC165 - -Certain contracts like ERC721 or ERC1155 require a means to differentiate between account contracts and non-account contracts. -For a contract to declare itself as an account, it should implement https://eips.ethereum.org/EIPS/eip-165[ERC165] as proposed in https://github.com/OpenZeppelin/cairo-contracts/discussions/100[#100]. - -To be in compliance with ERC165 specifications, we calculate the account contract ID as the XOR of ``IAccount``'s equivalent EVM selectors (not StarkNet selectors). -This magic value has been tracking the changes of the still evolving Account interface standard, and **its current value is `0xa66bd575`**. - -Our ERC165 integration on StarkNet is inspired by OpenZeppelin's Solidity implementation of https://docs.openzeppelin.com/contracts/4.x/api/utils#ERC165Storage[ERC165Storage] which stores the interfaces that the implementing contract supports. -In the case of account contracts, querying `supportsInterface` of an account's address with the `IAccount` magic value should return `TRUE`. - -NOTE: For Account contracts, ERC165 support is static and does not require Account contracts to register. - -== Extending the Account contract +{snip-6}[SNIP-6] compliant accounts must return `true` when queried for the ISRC6 interface Id. -Account contracts can be extended by following the xref:extensibility.adoc#the_pattern[extensibility pattern]. +Even though these interfaces are not enforced by the protocol, it's recommended to implement them for enabling +interoperability with the ecosystem. -To implement custom account contracts, it's required by the StarkNet compiler that they include the three entrypoint functions `\\__validate__`, `\\__validate_declare__`, and `\\__execute__`. -`\\__validate__` and `\\__validate_declare__` should include the same signature validation method; whereas, `\\__execute__` should only handle the actual transaction. Incorporating a new validation scheme necessitates only that it's invoked by both `\\__validate__` and `\\__validate_declare__`. +== Protocol-level methods -This is why the Account library comes with different flavors of signature validation methods like `is_valid_eth_signature` and the vanilla `is_valid_signature`. +In this section we will describe the methods that the protocol uses for abstracting the accounts. The first two +are required for enabling accounts to be used for executing transactions. The rest are optional: -Account contract developers are encouraged to implement the https://github.com/OpenZeppelin/cairo-contracts/discussions/41[standard Account interface] and incorporate the custom logic thereafter. +1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, +but the entrypoint implementation can be customized to feature any validation mechanism https://docs.starknet.io/documentation/architecture_and_concepts/Accounts/validate_and_execute/#validate_limitations[with some limitations]. -IMPORTANT: Due to current inconsistencies between the testing framework and the actual StarkNet network, extreme caution should be used when integrating new Account contracts. -Instances have occurred where account functionality tests pass and transactions execute correctly on the local node; yet, they fail on public networks. -For this reason, it's highly encouraged that new account contracts are also deployed and tested on the public testnet. -See https://github.com/OpenZeppelin/cairo-contracts/issues/386[issue #386] for more information. +2. `\\__execute__` executes the transaction if the validation is successful. -Some other validation schemes to look out for in the future: +3. `\\__validate_declare__` optional entrypoint similar to `\\__validate__` but for transactions +meant to declare other contracts. -* Multisig. -* Guardian logic like in https://github.com/argentlabs/argent-contracts-starknet/blob/de5654555309fa76160ba3d7393d32d2b12e7349/contracts/ArgentAccount.cairo[Argent's account]. +4. `\\__validate_deploy__` optional entrypoint similar to `\\__validate__` but meant for {counterfactual}. -== L1 escape hatch mechanism +NOTE: Although these entrypoints are available to the protocol for its regular transaction flow, they can also be called like any other method. -[unknown, to be defined] +== Deploying an account -== Paying for gas +In Starknet there are two ways of deploying smart contracts: using the `deploy_syscall` and doing +counterfactual deployments. +The former can be easily done with the xref:udc.adoc[Universal Deployer Contract (UDC)], a contract that +wraps and exposes the `deploy_syscall` to provide arbitrary deployments through regular contract calls. +But if you don't have an account to invoke it, you will probably want to use the latter. -[unknown, to be defined] +To do counterfactual deployments, you need to implement another protocol-level entrypoint named +`\\__validate_deploy__`. You can check the {counterfactual} guide to learn how. diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc new file mode 100644 index 000000000..52ed25191 --- /dev/null +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -0,0 +1,246 @@ +:github-icon: pass:[] +:snip6: https://github.com/ericnordelo/SNIPs/blob/feat/standard-account/SNIPS/snip-6.md[SNIP-6] + += Account + +Reference of interfaces, presets, and utilities related to account contracts. + +== Core + +[.contract] +[[ISRC6]] +=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/account/interface.cairo#L12[{github-icon},role=heading-link] + +```javascript +use openzeppelin::account::interface::ISRC6; +``` + +Interface of the SRC6 Standard Account as defined in the {snip6}. + +[.contract-index] +.Functions +-- +* xref:#ISRC6-\\__execute__[`++__execute__(calls)++`] +* xref:#ISRC6-\\__validate__[`++__validate__(calls)++`] +* xref:#ISRC6-is_valid_signature[`++is_valid_signature(hash, signature)++`] +-- + +[#ISRC6-Functions] +==== Functions + +[.contract-item] +[[ISRC6-__execute__]] +==== `[.contract-item-name]#++__execute__++#++(calls: Array) → Array>++` [.item-kind]#external# + +Executes the list of calls as a transaction after validation. + +Returns an array with each call's output. + +NOTE: The `Call` struct is defined in https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/account.cairo#L3[corelib]. + +[.contract-item] +[[ISRC6-__validate__]] +==== `[.contract-item-name]#++__validate__++#++(calls: Array) → felt252++` [.item-kind]#external# + +Validates a transaction before execution. + +Returns the short string `'VALID'` if valid, otherwise it reverts. + +[.contract-item] +[[ISRC6-is_valid_signature]] +==== `[.contract-item-name]#++is_valid_signature++#++(hash: felt252, signature: Array) → felt252++` [.item-kind]#external# + +Validates whether a signature is valid or not for the given message hash. + +Returns the short string `'VALID'` if valid, otherwise it reverts. + +[.contract] +[[Account]] +=== `++Account++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/account/account.cairo#L27[{github-icon},role=heading-link] + +:OwnerAdded: xref:Account-OwnerAdded[OwnerAdded] +:OwnerRemoved: xref:Account-OwnerRemoved[OwnerRemoved] + +```javascript +use openzeppelin::account::Account; +``` +Account contract implementation extending xref:ISRC6[`ISRC6`]. + +[.contract-index] +.Utilities +-- +* xref:#Account-assert_only_self[`++InternalImpl::assert_only_self(self)++`] +-- + +[.contract-index] +.External Functions +-- +* xref:#Account-\\__validate_deploy__[`++__validate_deploy__(self, hash, signature)++`] + +[.contract-subindex-inherited] +.SRC6Impl + +* xref:#Account-\\__execute__[`++__execute__(self, calls)++`] +* xref:#Account-\\__validate__[`++__validate__(self, calls)++`] +* xref:#Account-is_valid_signature[`++is_valid_signature(self, hash, signature)++`] + +[.contract-subindex-inherited] +.SRC5Impl + +* xref:#Account-supports_interface[`++supports_interface(self, interface_id)++`] + +[.contract-subindex-inherited] +.DeclarerImpl + +* xref:#Account-\\__validate_declare__[`++__validate_declare__(self, class_hash)++`] + +[.contract-subindex-inherited] +.PublicKeyImpl + +* xref:#Account-set_public_key[`++set_public_key(self, new_public_key)++`] +* xref:#Account-get_public_key[`++get_public_key(self)++`] +-- + +[.contract-index] +.Internal Functions +-- +* xref:#Account-constructor[`++constructor(self, _public_key)++`] + +[.contract-subindex-inherited] +.InternalImpl + +* xref:#Account-initializer[`++initializer(self, _public_key)++`] +* xref:#Account-validate_transaction[`++validate_transaction(self)++`] +* xref:#Account-_set_public_key[`++_set_public_key(self, new_public_key)++`] +* xref:#Account-_is_valid_signature[`++_is_valid_signature(self, hash, signature)++`] +-- + +[.contract-index] +.Events +-- +* xref:#Account-OwnerAdded[`++OwnerAdded(new_owner_guid)++`] +* xref:#Account-OwnerRemoved[`++OwnerRemoved(removed_owner_guid)++`] +-- + +[#Account-Utilities] +==== Utilities + +[.contract-item] +[[Account-assert_only_self]] +==== `[.contract-item-name]#++assert_only_self++#++(self: @ContractState)++` [.item-kind]#internal# + +Validates that the caller is the account itself. Otherwise it reverts. + +[#Account-Functions] +==== Functions + +[.contract-item] +[[Account-constructor]] +==== `[.contract-item-name]#++constructor++#++(ref self: ContractState, _public_key: felt252)++` [.item-kind]#constructor# + +Initializes the account with the given public key, and registers the ISRC6 interface ID. + +Emits an {OwnerAdded} event. + +[.contract-item] +[[Account-__validate_deploy__]] +==== `[.contract-item-name]#++__validate_deploy__++#++(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, _public_key: felt252) → felt252++` [.item-kind]#external# + +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#deploy_account_transaction[`DeployAccount` transaction]. +See xref:/guides/deployment.adoc[Counterfactual Deployments]. + +Returns the short string `'VALID'` if valid, otherwise it reverts. + +[.contract-item] +[[Account-__execute__]] +==== `[.contract-item-name]#++__execute__++#++(ref self: ContractState, calls: Array) → Array>++` [.item-kind]#external# + +See xref:ISRC6-\\__execute__[ISRC6::\\__execute__]. + +[.contract-item] +[[Account-__validate__]] +==== `[.contract-item-name]#++__validate__++#++(self: @ContractState, calls: Array) → felt252++` [.item-kind]#external# + +See xref:ISRC6-\\__validate__[ISRC6::\\__validate__]. + +[.contract-item] +[[Account-is_valid_signature]] +==== `[.contract-item-name]#++is_valid_signature++#++(self: @ContractState, hash: felt252, signature: Array) → felt252++` [.item-kind]#external# + +See xref:ISRC6-is_valid_signature[ISRC6::is_valid_signature]. + +[.contract-item] +[[Account-supports_interface]] +==== `[.contract-item-name]#++supports_interface++#++(self: @ContractState, interface_id: felt252) → bool++` [.item-kind]#external# + +Returns whether a contract implements a given interface or not. + +[.contract-item] +[[Account-__validate_declare__]] +==== `[.contract-item-name]#++__validate_declare__++#++(self: @ContractState, class_hash: felt252) → felt252++` [.item-kind]#external# + +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#declare-transaction[`Declare` transaction]. + +Returns the short string `'VALID'` if valid, otherwise it reverts. + +[.contract-item] +[[Account-set_public_key]] +==== `[.contract-item-name]#++set_public_key++#++(ref self: ContractState, new_public_key: felt252)++` [.item-kind]#external# + +Sets a new public key for the account. Only accesible by the account calling itself through `\\__execute__`. + +Emits both an {OwnerRemoved} and an {OwnerAdded} event. + +[.contract-item] +[[Account-get_public_key]] +==== `[.contract-item-name]#++get_public_key++#++(self: @ContractState)++ → felt252` [.item-kind]#external# + +Returns the current public key of the account. + +[.contract-item] +[[Account-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, _public_key: felt252)++` [.item-kind]#internal# + +Initializes the account with the given public key, and registers the ISRC6 interface ID. + +Emits an {OwnerAdded} event. + +[.contract-item] +[[Account-validate_transaction]] +==== `[.contract-item-name]#++validate_transaction++#++(self: @ContractState)++ → felt252` [.item-kind]#internal# + +Validates a transaction signature from the +https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/info.cairo#L61[global context]. + +Returns the short string `'VALID'` if valid, otherwise it reverts. + +[.contract-item] +[[Account-_set_public_key]] +==== `[.contract-item-name]#++_set_public_key++#++(ref self: ContractState, new_public_key: felt252)++` [.item-kind]#internal# + +Set the public key without validating the caller. + +Emits an {OwnerAdded} event. + +CAUTION: The usage of this method outside the `set_public_key` function is discouraged. + +[.contract-item] +[[Account-_is_valid_signature]] +==== `[.contract-item-name]#++_is_valid_signature++#++(self: @ContractState, hash: felt252, signature: Span)++ → bool` [.item-kind]#internal# + +Validates the provided `signature` for the `hash`, using the account current public key. + +[#Account-Events] +==== Events + +[.contract-item] +[[Account-OwnerAdded]] +==== `[.contract-item-name]#++OwnerAdded++#++(new_owner_guid: felt252)++` [.item-kind]#event# + +Emitted when a `public_key` is added. + +[.contract-item] +[[Account-OwnerRemoved]] +==== `[.contract-item-name]#++OwnerRemoved++#++(removed_owner_guid: felt252)++` [.item-kind]#event# + +Emitted when a `public_key` is removed. diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc new file mode 100644 index 000000000..92f6a1bd2 --- /dev/null +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -0,0 +1,42 @@ +:foundry: https://foundry-rs.github.io/starknet-foundry/starknet/account.html[Starknet Foundry] +:starkli: https://book.starkli.rs/accounts#account-deployment[Starkli] + += Counterfactual deployments + +A counterfactual contract is a contract we can interact with even before actually deploying it on-chain. +For example, we can send funds or assign privileges to a contract that doesn't yet exist. +Why? Because deployments in Starknet are deterministic, allowing us to predict the address where our contract will be deployed. +We can leverage this property to make a contract pay for its own deployment by simply sending funds in advance. We call this a counterfactual deployment. + +This process can be described with the following steps: + +TIP: For testing this flow you can check the {foundry} or the {starkli} guides for deploying accounts. + +1. Deterministically precompute the `contract_address` given a `class_hash`, `salt`, and constructor `calldata`. +Note that the `class_hash` must be previously declared for the deployment to succeed. + +2. Send funds to the `contract_address`. Usually you will estimate the fee of the transaction first. Existing +tools usually do this for you. + +3. Send a `DeployAccount` type transaction to the network. + +4. The protocol will then validate the transaction with the `\\__validate_deploy__` entrypoint of the contract to be deployed. + +5. If the validation succeeds, the protocol will charge the fee and then register the contract as deployed. + +NOTE: Although this method is very popular to deploy accounts, this works for any kind of contract. + +== Deployment validation + +To be counterfactually deployed, the deploying contract must implement the `\\__validate_deploy__` entrypoint, +called by the protocol when a `DeployAccount` transaction is sent to the network. + +[,javascript] +---- +trait IDeployable { + /// Must return 'VALID' when the validation is successful. + fn __validate_deploy__( + class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + ) -> felt252; +} +---- diff --git a/src/account/account.cairo b/src/account/account.cairo index ce2eb8c2f..13b7e8d0e 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -228,7 +228,7 @@ mod Account { assert(self == caller, Errors::UNAUTHORIZED); } - #[internal] + #[private] fn _execute_calls(mut calls: Array) -> Array> { let mut res = ArrayTrait::new(); loop { @@ -245,7 +245,7 @@ mod Account { res } - #[internal] + #[private] fn _execute_single_call(call: Call) -> Span { let Call{to, selector, calldata } = call; starknet::call_contract_syscall(to, selector, calldata.span()).unwrap() From cbb5bf55631c8aafecb8bbefbf92a289e6b6bb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Wed, 20 Sep 2023 16:21:23 -0300 Subject: [PATCH 095/124] Add Interface & Dispatchers docs (#730) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: update format and add api * fix: typo * feat: add counterfactual deployment doc * feat: add API entries * feat: add events * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Andrew Fleming * feat: update from reviews * feat: apply review updates * feat: update docs * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: apply review updates * fix: account casing * feat: add headers * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: add link * feat: move API * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * refactor: update wording * Update docs/antora.yml Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: apply update reviews * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * refactor: UI * fix: UI * feat: focus on SRC6 * add interface & dispatchers docs * apply review feedback * address feedback comments --------- Co-authored-by: Eric Nordelo Co-authored-by: Andrew Fleming --- docs/modules/ROOT/nav.adoc | 25 ++-- docs/modules/ROOT/pages/interfaces.adoc | 185 ++++++++++++++++++++++++ 2 files changed, 199 insertions(+), 11 deletions(-) create mode 100644 docs/modules/ROOT/pages/interfaces.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index d78f8a2bd..380822723 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -1,7 +1,8 @@ * xref:index.adoc[Overview] -* xref:wizard.adoc[Wizard] -* xref:extensibility.adoc[Extensibility] -* xref:proxies.adoc[Proxies and Upgrades] +//* xref:wizard.adoc[Wizard] +//* xref:extensibility.adoc[Extensibility] +//* xref:proxies.adoc[Proxies and Upgrades] +* xref:interfaces.adoc[Interfaces and Dispatchers] * xref:accounts.adoc[Accounts] ** xref:/guides/deployment.adoc[Counterfactual deployments] @@ -9,14 +10,16 @@ * xref:access.adoc[Access Control] -* Tokens -** xref:erc20.adoc[ERC20] -** xref:erc721.adoc[ERC721] -** xref:erc1155.adoc[ERC1155] +//* xref:access.adoc[Access Control] -* xref:security.adoc[Security] -* xref:introspection.adoc[Introspection] -* xref:udc.adoc[Universal Deployer Contract] -* xref:utilities.adoc[Utilities] +//* Tokens +//** xref:erc20.adoc[ERC20] +//** xref:erc721.adoc[ERC721] +//** xref:erc1155.adoc[ERC1155] + +//* xref:security.adoc[Security] +//* xref:introspection.adoc[Introspection] +//* xref:udc.adoc[Universal Deployer Contract] +//* xref:utilities.adoc[Utilities] * xref:contracts::index.adoc[Contracts for Solidity] diff --git a/docs/modules/ROOT/pages/interfaces.adoc b/docs/modules/ROOT/pages/interfaces.adoc new file mode 100644 index 000000000..44125f15c --- /dev/null +++ b/docs/modules/ROOT/pages/interfaces.adoc @@ -0,0 +1,185 @@ +:great-interface-migration: link:https://community.starknet.io/t/the-great-interface-migration/92107[Great Interface Migration] + += Interfaces and Dispatchers + +This section describes the interfaces OpenZeppelin Contracts for Cairo offer, and explains the design choices behind them. + +Interfaces can be found in the module tree under the `interface` submodule, such as `token::erc20::interface`. For example: + +```javascript +use openzeppelin::token::erc20::interface::IERC20; +``` + +or + +```javascript +use openzeppelin::token::erc20::dual20::DualCaseERC20; +``` + +NOTE: For simplicity, we'll use ERC20 as example but the same concepts apply to other modules. + +== Interface traits +The library offers three types of traits to implement or interact with contracts: + +=== Standard traits + +These are associated with a predefined interface such as a standard. +This includes only the functions defined in the interface, and is the standard way to interact with a compliant contract. + +```javascript +#[starknet::interface] +trait IERC20 { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn total_supply(self: @TState) -> u256; + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; +} +``` + +=== ABI traits + +They describe a contract's complete interface. This is useful to interface with a preset contract offered by this library, such as the ERC20 preset that includes non-standard functions like `increase_allowance`. + +```javascript +#[starknet::interface] +trait ERC20ABI { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn total_supply(self: @TState) -> u256; + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; + fn increase_allowance(ref self: TState, spender: ContractAddress, added_value: u256) -> bool; + fn decrease_allowance( + ref self: TState, spender: ContractAddress, subtracted_value: u256 + ) -> bool; +} +``` + +=== Dispatcher traits +This is a utility trait to interface with contracts whose interface is unknown. Read more in the xref:#dualcase_dispatchers[DualCase Dispatchers] section. + +```javascript +#[derive(Copy, Drop)] +struct DualCaseERC20 { + contract_address: ContractAddress +} + +trait DualCaseERC20Trait { + fn name(self: @DualCaseERC20) -> felt252; + fn symbol(self: @DualCaseERC20) -> felt252; + fn decimals(self: @DualCaseERC20) -> u8; + fn total_supply(self: @DualCaseERC20) -> u256; + fn balance_of(self: @DualCaseERC20, account: ContractAddress) -> u256; + fn allowance(self: @DualCaseERC20, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(self: @DualCaseERC20, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + self: @DualCaseERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(self: @DualCaseERC20, spender: ContractAddress, amount: u256) -> bool; +} +``` + +== Dual interfaces + +Following the {great-interface-migration} plan, we added `snake_case` functions to all of our preexisting `camelCase` contracts with the goal of eventually dropping support for the latter. + +In short, we offer two types of interfaces and utilities to handle them: + +1. `camelCase` interfaces, which are the ones we've been using so far. +2. `snake_case` interfaces, which are the ones we're migrating to. + +This means that currently most of our contracts implement _dual interfaces_. For example, the ERC20 preset contract exposes `transferFrom`, `transfer_from`, `balanceOf`, `balance_of`, etc. + +NOTE: Dual interfaces are available for all external functions present in previous versions of OpenZeppelin Contracts for Cairo (https://github.com/OpenZeppelin/cairo-contracts/releases/tag/v0.6.1[v0.6.1] and below). + +=== `IERC20` + +The default version of the ERC20 interface trait exposes `snake_case` functions: + +```javascript +#[starknet::interface] +trait IERC20 { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn total_supply(self: @TState) -> u256; + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; +} +``` + +=== `IERC20Camel` + +On top of that, we also offer a `camelCase` version of the same interface: + +```javascript +#[starknet::interface] +trait IERC20Camel { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn totalSupply(self: @TState) -> u256; + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transferFrom( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; +} +``` + +== `DualCase` dispatchers + +WARNING: `DualCase` dispatchers won't work on live chains (`mainnet` or testnets) until they implement panic handling in their runtime. Dispatchers work fine in testing environments. + +In order to ease this transition, OpenZeppelin Contracts for Cairo offer what we call `DualCase` dispatchers such as `DualCaseERC721` or `DualCaseAccount`. + +These modules wrap a target contract with a compatibility layer to expose a `snake_case` interface no matter what casing the underlying contract uses. +This way, an AMM wouldn't have problems integrating tokens independently of their interface. + +For example: + +```javascript +let token = DualCaseERC20 { contract_address: target }; +token.transfer_from(OWNER(), RECIPIENT(), VALUE); +``` + +This is done by simply executing the `snake_case` version of the function (e.g. `transfer_from`) and falling back to the `camelCase` one (e.g. `transferFrom`) in case it reverts with `ENTRYPOINT_NOT_FOUND`, like this: + +```javascript +fn try_selector_with_fallback( + target: ContractAddress, snake_selector: felt252, camel_selector: felt252, args: Span +) -> SyscallResult> { + match call_contract_syscall(target, snake_selector, args) { + Result::Ok(ret) => Result::Ok(ret), + Result::Err(errors) => { + if *errors.at(0) == 'ENTRYPOINT_NOT_FOUND' { + return call_contract_syscall(target, camel_selector, args); + } else { + Result::Err(errors) + } + } + } +} +``` + +Trying the `snake_case` interface first renders `camelCase` calls a bit more expensive since a failed `snake_case` call will always happen before. This is a design choice to incentivize casing adoption/transition as per the {great-interface-migration}. From 4e388f57bb93e2be9ad7193255535c6a446a3e05 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 21 Sep 2023 00:44:38 +0200 Subject: [PATCH 096/124] Update overview docs (#735) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: update format and add api * fix: typo * feat: add counterfactual deployment doc * feat: add API entries * feat: add events * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Andrew Fleming * feat: update from reviews * feat: apply review updates * feat: update docs * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: apply review updates * fix: account casing * feat: add headers * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: add link * feat: move API * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming * refactor: update wording * Update docs/antora.yml Co-authored-by: Andrew Fleming * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: apply update reviews * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * refactor: UI * fix: UI * feat: focus on SRC6 * Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Martín Triay * feat: update overview * feat: apply review updates * Update docs/modules/ROOT/pages/index.adoc Co-authored-by: Martín Triay * feat: apply review updates * Update docs/modules/ROOT/pages/index.adoc Co-authored-by: Andrew Fleming * feat: apply review updates * Update docs/modules/ROOT/pages/index.adoc Co-authored-by: Andrew Fleming --------- Co-authored-by: Andrew Fleming Co-authored-by: Martín Triay --- docs/modules/ROOT/nav.adoc | 20 ++-- docs/modules/ROOT/pages/index.adoc | 184 +++++++++++++++++------------ 2 files changed, 118 insertions(+), 86 deletions(-) diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 380822723..961aba815 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -8,18 +8,16 @@ ** xref:/guides/deployment.adoc[Counterfactual deployments] ** xref:/api/account.adoc[API Reference] -* xref:access.adoc[Access Control] +// * xref:access.adoc[Access Control] -//* xref:access.adoc[Access Control] +// * Tokens +// ** xref:erc20.adoc[ERC20] +// ** xref:erc721.adoc[ERC721] +// ** xref:erc1155.adoc[ERC1155] -//* Tokens -//** xref:erc20.adoc[ERC20] -//** xref:erc721.adoc[ERC721] -//** xref:erc1155.adoc[ERC1155] - -//* xref:security.adoc[Security] -//* xref:introspection.adoc[Introspection] -//* xref:udc.adoc[Universal Deployer Contract] -//* xref:utilities.adoc[Utilities] +// * xref:security.adoc[Security] +// * xref:introspection.adoc[Introspection] +// * xref:udc.adoc[Universal Deployer Contract] +// * xref:utilities.adoc[Utilities] * xref:contracts::index.adoc[Contracts for Solidity] diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 648763e0c..aa01b689a 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -1,115 +1,149 @@ -= Contracts for Cairo +:starknet: https://starkware.co/product/starknet/[Starknet] +:scarb: https://docs.swmansion.com/scarb[Scarb] +:installation: https://docs.swmansion.com/scarb/download.html[this guide] -*A library for secure smart contract development* written in Cairo for https://starkware.co/product/starknet/[StarkNet], a decentralized ZK Rollup. += Contracts for Cairo -== Usage +*A library for secure smart contract development* written in Cairo for {starknet}, a decentralized ZK Rollup. WARNING: This repo contains highly experimental code. Expect rapid iteration. *Use at your own risk.* -=== First time? +== Installation -Before installing Cairo on your machine, you need to install `gmp`: +The library is available as a {scarb} package. Follow {installation} for installing Cairo and Scarb on your machine +before proceeding, and run the following command to check that the installation was successful: [,bash] ---- -sudo apt install -y libgmp3-dev # linux -brew install gmp # mac ----- +$ scarb --version -TIP: If you have any trouble installing gmp on your Apple M1 computer, https://github.com/OpenZeppelin/nile/issues/22[here's a list of potential solutions]. +scarb 0.7.0 (58cc88efb 2023-08-23) +cairo: 2.2.0 (https://crates.io/crates/cairo-lang-compiler/2.2.0) +sierra: 1.3.0 +---- === Set up your project -Create a directory for your project, then `cd` into it and create a Python virtual environment. +Create an empty directory, and `cd` into it: [,bash] ---- -mkdir my-project -cd my-project -python3 -m venv env -source env/bin/activate +mkdir my_project/ && cd my_project/ ---- -Install the https://github.com/OpenZeppelin/nile[Nile] development environment and then run `init` to kickstart a new project. -Nile will create the project directory structure and install https://www.cairo-lang.org/docs/quickstart.html[the Cairo language], a https://github.com/Shard-Labs/starknet-devnet/[local network], and a https://docs.pytest.org/en/6.2.x/[testing framework]. +Initialize a new Scarb project: [,bash] ---- -pip install cairo-nile -nile init +scarb init ---- -=== Install the library +The contents of `my_project/` should now look like this: [,bash] ---- -pip install openzeppelin-cairo-contracts ----- - -WARNING: Installing directly through GitHub may contain incomplete or breaking implementations. -While we aim not to introduce such changes, we still strongly recommend installing through https://github.com/OpenZeppelin/cairo-contracts/releases/[official releases]. - -=== Use a basic preset +$ ls -Presets are ready-to-use contracts that you can deploy right away. -They also serve as examples of how to use library modules. -xref:extensibility.adoc#presets[Read more about presets]. - -[,cairo] ----- -// contracts/MyToken.cairo - -%lang starknet - -from openzeppelin.token.erc20.presets.ERC20 import ( - constructor, - name, - symbol, - totalSupply, - decimals, - balanceOf, - allowance, - transfer, - transferFrom, - approve, - increaseAllowance, - decreaseAllowance -) +Scarb.toml src ---- -Compile and deploy it right away: +=== Install the library -[,bash] ----- -nile compile +Install the library by declaring it as a dependency in the project's `Scarb.toml` file: -nile deploy MyToken --alias my_token +[,text] +---- +[dependencies] +openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.7.0" } ---- -NOTE: `` is expected to be two integers i.e. -`1` `0`. -See xref:utilities.adoc#uint256[uint256] for more information. +WARNING: Make sure the tag matches the target release. -=== Write a custom contract using library modules +== Basic usage -xref:extensibility.adoc#libraries[Read more about libraries]. +This is how it looks to build an account contract using the xref:accounts.adoc[account module]. +Copy the code into `src/lib.cairo`. -[,cairo] +[,javascript] +---- +#[starknet::contract] +mod MyAccount { + use openzeppelin::account::Account; + use openzeppelin::account::account::PublicKeyTrait; + use openzeppelin::account::interface; + use openzeppelin::introspection::interface::ISRC5; + use starknet::account::Call; + + // Storage members used by this contract are defined in each imported + // module whose `unsafe_state` is used. This design will be improved + // with the addition of components in the future. + #[storage] + struct Storage {} + + #[constructor] + fn constructor(ref self: ContractState, public_key: felt252) { + let mut unsafe_state = _unsafe_state(); + Account::InternalImpl::initializer(ref unsafe_state, public_key); + } + + #[external(v0)] + impl SRC6Impl of interface::ISRC6 { + fn __execute__(self: @ContractState, mut calls: Array) -> Array> { + Account::SRC6Impl::__execute__(@_unsafe_state(), calls) + } + + fn __validate__(self: @ContractState, mut calls: Array) -> felt252 { + Account::SRC6Impl::__validate__(@_unsafe_state(), calls) + } + + fn is_valid_signature( + self: @ContractState, hash: felt252, signature: Array + ) -> felt252 { + Account::SRC6Impl::is_valid_signature(@_unsafe_state(), hash, signature) + } + } + + #[external(v0)] + impl SRC5Impl of ISRC5 { + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + Account::SRC5Impl::supports_interface(@_unsafe_state(), interface_id) + } + } + + #[external(v0)] + impl PublicKeyImpl of PublicKeyTrait { + fn get_public_key(self: @ContractState) -> felt252 { + Account::PublicKeyImpl::get_public_key(@_unsafe_state()) + } + + fn set_public_key(ref self: ContractState, new_public_key: felt252) { + let mut unsafe_state = _unsafe_state(); + Account::PublicKeyImpl::set_public_key(ref unsafe_state, new_public_key); + } + } + + #[external(v0)] + fn __validate_deploy__( + self: @ContractState, + class_hash: felt252, + contract_address_salt: felt252, + _public_key: felt252 + ) -> felt252 { + Account::__validate_deploy__( + @_unsafe_state(), class_hash, contract_address_salt, _public_key + ) + } + + #[inline(always)] + fn _unsafe_state() -> Account::ContractState { + Account::unsafe_new_contract_state() + } +} ---- -%lang starknet - -from starkware.cairo.common.cairo_builtins import HashBuiltin -from starkware.cairo.common.uint256 import Uint256 -from openzeppelin.security.pausable.library import Pausable -from openzeppelin.token.erc20.library import ERC20 -(...) +You can now compile it: -@external -func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - recipient: felt, amount: Uint256 -) -> (success: felt) { - Pausable.assert_not_paused(); - return ERC20.transfer(recipient, amount); -} +[,bash] ---- +scarb build +---- \ No newline at end of file From a1b559c46eaa48d855b049134fd294ce43ee44e7 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 21 Sep 2023 19:05:33 -0400 Subject: [PATCH 097/124] remove underscore from name_ and symbol_ (#738) --- src/token/erc20/erc20.cairo | 6 +++--- src/token/erc721/erc721.cairo | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo index df5d1fd25..9a97cee58 100644 --- a/src/token/erc20/erc20.cairo +++ b/src/token/erc20/erc20.cairo @@ -172,9 +172,9 @@ mod ERC20 { #[generate_trait] impl InternalImpl of InternalTrait { - fn initializer(ref self: ContractState, name_: felt252, symbol_: felt252) { - self._name.write(name_); - self._symbol.write(symbol_); + fn initializer(ref self: ContractState, name: felt252, symbol: felt252) { + self._name.write(name); + self._symbol.write(symbol); } fn _increase_allowance( diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index 559b57c9c..0373dad36 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -238,9 +238,9 @@ mod ERC721 { #[generate_trait] impl InternalImpl of InternalTrait { - fn initializer(ref self: ContractState, name_: felt252, symbol_: felt252) { - self._name.write(name_); - self._symbol.write(symbol_); + fn initializer(ref self: ContractState, name: felt252, symbol: felt252) { + self._name.write(name); + self._symbol.write(symbol); let mut unsafe_state = src5::SRC5::unsafe_new_contract_state(); src5::SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IERC721_ID); From 74eb4e86702501ba9654eaf4b4330f5737bfe207 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Tue, 26 Sep 2023 20:27:20 +0200 Subject: [PATCH 098/124] Add prefixes to storage members (#743) * feat: add prefixes * Update src/access/accesscontrol/accesscontrol.cairo Co-authored-by: Andrew Fleming --------- Co-authored-by: Andrew Fleming --- src/access/accesscontrol/accesscontrol.cairo | 14 ++--- src/access/ownable/ownable.cairo | 10 ++-- src/account/account.cairo | 12 ++-- src/introspection/src5.cairo | 8 +-- src/security/initializable.cairo | 6 +- src/security/pausable.cairo | 12 ++-- src/security/reentrancyguard.cairo | 8 +-- src/tests/access/test_ownable.cairo | 8 +-- src/tests/security/test_reentrancyguard.cairo | 10 ++-- src/tests/token/test_erc721.cairo | 14 ++--- src/token/erc20/erc20.cairo | 49 ++++++++------- src/token/erc721/erc721.cairo | 60 +++++++++---------- 12 files changed, 108 insertions(+), 103 deletions(-) diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index 90dfe421c..0f3aa7535 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -12,8 +12,8 @@ mod AccessControl { #[storage] struct Storage { - role_admin: LegacyMap, - role_members: LegacyMap<(felt252, ContractAddress), bool>, + AccessControl_role_admin: LegacyMap, + AccessControl_role_member: LegacyMap<(felt252, ContractAddress), bool>, } #[event] @@ -82,11 +82,11 @@ mod AccessControl { #[external(v0)] impl AccessControlImpl of interface::IAccessControl { fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - self.role_members.read((role, account)) + self.AccessControl_role_member.read((role, account)) } fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { - self.role_admin.read(role) + self.AccessControl_role_admin.read(role) } fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { @@ -151,7 +151,7 @@ mod AccessControl { fn _grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { if !AccessControlImpl::has_role(@self, role, account) { let caller: ContractAddress = get_caller_address(); - self.role_members.write((role, account), true); + self.AccessControl_role_member.write((role, account), true); self.emit(RoleGranted { role, account, sender: caller }); } } @@ -159,14 +159,14 @@ mod AccessControl { fn _revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { if AccessControlImpl::has_role(@self, role, account) { let caller: ContractAddress = get_caller_address(); - self.role_members.write((role, account), false); + self.AccessControl_role_member.write((role, account), false); self.emit(RoleRevoked { role, account, sender: caller }); } } fn _set_role_admin(ref self: ContractState, role: felt252, admin_role: felt252) { let previous_admin_role: felt252 = AccessControlImpl::get_role_admin(@self, role); - self.role_admin.write(role, admin_role); + self.AccessControl_role_admin.write(role, admin_role); self.emit(RoleAdminChanged { role, previous_admin_role, new_admin_role: admin_role }); } } diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index ee621afa4..856de8190 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -10,7 +10,7 @@ mod Ownable { #[storage] struct Storage { - _owner: ContractAddress + Ownable_owner: ContractAddress } #[event] @@ -38,15 +38,15 @@ mod Ownable { } fn assert_only_owner(self: @ContractState) { - let owner: ContractAddress = self._owner.read(); + let owner: ContractAddress = self.Ownable_owner.read(); let caller: ContractAddress = get_caller_address(); assert(!caller.is_zero(), Errors::ZERO_ADDRESS_CALLER); assert(caller == owner, Errors::NOT_OWNER); } fn _transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { - let previous_owner: ContractAddress = self._owner.read(); - self._owner.write(new_owner); + let previous_owner: ContractAddress = self.Ownable_owner.read(); + self.Ownable_owner.write(new_owner); self .emit( OwnershipTransferred { previous_owner: previous_owner, new_owner: new_owner } @@ -57,7 +57,7 @@ mod Ownable { #[external(v0)] impl OwnableImpl of interface::IOwnable { fn owner(self: @ContractState) -> ContractAddress { - self._owner.read() + self.Ownable_owner.read() } fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { diff --git a/src/account/account.cairo b/src/account/account.cairo index 13b7e8d0e..90408a30f 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -46,7 +46,7 @@ mod Account { #[storage] struct Storage { - public_key: felt252 + Account_public_key: felt252 } #[event] @@ -150,12 +150,12 @@ mod Account { #[external(v0)] impl PublicKeyImpl of super::PublicKeyTrait { fn get_public_key(self: @ContractState) -> felt252 { - self.public_key.read() + self.Account_public_key.read() } fn set_public_key(ref self: ContractState, new_public_key: felt252) { assert_only_self(); - self.emit(OwnerRemoved { removed_owner_guid: self.public_key.read() }); + self.emit(OwnerRemoved { removed_owner_guid: self.Account_public_key.read() }); self._set_public_key(new_public_key); } } @@ -163,7 +163,7 @@ mod Account { #[external(v0)] impl PublicKeyCamelImpl of super::PublicKeyCamelTrait { fn getPublicKey(self: @ContractState) -> felt252 { - self.public_key.read() + self.Account_public_key.read() } fn setPublicKey(ref self: ContractState, newPublicKey: felt252) { @@ -202,7 +202,7 @@ mod Account { } fn _set_public_key(ref self: ContractState, new_public_key: felt252) { - self.public_key.write(new_public_key); + self.Account_public_key.write(new_public_key); self.emit(OwnerAdded { new_owner_guid: new_public_key }); } @@ -213,7 +213,7 @@ mod Account { if valid_length { check_ecdsa_signature( - hash, self.public_key.read(), *signature.at(0_u32), *signature.at(1_u32) + hash, self.Account_public_key.read(), *signature.at(0_u32), *signature.at(1_u32) ) } else { false diff --git a/src/introspection/src5.cairo b/src/introspection/src5.cairo index 51a4e6720..3b94f4218 100644 --- a/src/introspection/src5.cairo +++ b/src/introspection/src5.cairo @@ -7,7 +7,7 @@ mod SRC5 { #[storage] struct Storage { - supported_interfaces: LegacyMap + SRC5_supported_interfaces: LegacyMap } mod Errors { @@ -20,7 +20,7 @@ mod SRC5 { if interface_id == interface::ISRC5_ID { return true; } - self.supported_interfaces.read(interface_id) + self.SRC5_supported_interfaces.read(interface_id) } } @@ -34,12 +34,12 @@ mod SRC5 { #[generate_trait] impl InternalImpl of InternalTrait { fn register_interface(ref self: ContractState, interface_id: felt252) { - self.supported_interfaces.write(interface_id, true); + self.SRC5_supported_interfaces.write(interface_id, true); } fn deregister_interface(ref self: ContractState, interface_id: felt252) { assert(interface_id != interface::ISRC5_ID, Errors::INVALID_ID); - self.supported_interfaces.write(interface_id, false); + self.SRC5_supported_interfaces.write(interface_id, false); } } } diff --git a/src/security/initializable.cairo b/src/security/initializable.cairo index 934813276..3ab4cda1f 100644 --- a/src/security/initializable.cairo +++ b/src/security/initializable.cairo @@ -5,7 +5,7 @@ mod Initializable { #[storage] struct Storage { - initialized: bool + Initializable_initialized: bool } mod Errors { @@ -15,12 +15,12 @@ mod Initializable { #[generate_trait] impl InternalImpl of InternalTrait { fn is_initialized(self: @ContractState) -> bool { - self.initialized.read() + self.Initializable_initialized.read() } fn initialize(ref self: ContractState) { assert(!self.is_initialized(), Errors::INITIALIZED); - self.initialized.write(true); + self.Initializable_initialized.write(true); } } } diff --git a/src/security/pausable.cairo b/src/security/pausable.cairo index 7441891a8..b29bbf19d 100644 --- a/src/security/pausable.cairo +++ b/src/security/pausable.cairo @@ -13,7 +13,7 @@ mod Pausable { #[storage] struct Storage { - paused: bool + Pausable_paused: bool } #[event] @@ -41,29 +41,29 @@ mod Pausable { #[external(v0)] impl PausableImpl of super::IPausable { fn is_paused(self: @ContractState) -> bool { - self.paused.read() + self.Pausable_paused.read() } } #[generate_trait] impl InternalImpl of InternalTrait { fn assert_not_paused(self: @ContractState) { - assert(!self.paused.read(), Errors::PAUSED); + assert(!self.Pausable_paused.read(), Errors::PAUSED); } fn assert_paused(self: @ContractState) { - assert(self.paused.read(), Errors::NOT_PAUSED); + assert(self.Pausable_paused.read(), Errors::NOT_PAUSED); } fn _pause(ref self: ContractState) { self.assert_not_paused(); - self.paused.write(true); + self.Pausable_paused.write(true); self.emit(Paused { account: get_caller_address() }); } fn _unpause(ref self: ContractState) { self.assert_paused(); - self.paused.write(false); + self.Pausable_paused.write(false); self.emit(Unpaused { account: get_caller_address() }); } } diff --git a/src/security/reentrancyguard.cairo b/src/security/reentrancyguard.cairo index d6a218c62..cabc96049 100644 --- a/src/security/reentrancyguard.cairo +++ b/src/security/reentrancyguard.cairo @@ -7,7 +7,7 @@ mod ReentrancyGuard { #[storage] struct Storage { - entered: bool + ReentrancyGuard_entered: bool } mod Errors { @@ -17,12 +17,12 @@ mod ReentrancyGuard { #[generate_trait] impl InternalImpl of InternalTrait { fn start(ref self: ContractState) { - assert(!self.entered.read(), Errors::REENTRANT_CALL); - self.entered.write(true); + assert(!self.ReentrancyGuard_entered.read(), Errors::REENTRANT_CALL); + self.ReentrancyGuard_entered.write(true); } fn end(ref self: ContractState) { - self.entered.write(false); + self.ReentrancyGuard_entered.write(false); } } } diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index 04b9033a2..5c68a490a 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -2,7 +2,7 @@ use openzeppelin::access::ownable::Ownable::InternalImpl; use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; use openzeppelin::access::ownable::Ownable::OwnableImpl; use openzeppelin::access::ownable::Ownable::OwnershipTransferred; -use openzeppelin::access::ownable::Ownable::_owner::InternalContractMemberStateTrait; +use openzeppelin::access::ownable::Ownable::Ownable_owner::InternalContractMemberStateTrait; use openzeppelin::access::ownable::Ownable; use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; use openzeppelin::tests::utils; @@ -35,12 +35,12 @@ fn setup() -> Ownable::ContractState { #[available_gas(2000000)] fn test_initializer() { let mut state = STATE(); - assert(state._owner.read().is_zero(), 'Should be zero'); + assert(state.Ownable_owner.read().is_zero(), 'Should be zero'); InternalImpl::initializer(ref state, OWNER()); assert_event_ownership_transferred(ZERO(), OWNER()); - assert(state._owner.read() == OWNER(), 'Owner should be set'); + assert(state.Ownable_owner.read() == OWNER(), 'Owner should be set'); } // @@ -84,7 +84,7 @@ fn test__transfer_ownership() { assert_event_ownership_transferred(OWNER(), OTHER()); - assert(state._owner.read() == OTHER(), 'Owner should be OTHER'); + assert(state.Ownable_owner.read() == OTHER(), 'Owner should be OTHER'); } // diff --git a/src/tests/security/test_reentrancyguard.cairo b/src/tests/security/test_reentrancyguard.cairo index b5aa84056..231a693b6 100644 --- a/src/tests/security/test_reentrancyguard.cairo +++ b/src/tests/security/test_reentrancyguard.cairo @@ -1,5 +1,5 @@ use openzeppelin::security::reentrancyguard::ReentrancyGuard::InternalImpl; -use openzeppelin::security::reentrancyguard::ReentrancyGuard::entered::InternalContractMemberStateTrait; +use openzeppelin::security::reentrancyguard::ReentrancyGuard::ReentrancyGuard_entered::InternalContractMemberStateTrait; use openzeppelin::security::reentrancyguard::ReentrancyGuard; use openzeppelin::tests::mocks::reentrancy_attacker_mock::Attacker; use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; @@ -26,9 +26,9 @@ fn deploy_mock() -> IReentrancyMockDispatcher { fn test_reentrancy_guard_start() { let mut state = STATE(); - assert(!state.entered.read(), 'Should not be entered'); + assert(!state.ReentrancyGuard_entered.read(), 'Should not be entered'); InternalImpl::start(ref state); - assert(state.entered.read(), 'Should be entered'); + assert(state.ReentrancyGuard_entered.read(), 'Should be entered'); } #[test] @@ -47,9 +47,9 @@ fn test_reentrancy_guard_end() { let mut state = STATE(); InternalImpl::start(ref state); - assert(state.entered.read(), 'Should be entered'); + assert(state.ReentrancyGuard_entered.read(), 'Should be entered'); InternalImpl::end(ref state); - assert(!state.entered.read(), 'Should no longer be entered'); + assert(!state.ReentrancyGuard_entered.read(), 'Should no longer be entered'); } // diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index 1351e0385..25265d7e4 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -1,5 +1,5 @@ -use ERC721::_owners::InternalContractMemberStateTrait as OwnersTrait; -use ERC721::_token_approvals::InternalContractMemberStateTrait as TokenApprovalsTrait; +use ERC721::ERC721_owners::InternalContractMemberStateTrait as OwnersTrait; +use ERC721::ERC721_token_approvals::InternalContractMemberStateTrait as TokenApprovalsTrait; use array::ArrayTrait; use integer::u256; @@ -191,17 +191,17 @@ fn test__exists() { let token_id = TOKEN_ID; assert(!InternalImpl::_exists(@state, token_id), 'Token should not exist'); - assert(state._owners.read(token_id) == zero, 'Invalid owner'); + assert(state.ERC721_owners.read(token_id) == zero, 'Invalid owner'); InternalImpl::_mint(ref state, RECIPIENT(), token_id); assert(InternalImpl::_exists(@state, token_id), 'Token should exist'); - assert(state._owners.read(token_id) == RECIPIENT(), 'Invalid owner'); + assert(state.ERC721_owners.read(token_id) == RECIPIENT(), 'Invalid owner'); InternalImpl::_burn(ref state, token_id); assert(!InternalImpl::_exists(@state, token_id), 'Token should not exist'); - assert(state._owners.read(token_id) == zero, 'Invalid owner'); + assert(state.ERC721_owners.read(token_id) == zero, 'Invalid owner'); } // @@ -1329,9 +1329,9 @@ fn test__burn() { InternalImpl::_burn(ref state, TOKEN_ID); assert_event_transfer(OWNER(), ZERO(), TOKEN_ID); - assert(state._owners.read(TOKEN_ID) == ZERO(), 'Ownership after'); + assert(state.ERC721_owners.read(TOKEN_ID) == ZERO(), 'Ownership after'); assert(ERC721Impl::balance_of(@state, OWNER()) == 0, 'Balance of owner after'); - assert(state._token_approvals.read(TOKEN_ID) == ZERO(), 'Approval after'); + assert(state.ERC721_token_approvals.read(TOKEN_ID) == ZERO(), 'Approval after'); } #[test] diff --git a/src/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo index 9a97cee58..36b32c593 100644 --- a/src/token/erc20/erc20.cairo +++ b/src/token/erc20/erc20.cairo @@ -12,11 +12,11 @@ mod ERC20 { #[storage] struct Storage { - _name: felt252, - _symbol: felt252, - _total_supply: u256, - _balances: LegacyMap, - _allowances: LegacyMap<(ContractAddress, ContractAddress), u256>, + ERC20_name: felt252, + ERC20_symbol: felt252, + ERC20_total_supply: u256, + ERC20_balances: LegacyMap, + ERC20_allowances: LegacyMap<(ContractAddress, ContractAddress), u256>, } #[event] @@ -68,11 +68,11 @@ mod ERC20 { #[external(v0)] impl ERC20Impl of IERC20 { fn name(self: @ContractState) -> felt252 { - self._name.read() + self.ERC20_name.read() } fn symbol(self: @ContractState) -> felt252 { - self._symbol.read() + self.ERC20_symbol.read() } fn decimals(self: @ContractState) -> u8 { @@ -80,17 +80,17 @@ mod ERC20 { } fn total_supply(self: @ContractState) -> u256 { - self._total_supply.read() + self.ERC20_total_supply.read() } fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { - self._balances.read(account) + self.ERC20_balances.read(account) } fn allowance( self: @ContractState, owner: ContractAddress, spender: ContractAddress ) -> u256 { - self._allowances.read((owner, spender)) + self.ERC20_allowances.read((owner, spender)) } fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { @@ -173,15 +173,18 @@ mod ERC20 { #[generate_trait] impl InternalImpl of InternalTrait { fn initializer(ref self: ContractState, name: felt252, symbol: felt252) { - self._name.write(name); - self._symbol.write(symbol); + self.ERC20_name.write(name); + self.ERC20_symbol.write(symbol); } fn _increase_allowance( ref self: ContractState, spender: ContractAddress, added_value: u256 ) -> bool { let caller = get_caller_address(); - self._approve(caller, spender, self._allowances.read((caller, spender)) + added_value); + self + ._approve( + caller, spender, self.ERC20_allowances.read((caller, spender)) + added_value + ); true } @@ -191,22 +194,24 @@ mod ERC20 { let caller = get_caller_address(); self ._approve( - caller, spender, self._allowances.read((caller, spender)) - subtracted_value + caller, + spender, + self.ERC20_allowances.read((caller, spender)) - subtracted_value ); true } fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { assert(!recipient.is_zero(), Errors::MINT_TO_ZERO); - self._total_supply.write(self._total_supply.read() + amount); - self._balances.write(recipient, self._balances.read(recipient) + amount); + self.ERC20_total_supply.write(self.ERC20_total_supply.read() + amount); + self.ERC20_balances.write(recipient, self.ERC20_balances.read(recipient) + amount); self.emit(Transfer { from: Zeroable::zero(), to: recipient, value: amount }); } fn _burn(ref self: ContractState, account: ContractAddress, amount: u256) { assert(!account.is_zero(), Errors::BURN_FROM_ZERO); - self._total_supply.write(self._total_supply.read() - amount); - self._balances.write(account, self._balances.read(account) - amount); + self.ERC20_total_supply.write(self.ERC20_total_supply.read() - amount); + self.ERC20_balances.write(account, self.ERC20_balances.read(account) - amount); self.emit(Transfer { from: account, to: Zeroable::zero(), value: amount }); } @@ -215,7 +220,7 @@ mod ERC20 { ) { assert(!owner.is_zero(), Errors::APPROVE_FROM_ZERO); assert(!spender.is_zero(), Errors::APPROVE_TO_ZERO); - self._allowances.write((owner, spender), amount); + self.ERC20_allowances.write((owner, spender), amount); self.emit(Approval { owner, spender, value: amount }); } @@ -227,15 +232,15 @@ mod ERC20 { ) { assert(!sender.is_zero(), Errors::TRANSFER_FROM_ZERO); assert(!recipient.is_zero(), Errors::TRANSFER_TO_ZERO); - self._balances.write(sender, self._balances.read(sender) - amount); - self._balances.write(recipient, self._balances.read(recipient) + amount); + self.ERC20_balances.write(sender, self.ERC20_balances.read(sender) - amount); + self.ERC20_balances.write(recipient, self.ERC20_balances.read(recipient) + amount); self.emit(Transfer { from: sender, to: recipient, value: amount }); } fn _spend_allowance( ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256 ) { - let current_allowance = self._allowances.read((owner, spender)); + let current_allowance = self.ERC20_allowances.read((owner, spender)); if current_allowance != BoundedInt::max() { self._approve(owner, spender, current_allowance - amount); } diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index 0373dad36..660a92919 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -22,13 +22,13 @@ mod ERC721 { #[storage] struct Storage { - _name: felt252, - _symbol: felt252, - _owners: LegacyMap, - _balances: LegacyMap, - _token_approvals: LegacyMap, - _operator_approvals: LegacyMap<(ContractAddress, ContractAddress), bool>, - _token_uri: LegacyMap, + ERC721_name: felt252, + ERC721_symbol: felt252, + ERC721_owners: LegacyMap, + ERC721_balances: LegacyMap, + ERC721_token_approvals: LegacyMap, + ERC721_operator_approvals: LegacyMap<(ContractAddress, ContractAddress), bool>, + ERC721_token_uri: LegacyMap, } #[event] @@ -108,16 +108,16 @@ mod ERC721 { #[external(v0)] impl ERC721MetadataImpl of interface::IERC721Metadata { fn name(self: @ContractState) -> felt252 { - self._name.read() + self.ERC721_name.read() } fn symbol(self: @ContractState) -> felt252 { - self._symbol.read() + self.ERC721_symbol.read() } fn token_uri(self: @ContractState, token_id: u256) -> felt252 { assert(self._exists(token_id), Errors::INVALID_TOKEN_ID); - self._token_uri.read(token_id) + self.ERC721_token_uri.read(token_id) } } @@ -125,7 +125,7 @@ mod ERC721 { impl ERC721MetadataCamelOnlyImpl of interface::IERC721MetadataCamelOnly { fn tokenURI(self: @ContractState, tokenId: u256) -> felt252 { assert(self._exists(tokenId), Errors::INVALID_TOKEN_ID); - self._token_uri.read(tokenId) + self.ERC721_token_uri.read(tokenId) } } @@ -133,7 +133,7 @@ mod ERC721 { impl ERC721Impl of interface::IERC721 { fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { assert(!account.is_zero(), Errors::INVALID_ACCOUNT); - self._balances.read(account) + self.ERC721_balances.read(account) } fn owner_of(self: @ContractState, token_id: u256) -> ContractAddress { @@ -142,13 +142,13 @@ mod ERC721 { fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress { assert(self._exists(token_id), Errors::INVALID_TOKEN_ID); - self._token_approvals.read(token_id) + self.ERC721_token_approvals.read(token_id) } fn is_approved_for_all( self: @ContractState, owner: ContractAddress, operator: ContractAddress ) -> bool { - self._operator_approvals.read((owner, operator)) + self.ERC721_operator_approvals.read((owner, operator)) } fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) { @@ -239,8 +239,8 @@ mod ERC721 { #[generate_trait] impl InternalImpl of InternalTrait { fn initializer(ref self: ContractState, name: felt252, symbol: felt252) { - self._name.write(name); - self._symbol.write(symbol); + self.ERC721_name.write(name); + self.ERC721_symbol.write(symbol); let mut unsafe_state = src5::SRC5::unsafe_new_contract_state(); src5::SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IERC721_ID); @@ -250,7 +250,7 @@ mod ERC721 { } fn _owner_of(self: @ContractState, token_id: u256) -> ContractAddress { - let owner = self._owners.read(token_id); + let owner = self.ERC721_owners.read(token_id); match owner.is_zero() { bool::False(()) => owner, bool::True(()) => panic_with_felt252(Errors::INVALID_TOKEN_ID) @@ -258,7 +258,7 @@ mod ERC721 { } fn _exists(self: @ContractState, token_id: u256) -> bool { - !self._owners.read(token_id).is_zero() + !self.ERC721_owners.read(token_id).is_zero() } fn _is_approved_or_owner( @@ -275,7 +275,7 @@ mod ERC721 { let owner = self._owner_of(token_id); assert(owner != to, Errors::APPROVAL_TO_OWNER); - self._token_approvals.write(token_id, to); + self.ERC721_token_approvals.write(token_id, to); self.emit(Approval { owner, approved: to, token_id }); } @@ -286,7 +286,7 @@ mod ERC721 { approved: bool ) { assert(owner != operator, Errors::SELF_APPROVAL); - self._operator_approvals.write((owner, operator), approved); + self.ERC721_operator_approvals.write((owner, operator), approved); self.emit(ApprovalForAll { owner, operator, approved }); } @@ -294,8 +294,8 @@ mod ERC721 { assert(!to.is_zero(), Errors::INVALID_RECEIVER); assert(!self._exists(token_id), Errors::ALREADY_MINTED); - self._balances.write(to, self._balances.read(to) + 1); - self._owners.write(token_id, to); + self.ERC721_balances.write(to, self.ERC721_balances.read(to) + 1); + self.ERC721_owners.write(token_id, to); self.emit(Transfer { from: Zeroable::zero(), to, token_id }); } @@ -308,11 +308,11 @@ mod ERC721 { assert(from == owner, Errors::WRONG_SENDER); // Implicit clear approvals, no need to emit an event - self._token_approvals.write(token_id, Zeroable::zero()); + self.ERC721_token_approvals.write(token_id, Zeroable::zero()); - self._balances.write(from, self._balances.read(from) - 1); - self._balances.write(to, self._balances.read(to) + 1); - self._owners.write(token_id, to); + self.ERC721_balances.write(from, self.ERC721_balances.read(from) - 1); + self.ERC721_balances.write(to, self.ERC721_balances.read(to) + 1); + self.ERC721_owners.write(token_id, to); self.emit(Transfer { from, to, token_id }); } @@ -321,10 +321,10 @@ mod ERC721 { let owner = self._owner_of(token_id); // Implicit clear approvals, no need to emit an event - self._token_approvals.write(token_id, Zeroable::zero()); + self.ERC721_token_approvals.write(token_id, Zeroable::zero()); - self._balances.write(owner, self._balances.read(owner) - 1); - self._owners.write(token_id, Zeroable::zero()); + self.ERC721_balances.write(owner, self.ERC721_balances.read(owner) - 1); + self.ERC721_owners.write(token_id, Zeroable::zero()); self.emit(Transfer { from: owner, to: Zeroable::zero(), token_id }); } @@ -354,7 +354,7 @@ mod ERC721 { fn _set_token_uri(ref self: ContractState, token_id: u256, token_uri: felt252) { assert(self._exists(token_id), Errors::INVALID_TOKEN_ID); - self._token_uri.write(token_id, token_uri) + self.ERC721_token_uri.write(token_id, token_uri) } } From 420f320084033628d8aa4477107d84f2c21e0eea Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 27 Sep 2023 16:09:54 +0200 Subject: [PATCH 099/124] Sanitizing for release. (#736) * refactor: sanitizing * feat: sanitizing * feat: apply review updates * feat: apply review updates --- src/access/accesscontrol/accesscontrol.cairo | 9 ++--- .../accesscontrol/dual_accesscontrol.cairo | 2 - src/access/ownable/dual_ownable.cairo | 6 --- src/access/ownable/ownable.cairo | 1 - src/account.cairo | 2 - src/account/account.cairo | 33 ++++------------ src/account/dual_account.cairo | 2 - src/account/interface.cairo | 2 - src/introspection/dual_src5.cairo | 1 - src/introspection/src5.cairo | 5 +++ src/tests/access/test_accesscontrol.cairo | 1 - .../access/test_dual_accesscontrol.cairo | 1 - src/tests/access/test_dual_ownable.cairo | 16 +------- src/tests/access/test_ownable.cairo | 2 - src/tests/account/test_account.cairo | 7 +--- src/tests/introspection/test_dual_src5.cairo | 1 - src/tests/mocks/erc721_receiver.cairo | 4 +- src/tests/mocks/upgrades_v1.cairo | 1 - src/tests/mocks/upgrades_v2.cairo | 1 - src/tests/security/test_pausable.cairo | 1 - src/tests/token/test_dual20.cairo | 29 ++------------ src/tests/token/test_dual721.cairo | 38 ++----------------- src/tests/token/test_dual721_receiver.cairo | 30 +-------------- src/tests/token/test_erc20.cairo | 5 --- src/tests/token/test_erc721.cairo | 18 +-------- src/tests/upgrades/test_upgradeable.cairo | 14 +------ src/tests/utils.cairo | 1 - src/tests/utils/constants.cairo | 18 +++++++++ src/token/erc20/dual20.cairo | 1 - src/token/erc20/erc20.cairo | 1 - src/token/erc721/dual721.cairo | 1 - src/token/erc721/dual721_receiver.cairo | 2 - src/token/erc721/erc721.cairo | 14 ++----- src/token/erc721/interface.cairo | 1 - src/upgrades/upgradeable.cairo | 1 - src/utils.cairo | 4 -- src/utils/serde.cairo | 2 - src/utils/unwrap_and_cast.cairo | 4 -- 38 files changed, 51 insertions(+), 231 deletions(-) diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index 0f3aa7535..cd7cdde3a 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -7,6 +7,7 @@ mod AccessControl { use openzeppelin::introspection::interface::ISRC5; use openzeppelin::introspection::interface::ISRC5Camel; use openzeppelin::introspection::src5::SRC5; + use openzeppelin::introspection::src5::unsafe_state as src5_state; use starknet::ContractAddress; use starknet::get_caller_address; @@ -66,16 +67,14 @@ mod AccessControl { #[external(v0)] impl SRC5Impl of ISRC5 { fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - let unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) + SRC5::SRC5Impl::supports_interface(@src5_state(), interface_id) } } #[external(v0)] impl SRC5CamelImpl of ISRC5Camel { fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - let unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) + SRC5::SRC5CamelImpl::supportsInterface(@src5_state(), interfaceId) } } @@ -138,7 +137,7 @@ mod AccessControl { #[generate_trait] impl InternalImpl of InternalTrait { fn initializer(ref self: ContractState) { - let mut unsafe_state = SRC5::unsafe_new_contract_state(); + let mut unsafe_state = src5_state(); SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IACCESSCONTROL_ID); } diff --git a/src/access/accesscontrol/dual_accesscontrol.cairo b/src/access/accesscontrol/dual_accesscontrol.cairo index eb086840e..1fa18ff1d 100644 --- a/src/access/accesscontrol/dual_accesscontrol.cairo +++ b/src/access/accesscontrol/dual_accesscontrol.cairo @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/accesscontrol/dual_accesscontrol.cairo) -use array::ArrayTrait; - use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; diff --git a/src/access/ownable/dual_ownable.cairo b/src/access/ownable/dual_ownable.cairo index 03d2ba51b..923f97c5b 100644 --- a/src/access/ownable/dual_ownable.cairo +++ b/src/access/ownable/dual_ownable.cairo @@ -1,21 +1,15 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/dual_ownable.cairo) -use array::ArrayTrait; -use array::SpanTrait; -use core::result::ResultTrait; - use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::try_selector_with_fallback; -use option::OptionTrait; use starknet::ContractAddress; use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResultTrait; use starknet::call_contract_syscall; -use traits::TryInto; #[derive(Copy, Drop)] struct DualCaseOwnable { diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index 856de8190..9fac9da4a 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -6,7 +6,6 @@ mod Ownable { use openzeppelin::access::ownable::interface; use starknet::ContractAddress; use starknet::get_caller_address; - use zeroable::Zeroable; #[storage] struct Storage { diff --git a/src/account.cairo b/src/account.cairo index 1ca2c1578..501227b0b 100644 --- a/src/account.cairo +++ b/src/account.cairo @@ -3,8 +3,6 @@ mod dual_account; mod interface; use account::Account; -use account::QUERY_VERSION; -use account::TRANSACTION_VERSION; use interface::AccountABIDispatcher; use interface::AccountABIDispatcherTrait; use interface::AccountCamelABIDispatcher; diff --git a/src/account/account.cairo b/src/account/account.cairo index 90408a30f..ef73ef44a 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -1,18 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (account/account.cairo) -use array::ArrayTrait; -use array::SpanTrait; -use option::OptionTrait; -use serde::Serde; -use starknet::ContractAddress; -use starknet::account::Call; - -const TRANSACTION_VERSION: felt252 = 1; - -// 2**128 + TRANSACTION_VERSION -const QUERY_VERSION: felt252 = 340282366920938463463374607431768211457; - trait PublicKeyTrait { fn set_public_key(ref self: TState, new_public_key: felt252); fn get_public_key(self: @TState) -> felt252; @@ -25,24 +13,21 @@ trait PublicKeyCamelTrait { #[starknet::contract] mod Account { - use array::ArrayTrait; - use array::SpanTrait; - use box::BoxTrait; use ecdsa::check_ecdsa_signature; use openzeppelin::account::interface; use openzeppelin::introspection::interface::ISRC5; use openzeppelin::introspection::interface::ISRC5Camel; use openzeppelin::introspection::src5::SRC5; - use option::OptionTrait; + use openzeppelin::introspection::src5::unsafe_state as src5_state; + use starknet::account::Call; use starknet::get_caller_address; use starknet::get_contract_address; use starknet::get_tx_info; - use super::Call; - use super::QUERY_VERSION; - use super::TRANSACTION_VERSION; - use zeroable::Zeroable; + const TRANSACTION_VERSION: felt252 = 1; + // 2**128 + TRANSACTION_VERSION + const QUERY_VERSION: felt252 = 0x100000000000000000000000000000001; #[storage] struct Storage { @@ -134,16 +119,14 @@ mod Account { #[external(v0)] impl SRC5Impl of ISRC5 { fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - let unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) + SRC5::SRC5Impl::supports_interface(@src5_state(), interface_id) } } #[external(v0)] impl SRC5CamelImpl of ISRC5Camel { fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - let unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) + SRC5::SRC5CamelImpl::supportsInterface(@src5_state(), interfaceId) } } @@ -188,7 +171,7 @@ mod Account { #[generate_trait] impl InternalImpl of InternalTrait { fn initializer(ref self: ContractState, _public_key: felt252) { - let mut unsafe_state = SRC5::unsafe_new_contract_state(); + let mut unsafe_state = src5_state(); SRC5::InternalImpl::register_interface(ref unsafe_state, interface::ISRC6_ID); self._set_public_key(_public_key); } diff --git a/src/account/dual_account.cairo b/src/account/dual_account.cairo index 9e4d321c8..0f0ddfdee 100644 --- a/src/account/dual_account.cairo +++ b/src/account/dual_account.cairo @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (account/dual_account.cairo) -use array::ArrayTrait; -use array::SpanTrait; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; diff --git a/src/account/interface.cairo b/src/account/interface.cairo index b9a5abbef..e58c5bb30 100644 --- a/src/account/interface.cairo +++ b/src/account/interface.cairo @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (account/interface.cairo) -use array::ArrayTrait; -use array::SpanTrait; use starknet::ContractAddress; use starknet::account::Call; diff --git a/src/introspection/dual_src5.cairo b/src/introspection/dual_src5.cairo index 48d7c9c68..6d68e89ec 100644 --- a/src/introspection/dual_src5.cairo +++ b/src/introspection/dual_src5.cairo @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (introspection/dual_src5.cairo) -use array::ArrayTrait; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::try_selector_with_fallback; diff --git a/src/introspection/src5.cairo b/src/introspection/src5.cairo index 3b94f4218..ec8ec85b5 100644 --- a/src/introspection/src5.cairo +++ b/src/introspection/src5.cairo @@ -43,3 +43,8 @@ mod SRC5 { } } } + +#[inline(always)] +fn unsafe_state() -> SRC5::ContractState { + SRC5::unsafe_new_contract_state() +} diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index c8aeab26b..d86dd4490 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -11,7 +11,6 @@ use openzeppelin::tests::utils::constants::{ ADMIN, AUTHORIZED, OTHER, OTHER_ADMIN, ROLE, OTHER_ROLE, ZERO }; use openzeppelin::tests::utils; -use option::OptionTrait; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index 0a2f3527d..b7f922963 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; diff --git a/src/tests/access/test_dual_ownable.cairo b/src/tests/access/test_dual_ownable.cairo index 8055bd1fc..40f736bf5 100644 --- a/src/tests/access/test_dual_ownable.cairo +++ b/src/tests/access/test_dual_ownable.cairo @@ -9,25 +9,11 @@ use openzeppelin::tests::mocks::dual_ownable_mocks::CamelOwnablePanicMock; use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnableMock; use openzeppelin::tests::mocks::dual_ownable_mocks::SnakeOwnablePanicMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils::constants::{OWNER, NEW_OWNER}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; -use starknet::ContractAddress; -use starknet::contract_address_const; use starknet::testing::set_caller_address; use starknet::testing::set_contract_address; -use zeroable::Zeroable; - -// -// Constants -// - -fn OWNER() -> ContractAddress { - contract_address_const::<10>() -} - -fn NEW_OWNER() -> ContractAddress { - contract_address_const::<20>() -} // // Setup diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index 5c68a490a..8bb58ac01 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -6,11 +6,9 @@ use openzeppelin::access::ownable::Ownable::Ownable_owner::InternalContractMembe use openzeppelin::access::ownable::Ownable; use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; use openzeppelin::tests::utils; -use option::OptionTrait; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; -use zeroable::Zeroable; // // Setup diff --git a/src/tests/account/test_account.cairo b/src/tests/account/test_account.cairo index 83bea533b..2ca9550a8 100644 --- a/src/tests/account/test_account.cairo +++ b/src/tests/account/test_account.cairo @@ -1,5 +1,3 @@ -use array::ArrayTrait; -use core::traits::Into; use openzeppelin::account::Account::OwnerAdded; use openzeppelin::account::Account::OwnerRemoved; use openzeppelin::account::Account::PublicKeyCamelImpl; @@ -7,8 +5,7 @@ use openzeppelin::account::Account::PublicKeyImpl; use openzeppelin::account::Account; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; -use openzeppelin::account::QUERY_VERSION; -use openzeppelin::account::TRANSACTION_VERSION; +use openzeppelin::account::Account::{TRANSACTION_VERSION, QUERY_VERSION}; use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::utils; @@ -18,8 +15,6 @@ use openzeppelin::token::erc20::interface::IERC20Dispatcher; use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; -use option::OptionTrait; -use serde::Serde; use starknet::ContractAddress; use starknet::account::Call; use starknet::contract_address_const; diff --git a/src/tests/introspection/test_dual_src5.cairo b/src/tests/introspection/test_dual_src5.cairo index f2122f2e1..9720e8968 100644 --- a/src/tests/introspection/test_dual_src5.cairo +++ b/src/tests/introspection/test_dual_src5.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; use openzeppelin::introspection::interface::ISRC5CamelDispatcher; diff --git a/src/tests/mocks/erc721_receiver.cairo b/src/tests/mocks/erc721_receiver.cairo index 9205f6d97..240246019 100644 --- a/src/tests/mocks/erc721_receiver.cairo +++ b/src/tests/mocks/erc721_receiver.cairo @@ -1,9 +1,7 @@ -const SUCCESS: felt252 = 123123; -const FAILURE: felt252 = 456456; +use openzeppelin::tests::utils::constants::{FAILURE, SUCCESS}; #[starknet::contract] mod ERC721Receiver { - use array::SpanTrait; use openzeppelin::introspection::interface::ISRC5; use openzeppelin::introspection::interface::ISRC5Camel; use openzeppelin::introspection::src5::SRC5; diff --git a/src/tests/mocks/upgrades_v1.cairo b/src/tests/mocks/upgrades_v1.cairo index d851f59d9..37d5c19b3 100644 --- a/src/tests/mocks/upgrades_v1.cairo +++ b/src/tests/mocks/upgrades_v1.cairo @@ -2,7 +2,6 @@ // The functions are NOT PROTECTED. // DO NOT USE IN PRODUCTION. -use array::ArrayTrait; use starknet::ClassHash; #[starknet::interface] diff --git a/src/tests/mocks/upgrades_v2.cairo b/src/tests/mocks/upgrades_v2.cairo index f0ad60ee7..322c47ba1 100644 --- a/src/tests/mocks/upgrades_v2.cairo +++ b/src/tests/mocks/upgrades_v2.cairo @@ -2,7 +2,6 @@ // The functions are NOT PROTECTED. // DO NOT USE IN PRODUCTION. -use array::ArrayTrait; use starknet::ClassHash; #[starknet::interface] diff --git a/src/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo index 26497e121..faf1fcfc6 100644 --- a/src/tests/security/test_pausable.cairo +++ b/src/tests/security/test_pausable.cairo @@ -5,7 +5,6 @@ use openzeppelin::security::pausable::Pausable::Unpaused; use openzeppelin::security::pausable::Pausable; use openzeppelin::tests::utils::constants::{CALLER, ZERO}; use openzeppelin::tests::utils; -use option::OptionTrait; use starknet::contract_address_const; use starknet::ContractAddress; use starknet::testing; diff --git a/src/tests/token/test_dual20.cairo b/src/tests/token/test_dual20.cairo index aa0bd2306..948e1f882 100644 --- a/src/tests/token/test_dual20.cairo +++ b/src/tests/token/test_dual20.cairo @@ -1,9 +1,11 @@ -use array::ArrayTrait; use openzeppelin::tests::mocks::camel20_mock::CamelERC20Mock; use openzeppelin::tests::mocks::erc20_panic::CamelERC20Panic; use openzeppelin::tests::mocks::erc20_panic::SnakeERC20Panic; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::snake20_mock::SnakeERC20Mock; +use openzeppelin::tests::utils::constants::{ + OWNER, RECIPIENT, SPENDER, OPERATOR, NAME, SYMBOL, DECIMALS, SUPPLY, VALUE +}; use openzeppelin::tests::utils; use openzeppelin::token::erc20::dual20::DualCaseERC20; use openzeppelin::token::erc20::dual20::DualCaseERC20Trait; @@ -12,33 +14,8 @@ use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait; use openzeppelin::token::erc20::interface::IERC20Dispatcher; use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; use openzeppelin::utils::serde::SerializedAppend; -use starknet::ContractAddress; -use starknet::contract_address_const; use starknet::testing::set_contract_address; -// -// Constants -// - -const NAME: felt252 = 111; -const SYMBOL: felt252 = 222; -const DECIMALS: u8 = 18_u8; -const SUPPLY: u256 = 2000; -const VALUE: u256 = 300; - -fn OWNER() -> ContractAddress { - contract_address_const::<10>() -} -fn SPENDER() -> ContractAddress { - contract_address_const::<20>() -} -fn RECIPIENT() -> ContractAddress { - contract_address_const::<30>() -} -fn OPERATOR() -> ContractAddress { - contract_address_const::<40>() -} - // // Setup // diff --git a/src/tests/token/test_dual721.cairo b/src/tests/token/test_dual721.cairo index fc65cc426..0beb985a4 100644 --- a/src/tests/token/test_dual721.cairo +++ b/src/tests/token/test_dual721.cairo @@ -1,12 +1,12 @@ -use array::ArrayTrait; use openzeppelin::tests::mocks::camel721_mock::CamelERC721Mock; use openzeppelin::tests::mocks::erc721_panic_mock::CamelERC721PanicMock; use openzeppelin::tests::mocks::erc721_panic_mock::SnakeERC721PanicMock; use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; -use openzeppelin::tests::mocks::erc721_receiver::FAILURE; -use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::snake721_mock::SnakeERC721Mock; +use openzeppelin::tests::utils::constants::{ + DATA, OWNER, RECIPIENT, SPENDER, OPERATOR, OTHER, NAME, SYMBOL, URI, TOKEN_ID +}; use openzeppelin::tests::utils; use openzeppelin::token::erc721::dual721::DualCaseERC721; use openzeppelin::token::erc721::dual721::DualCaseERC721Trait; @@ -17,41 +17,9 @@ use openzeppelin::token::erc721::interface::IERC721DispatcherTrait; use openzeppelin::token::erc721::interface::IERC721_ID; use openzeppelin::utils::serde::SerializedAppend; use starknet::ContractAddress; -use starknet::contract_address_const; use starknet::testing::set_caller_address; use starknet::testing::set_contract_address; -// -// Constants -// - -const NAME: felt252 = 111; -const SYMBOL: felt252 = 222; -const URI: felt252 = 333; -const TOKEN_ID: u256 = 7; - -fn OWNER() -> ContractAddress { - contract_address_const::<10>() -} -fn RECIPIENT() -> ContractAddress { - contract_address_const::<20>() -} -fn SPENDER() -> ContractAddress { - contract_address_const::<30>() -} -fn OPERATOR() -> ContractAddress { - contract_address_const::<40>() -} -fn DATA(success: bool) -> Span { - let mut data = array![]; - if success { - data.append_serde(SUCCESS); - } else { - data.append_serde(FAILURE); - } - data.span() -} - // // Setup // diff --git a/src/tests/token/test_dual721_receiver.cairo b/src/tests/token/test_dual721_receiver.cairo index 876661b8c..84644dcf2 100644 --- a/src/tests/token/test_dual721_receiver.cairo +++ b/src/tests/token/test_dual721_receiver.cairo @@ -1,11 +1,9 @@ -use array::ArrayTrait; use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverPanicMock; use openzeppelin::tests::mocks::dual721_receiver_mocks::SnakeERC721ReceiverMock; use openzeppelin::tests::mocks::dual721_receiver_mocks::SnakeERC721ReceiverPanicMock; -use openzeppelin::tests::mocks::erc721_receiver::FAILURE; -use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils::constants::{DATA, OPERATOR, OWNER, TOKEN_ID}; use openzeppelin::tests::utils; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; @@ -14,32 +12,6 @@ use openzeppelin::token::erc721::interface::IERC721ReceiverCamelDispatcherTrait; use openzeppelin::token::erc721::interface::IERC721ReceiverDispatcher; use openzeppelin::token::erc721::interface::IERC721ReceiverDispatcherTrait; use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; -use starknet::ContractAddress; -use starknet::contract_address_const; - -// -// Constants -// - -const TOKEN_ID: u256 = 7; - -fn DATA(success: bool) -> Span { - let mut data = ArrayTrait::new(); - if success { - data.append(SUCCESS); - } else { - data.append(FAILURE); - } - data.span() -} - -fn OWNER() -> ContractAddress { - contract_address_const::<10>() -} - -fn OPERATOR() -> ContractAddress { - contract_address_const::<20>() -} // // Setup diff --git a/src/tests/token/test_erc20.cairo b/src/tests/token/test_erc20.cairo index 4109e909a..6ff440859 100644 --- a/src/tests/token/test_erc20.cairo +++ b/src/tests/token/test_erc20.cairo @@ -1,6 +1,4 @@ use integer::BoundedInt; -use integer::u256; -use integer::u256_from_felt252; use openzeppelin::tests::utils::constants::{ ZERO, OWNER, SPENDER, RECIPIENT, NAME, SYMBOL, DECIMALS, SUPPLY, VALUE }; @@ -11,12 +9,9 @@ use openzeppelin::token::erc20::ERC20::ERC20Impl; use openzeppelin::token::erc20::ERC20::InternalImpl; use openzeppelin::token::erc20::ERC20::Transfer; use openzeppelin::token::erc20::ERC20; -use option::OptionTrait; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; -use traits::Into; -use zeroable::Zeroable; // // Setup diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index 25265d7e4..4299928f9 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -1,7 +1,6 @@ use ERC721::ERC721_owners::InternalContractMemberStateTrait as OwnersTrait; use ERC721::ERC721_token_approvals::InternalContractMemberStateTrait as TokenApprovalsTrait; -use array::ArrayTrait; use integer::u256; use integer::u256_from_felt252; use openzeppelin::account::Account; @@ -10,11 +9,9 @@ use openzeppelin::introspection; use openzeppelin::tests::mocks::camel_account_mock::CamelAccountMock; use openzeppelin::tests::mocks::dual721_receiver_mocks::CamelERC721ReceiverMock; use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; -use openzeppelin::tests::mocks::erc721_receiver::FAILURE; -use openzeppelin::tests::mocks::erc721_receiver::SUCCESS; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils::constants::{ - ZERO, OWNER, RECIPIENT, SPENDER, OPERATOR, OTHER, NAME, SYMBOL, URI, TOKEN_ID, PUBKEY, + DATA, ZERO, OWNER, RECIPIENT, SPENDER, OPERATOR, OTHER, NAME, SYMBOL, URI, TOKEN_ID, PUBKEY, }; use openzeppelin::tests::utils; use openzeppelin::token::erc721::ERC721::{ @@ -23,22 +20,9 @@ use openzeppelin::token::erc721::ERC721::{ }; use openzeppelin::token::erc721::ERC721; use openzeppelin::token::erc721; -use option::OptionTrait; use starknet::contract_address_const; use starknet::ContractAddress; use starknet::testing; -use traits::Into; -use zeroable::Zeroable; - -fn DATA(success: bool) -> Span { - let mut data = array![]; - if success { - data.append(SUCCESS); - } else { - data.append(FAILURE); - } - data.span() -} // // Setup diff --git a/src/tests/upgrades/test_upgradeable.cairo b/src/tests/upgrades/test_upgradeable.cairo index 20b9c48c3..c43f8518f 100644 --- a/src/tests/upgrades/test_upgradeable.cairo +++ b/src/tests/upgrades/test_upgradeable.cairo @@ -1,20 +1,16 @@ -use array::ArrayTrait; use openzeppelin::tests::mocks::upgrades_v1::IUpgradesV1Dispatcher; use openzeppelin::tests::mocks::upgrades_v1::IUpgradesV1DispatcherTrait; use openzeppelin::tests::mocks::upgrades_v2::IUpgradesV2Dispatcher; use openzeppelin::tests::mocks::upgrades_v2::IUpgradesV2DispatcherTrait; use openzeppelin::tests::mocks::upgrades_v1::UpgradesV1; use openzeppelin::tests::mocks::upgrades_v2::UpgradesV2; +use openzeppelin::tests::utils::constants::{CLASS_HASH_ZERO, ZERO}; use openzeppelin::tests::utils; use openzeppelin::upgrades::upgradeable::Upgradeable::Upgraded; -use option::OptionTrait; use starknet::ClassHash; use starknet::ContractAddress; use starknet::Felt252TryIntoClassHash; -use starknet::class_hash_const; -use starknet::contract_address_const; use starknet::testing; -use traits::TryInto; const VALUE: felt252 = 123; @@ -22,14 +18,6 @@ fn V2_CLASS_HASH() -> ClassHash { UpgradesV2::TEST_CLASS_HASH.try_into().unwrap() } -fn CLASS_HASH_ZERO() -> ClassHash { - class_hash_const::<0>() -} - -fn ZERO() -> ContractAddress { - contract_address_const::<0>() -} - // // Setup // diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index 77d711c53..e0ebeacb3 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -7,7 +7,6 @@ use option::OptionTrait; use starknet::class_hash::Felt252TryIntoClassHash; use starknet::ContractAddress; use starknet::testing; -use traits::TryInto; fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { let (address, _) = starknet::deploy_syscall( diff --git a/src/tests/utils/constants.cairo b/src/tests/utils/constants.cairo index a66b6e721..73d22eb41 100644 --- a/src/tests/utils/constants.cairo +++ b/src/tests/utils/constants.cairo @@ -1,4 +1,6 @@ +use starknet::ClassHash; use starknet::ContractAddress; +use starknet::class_hash_const; use starknet::contract_address_const; const NAME: felt252 = 'NAME'; @@ -11,6 +13,8 @@ const OTHER_ROLE: felt252 = 'OTHER_ROLE'; const URI: felt252 = 'URI'; const TOKEN_ID: u256 = 21; const PUBKEY: felt252 = 'PUBKEY'; +const SUCCESS: felt252 = 123123; +const FAILURE: felt252 = 456456; fn ADMIN() -> ContractAddress { contract_address_const::<'ADMIN'>() @@ -24,6 +28,10 @@ fn ZERO() -> ContractAddress { contract_address_const::<0>() } +fn CLASS_HASH_ZERO() -> ClassHash { + class_hash_const::<0>() +} + fn CALLER() -> ContractAddress { contract_address_const::<'CALLER'>() } @@ -55,3 +63,13 @@ fn RECIPIENT() -> ContractAddress { fn OPERATOR() -> ContractAddress { contract_address_const::<'OPERATOR'>() } + +fn DATA(success: bool) -> Span { + let mut data = array![]; + if success { + data.append(SUCCESS); + } else { + data.append(FAILURE); + } + data.span() +} diff --git a/src/token/erc20/dual20.cairo b/src/token/erc20/dual20.cairo index dfb54584b..bbd8d8aae 100644 --- a/src/token/erc20/dual20.cairo +++ b/src/token/erc20/dual20.cairo @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc20/dual20.cairo) -use array::ArrayTrait; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; diff --git a/src/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo index 36b32c593..c62cd3803 100644 --- a/src/token/erc20/erc20.cairo +++ b/src/token/erc20/erc20.cairo @@ -8,7 +8,6 @@ mod ERC20 { use openzeppelin::token::erc20::interface::IERC20CamelOnly; use starknet::ContractAddress; use starknet::get_caller_address; - use zeroable::Zeroable; #[storage] struct Storage { diff --git a/src/token/erc721/dual721.cairo b/src/token/erc721/dual721.cairo index 041f267a2..2df75e071 100644 --- a/src/token/erc721/dual721.cairo +++ b/src/token/erc721/dual721.cairo @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/dual721.cairo) -use array::ArrayTrait; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; diff --git a/src/token/erc721/dual721_receiver.cairo b/src/token/erc721/dual721_receiver.cairo index 650285d6d..a32011a37 100644 --- a/src/token/erc721/dual721_receiver.cairo +++ b/src/token/erc721/dual721_receiver.cairo @@ -1,13 +1,11 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/dual721_receiver.cairo) -use array::ArrayTrait; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::try_selector_with_fallback; use starknet::ContractAddress; -use starknet::SyscallResultTrait; #[derive(Copy, Drop)] struct DualCaseERC721Receiver { diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index 660a92919..d67952f2d 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -1,24 +1,20 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/erc721.cairo) -use starknet::ContractAddress; - #[starknet::contract] mod ERC721 { - use array::SpanTrait; use openzeppelin::account; use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; use openzeppelin::introspection::interface::ISRC5; use openzeppelin::introspection::interface::ISRC5Camel; + use openzeppelin::introspection::src5::unsafe_state as src5_state; use openzeppelin::introspection::src5; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; use openzeppelin::token::erc721::interface; - use option::OptionTrait; use starknet::ContractAddress; use starknet::get_caller_address; - use zeroable::Zeroable; #[storage] struct Storage { @@ -92,16 +88,14 @@ mod ERC721 { #[external(v0)] impl SRC5Impl of ISRC5 { fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - let unsafe_state = src5::SRC5::unsafe_new_contract_state(); - src5::SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) + src5::SRC5::SRC5Impl::supports_interface(@src5_state(), interface_id) } } #[external(v0)] impl SRC5CamelImpl of ISRC5Camel { fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - let unsafe_state = src5::SRC5::unsafe_new_contract_state(); - src5::SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) + src5::SRC5::SRC5CamelImpl::supportsInterface(@src5_state(), interfaceId) } } @@ -242,7 +236,7 @@ mod ERC721 { self.ERC721_name.write(name); self.ERC721_symbol.write(symbol); - let mut unsafe_state = src5::SRC5::unsafe_new_contract_state(); + let mut unsafe_state = src5_state(); src5::SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IERC721_ID); src5::SRC5::InternalImpl::register_interface( ref unsafe_state, interface::IERC721_METADATA_ID diff --git a/src/token/erc721/interface.cairo b/src/token/erc721/interface.cairo index 86125721d..6fdc68272 100644 --- a/src/token/erc721/interface.cairo +++ b/src/token/erc721/interface.cairo @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (token/erc721/interface.cairo) -use array::SpanTrait; use starknet::ContractAddress; const IERC721_ID: felt252 = 0x33eb2f84c309543403fd69f0d0f363781ef06ef6faeb0131ff16ea3175bd943; diff --git a/src/upgrades/upgradeable.cairo b/src/upgrades/upgradeable.cairo index b10978d85..de9e546f2 100644 --- a/src/upgrades/upgradeable.cairo +++ b/src/upgrades/upgradeable.cairo @@ -2,7 +2,6 @@ mod Upgradeable { use starknet::ClassHash; use starknet::SyscallResult; - use zeroable::Zeroable; #[storage] struct Storage {} diff --git a/src/utils.cairo b/src/utils.cairo index 38b0b35dd..5396a17f6 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -6,10 +6,6 @@ mod selectors; mod serde; mod unwrap_and_cast; -use array::ArrayTrait; -use array::SpanTrait; -use box::BoxTrait; -use option::OptionTrait; use starknet::ContractAddress; use starknet::SyscallResult; use starknet::SyscallResultTrait; diff --git a/src/utils/serde.cairo b/src/utils/serde.cairo index 23fdad21b..2a4951355 100644 --- a/src/utils/serde.cairo +++ b/src/utils/serde.cairo @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (utils/serde.cairo) -use serde::Serde; - trait SerializedAppend { fn append_serde(ref self: Array, value: T); } diff --git a/src/utils/unwrap_and_cast.cairo b/src/utils/unwrap_and_cast.cairo index 9e58009a2..f625c08a2 100644 --- a/src/utils/unwrap_and_cast.cairo +++ b/src/utils/unwrap_and_cast.cairo @@ -1,15 +1,11 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (utils/unwrap_and_cast.cairo) -use array::SpanTrait; - use openzeppelin::utils::Felt252TryIntoBool; -use option::OptionTrait; use starknet::ContractAddress; use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResult; use starknet::SyscallResultTrait; -use traits::TryInto; trait UnwrapAndCast { fn unwrap_and_cast(self: SyscallResult>) -> T; From 4f973b6e703e0f7745623a62faa4a27607d6adbd Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 27 Sep 2023 21:30:32 +0200 Subject: [PATCH 100/124] feat: migrate logic --- Scarb.toml | 7 +- src/access/ownable/dual_ownable.cairo | 8 +- src/access/ownable/ownable.cairo | 81 ++++++++------ src/account/account.cairo | 7 +- src/lib.cairo | 5 +- .../access/test_dual_accesscontrol.cairo | 16 +-- src/tests/access/test_dual_ownable.cairo | 13 +-- src/tests/access/test_ownable.cairo | 72 ++++++------- src/tests/account/test_account.cairo | 4 +- src/tests/mocks/dual_ownable_mocks.cairo | 101 ++++++++++++------ src/tests/mocks/upgrades_v1.cairo | 4 +- src/tests/mocks/upgrades_v2.cairo | 4 +- src/tests/security/test_pausable.cairo | 2 +- src/tests/token/test_erc721.cairo | 2 +- src/tests/upgrades/test_upgradeable.cairo | 2 +- src/tests/utils.cairo | 2 +- src/token/erc721/erc721.cairo | 1 - src/upgrades.cairo | 2 +- 18 files changed, 185 insertions(+), 148 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index 13ffeb95c..279ec8fa6 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,7 +1,7 @@ [package] name = "openzeppelin" version = "0.7.0-rc.0" -cairo-version = "2.2.0" +cairo-version = "2.3.0-rc0" authors = ["OpenZeppelin Community "] description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" documentation = "https://docs.openzeppelin.com/contracts-cairo" @@ -11,7 +11,7 @@ license-file = "LICENSE" keywords = ["openzeppelin", "starknet", "cairo", "contracts", "security", "standards"] [dependencies] -starknet = ">=2.2.0" +starknet = "2.3.0-rc0" [lib] @@ -19,3 +19,6 @@ starknet = ">=2.2.0" allowed-libfuncs-list.name = "experimental" sierra = true casm = false + +[tool.fmt] +sort-module-level-items = true \ No newline at end of file diff --git a/src/access/ownable/dual_ownable.cairo b/src/access/ownable/dual_ownable.cairo index 923f97c5b..c53e1ce06 100644 --- a/src/access/ownable/dual_ownable.cairo +++ b/src/access/ownable/dual_ownable.cairo @@ -1,13 +1,11 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/dual_ownable.cairo) -use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::try_selector_with_fallback; use starknet::ContractAddress; -use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResultTrait; use starknet::call_contract_syscall; @@ -24,14 +22,14 @@ trait DualCaseOwnableTrait { impl DualCaseOwnableImpl of DualCaseOwnableTrait { fn owner(self: @DualCaseOwnable) -> ContractAddress { - let args = ArrayTrait::new(); + let args = array![]; call_contract_syscall(*self.contract_address, selectors::owner, args.span()) .unwrap_and_cast() } fn transfer_ownership(self: @DualCaseOwnable, new_owner: ContractAddress) { - let mut args = ArrayTrait::new(); + let mut args = array![]; args.append_serde(new_owner); try_selector_with_fallback( @@ -44,7 +42,7 @@ impl DualCaseOwnableImpl of DualCaseOwnableTrait { } fn renounce_ownership(self: @DualCaseOwnable) { - let mut args = ArrayTrait::new(); + let mut args = array![]; try_selector_with_fallback( *self.contract_address, diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index 9fac9da4a..e5f1bd7e9 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/ownable.cairo) -#[starknet::contract] +#[starknet::component] mod Ownable { use openzeppelin::access::ownable::interface; use starknet::ContractAddress; @@ -30,20 +30,58 @@ mod Ownable { const ZERO_ADDRESS_OWNER: felt252 = 'New owner is the zero address'; } - #[generate_trait] - impl InternalImpl of InternalTrait { - fn initializer(ref self: ContractState, owner: ContractAddress) { + #[embeddable_as(OwnableImpl)] + impl Ownable< + TContractState, +HasComponent + > of interface::IOwnable> { + fn owner(self: @ComponentState) -> ContractAddress { + self.Ownable_owner.read() + } + + fn transfer_ownership( + ref self: ComponentState, new_owner: ContractAddress + ) { + assert(!new_owner.is_zero(), Errors::ZERO_ADDRESS_OWNER); + self.assert_only_owner(); + self._transfer_ownership(new_owner); + } + + fn renounce_ownership(ref self: ComponentState) { + self.assert_only_owner(); + self._transfer_ownership(Zeroable::zero()); + } + } + + #[embeddable_as(OwnableCamelOnlyImpl)] + impl OwnableCamelOnly< + TContractState, +HasComponent + > of interface::IOwnableCamelOnly> { + fn transferOwnership(ref self: ComponentState, newOwner: ContractAddress) { + self.transfer_ownership(newOwner); + } + + fn renounceOwnership(ref self: ComponentState) { + self.renounce_ownership(); + } + } + + impl InternalImpl< + TContractState, +HasComponent + > of InternalTrait> { + fn initializer(ref self: ComponentState, owner: ContractAddress) { self._transfer_ownership(owner); } - fn assert_only_owner(self: @ContractState) { + fn assert_only_owner(self: @ComponentState) { let owner: ContractAddress = self.Ownable_owner.read(); let caller: ContractAddress = get_caller_address(); assert(!caller.is_zero(), Errors::ZERO_ADDRESS_CALLER); assert(caller == owner, Errors::NOT_OWNER); } - fn _transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { + fn _transfer_ownership( + ref self: ComponentState, new_owner: ContractAddress + ) { let previous_owner: ContractAddress = self.Ownable_owner.read(); self.Ownable_owner.write(new_owner); self @@ -53,32 +91,9 @@ mod Ownable { } } - #[external(v0)] - impl OwnableImpl of interface::IOwnable { - fn owner(self: @ContractState) -> ContractAddress { - self.Ownable_owner.read() - } - - fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { - assert(!new_owner.is_zero(), Errors::ZERO_ADDRESS_OWNER); - self.assert_only_owner(); - self._transfer_ownership(new_owner); - } - - fn renounce_ownership(ref self: ContractState) { - self.assert_only_owner(); - self._transfer_ownership(Zeroable::zero()); - } - } - - #[external(v0)] - impl OwnableCamelOnlyImpl of interface::IOwnableCamelOnly { - fn transferOwnership(ref self: ContractState, newOwner: ContractAddress) { - OwnableImpl::transfer_ownership(ref self, newOwner); - } - - fn renounceOwnership(ref self: ContractState) { - OwnableImpl::renounce_ownership(ref self); - } + trait InternalTrait { + fn initializer(ref self: TContractState, owner: ContractAddress); + fn assert_only_owner(self: @TContractState); + fn _transfer_ownership(ref self: TContractState, new_owner: ContractAddress); } } diff --git a/src/account/account.cairo b/src/account/account.cairo index ef73ef44a..680d824b0 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -204,14 +204,12 @@ mod Account { } } - #[internal] fn assert_only_self() { let caller = get_caller_address(); let self = get_contract_address(); assert(self == caller, Errors::UNAUTHORIZED); } - #[private] fn _execute_calls(mut calls: Array) -> Array> { let mut res = ArrayTrait::new(); loop { @@ -220,15 +218,12 @@ mod Account { let _res = _execute_single_call(call); res.append(_res); }, - Option::None(_) => { - break (); - }, + Option::None(_) => { break (); }, }; }; res } - #[private] fn _execute_single_call(call: Call) -> Span { let Call{to, selector, calldata } = call; starknet::call_contract_syscall(to, selector, calldata.span()).unwrap() diff --git a/src/lib.cairo b/src/lib.cairo index ea35f72ca..71de24d54 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -2,9 +2,8 @@ mod access; mod account; mod introspection; mod security; +#[cfg(test)] +mod tests; mod token; mod upgrades; mod utils; - -#[cfg(test)] -mod tests; diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index b7f922963..5a666a6db 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -1,16 +1,16 @@ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; -use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; -use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; -use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; -use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; -use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; -use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; -use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; use openzeppelin::tests::mocks::accesscontrol_panic_mock::CamelAccessControlPanicMock; +use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; use openzeppelin::tests::utils::constants::{ADMIN, AUTHORIZED, ROLE}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; diff --git a/src/tests/access/test_dual_ownable.cairo b/src/tests/access/test_dual_ownable.cairo index 40f736bf5..7d9a2f79a 100644 --- a/src/tests/access/test_dual_ownable.cairo +++ b/src/tests/access/test_dual_ownable.cairo @@ -1,7 +1,6 @@ use openzeppelin::access::ownable::dual_ownable::DualCaseOwnable; use openzeppelin::access::ownable::dual_ownable::DualCaseOwnableTrait; use openzeppelin::access::ownable::interface::IOwnableCamelOnlyDispatcher; -use openzeppelin::access::ownable::interface::IOwnableCamelOnlyDispatcherTrait; use openzeppelin::access::ownable::interface::IOwnableDispatcher; use openzeppelin::access::ownable::interface::IOwnableDispatcherTrait; use openzeppelin::tests::mocks::dual_ownable_mocks::CamelOwnableMock; @@ -12,7 +11,6 @@ use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils::constants::{OWNER, NEW_OWNER}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; -use starknet::testing::set_caller_address; use starknet::testing::set_contract_address; // @@ -20,14 +18,14 @@ use starknet::testing::set_contract_address; // fn setup_snake() -> (DualCaseOwnable, IOwnableDispatcher) { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; calldata.append_serde(OWNER()); let target = utils::deploy(SnakeOwnableMock::TEST_CLASS_HASH, calldata); (DualCaseOwnable { contract_address: target }, IOwnableDispatcher { contract_address: target }) } fn setup_camel() -> (DualCaseOwnable, IOwnableCamelOnlyDispatcher) { - let mut calldata = ArrayTrait::new(); + let mut calldata = array![]; calldata.append_serde(OWNER()); let target = utils::deploy(CamelOwnableMock::TEST_CLASS_HASH, calldata); ( @@ -37,14 +35,14 @@ fn setup_camel() -> (DualCaseOwnable, IOwnableCamelOnlyDispatcher) { } fn setup_non_ownable() -> DualCaseOwnable { - let calldata = ArrayTrait::new(); + let calldata = array![]; let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); DualCaseOwnable { contract_address: target } } fn setup_ownable_panic() -> (DualCaseOwnable, DualCaseOwnable) { - let snake_target = utils::deploy(SnakeOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); - let camel_target = utils::deploy(CamelOwnablePanicMock::TEST_CLASS_HASH, ArrayTrait::new()); + let snake_target = utils::deploy(SnakeOwnablePanicMock::TEST_CLASS_HASH, array![]); + let camel_target = utils::deploy(CamelOwnablePanicMock::TEST_CLASS_HASH, array![]); ( DualCaseOwnable { contract_address: snake_target }, DualCaseOwnable { contract_address: camel_target } @@ -118,7 +116,6 @@ fn test_dual_renounce_ownership() { assert(target.owner().is_zero(), 'Should be zero'); } - #[test] #[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index 8bb58ac01..4a17980e4 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -1,26 +1,24 @@ -use openzeppelin::access::ownable::Ownable::InternalImpl; -use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; -use openzeppelin::access::ownable::Ownable::OwnableImpl; +use openzeppelin::access::ownable::Ownable::InternalTrait; use openzeppelin::access::ownable::Ownable::OwnershipTransferred; -use openzeppelin::access::ownable::Ownable::Ownable_owner::InternalContractMemberStateTrait; -use openzeppelin::access::ownable::Ownable; +use openzeppelin::access::ownable::interface::{IOwnable, IOwnableCamelOnly}; +use openzeppelin::tests::mocks::dual_ownable_mocks::DualCaseOwnableMock; use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; use openzeppelin::tests::utils; use starknet::ContractAddress; -use starknet::contract_address_const; +use starknet::storage::StorageMemberAccessTrait; use starknet::testing; // // Setup // -fn STATE() -> Ownable::ContractState { - Ownable::contract_state_for_testing() +fn STATE() -> DualCaseOwnableMock::ContractState { + DualCaseOwnableMock::contract_state_for_testing() } -fn setup() -> Ownable::ContractState { +fn setup() -> DualCaseOwnableMock::ContractState { let mut state = STATE(); - InternalImpl::initializer(ref state, OWNER()); + state.ownable.initializer(OWNER()); utils::drop_event(ZERO()); state } @@ -31,14 +29,14 @@ fn setup() -> Ownable::ContractState { #[test] #[available_gas(2000000)] -fn test_initializer() { +fn test_initializer_owner() { let mut state = STATE(); - assert(state.Ownable_owner.read().is_zero(), 'Should be zero'); - InternalImpl::initializer(ref state, OWNER()); + assert(state.ownable.Ownable_owner.read().is_zero(), 'Should be zero'); + state.ownable.initializer(OWNER()); assert_event_ownership_transferred(ZERO(), OWNER()); - assert(state.Ownable_owner.read() == OWNER(), 'Owner should be set'); + assert(state.ownable.Ownable_owner.read() == OWNER(), 'Owner should be set'); } // @@ -50,7 +48,7 @@ fn test_initializer() { fn test_assert_only_owner() { let state = setup(); testing::set_caller_address(OWNER()); - InternalImpl::assert_only_owner(@state); + state.ownable.assert_only_owner(); } #[test] @@ -59,7 +57,7 @@ fn test_assert_only_owner() { fn test_assert_only_owner_when_not_owner() { let state = setup(); testing::set_caller_address(OTHER()); - InternalImpl::assert_only_owner(@state); + state.ownable.assert_only_owner(); } #[test] @@ -67,7 +65,7 @@ fn test_assert_only_owner_when_not_owner() { #[should_panic(expected: ('Caller is the zero address',))] fn test_assert_only_owner_when_caller_zero() { let state = setup(); - InternalImpl::assert_only_owner(@state); + state.ownable.assert_only_owner(); } // @@ -78,11 +76,11 @@ fn test_assert_only_owner_when_caller_zero() { #[available_gas(2000000)] fn test__transfer_ownership() { let mut state = setup(); - InternalImpl::_transfer_ownership(ref state, OTHER()); + state.ownable._transfer_ownership(OTHER()); assert_event_ownership_transferred(OWNER(), OTHER()); - assert(state.Ownable_owner.read() == OTHER(), 'Owner should be OTHER'); + assert(state.ownable.Ownable_owner.read() == OTHER(), 'Owner should be OTHER'); } // @@ -94,11 +92,11 @@ fn test__transfer_ownership() { fn test_transfer_ownership() { let mut state = setup(); testing::set_caller_address(OWNER()); - OwnableImpl::transfer_ownership(ref state, OTHER()); + state.ownable.transfer_ownership(OTHER()); assert_event_ownership_transferred(OWNER(), OTHER()); - assert(OwnableImpl::owner(@state) == OTHER(), 'Should transfer ownership'); + assert(state.ownable.owner() == OTHER(), 'Should transfer ownership'); } #[test] @@ -107,7 +105,7 @@ fn test_transfer_ownership() { fn test_transfer_ownership_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); - OwnableImpl::transfer_ownership(ref state, ZERO()); + state.ownable.transfer_ownership(ZERO()); } #[test] @@ -115,7 +113,7 @@ fn test_transfer_ownership_to_zero() { #[should_panic(expected: ('Caller is the zero address',))] fn test_transfer_ownership_from_zero() { let mut state = setup(); - OwnableImpl::transfer_ownership(ref state, OTHER()); + state.ownable.transfer_ownership(OTHER()); } #[test] @@ -124,7 +122,7 @@ fn test_transfer_ownership_from_zero() { fn test_transfer_ownership_from_nonowner() { let mut state = setup(); testing::set_caller_address(OTHER()); - OwnableImpl::transfer_ownership(ref state, OTHER()); + state.ownable.transfer_ownership(OTHER()); } #[test] @@ -132,11 +130,11 @@ fn test_transfer_ownership_from_nonowner() { fn test_transferOwnership() { let mut state = setup(); testing::set_caller_address(OWNER()); - OwnableCamelOnlyImpl::transferOwnership(ref state, OTHER()); + state.ownable.transferOwnership(OTHER()); assert_event_ownership_transferred(OWNER(), OTHER()); - assert(OwnableImpl::owner(@state) == OTHER(), 'Should transfer ownership'); + assert(state.ownable.owner() == OTHER(), 'Should transfer ownership'); } #[test] @@ -145,7 +143,7 @@ fn test_transferOwnership() { fn test_transferOwnership_to_zero() { let mut state = setup(); testing::set_caller_address(OWNER()); - OwnableCamelOnlyImpl::transferOwnership(ref state, ZERO()); + state.ownable.transferOwnership(ZERO()); } #[test] @@ -153,7 +151,7 @@ fn test_transferOwnership_to_zero() { #[should_panic(expected: ('Caller is the zero address',))] fn test_transferOwnership_from_zero() { let mut state = setup(); - OwnableCamelOnlyImpl::transferOwnership(ref state, OTHER()); + state.ownable.transferOwnership(OTHER()); } #[test] @@ -162,7 +160,7 @@ fn test_transferOwnership_from_zero() { fn test_transferOwnership_from_nonowner() { let mut state = setup(); testing::set_caller_address(OTHER()); - OwnableCamelOnlyImpl::transferOwnership(ref state, OTHER()); + state.ownable.transferOwnership(OTHER()); } // @@ -174,11 +172,11 @@ fn test_transferOwnership_from_nonowner() { fn test_renounce_ownership() { let mut state = setup(); testing::set_caller_address(OWNER()); - OwnableImpl::renounce_ownership(ref state); + state.ownable.renounce_ownership(); assert_event_ownership_transferred(OWNER(), ZERO()); - assert(OwnableImpl::owner(@state) == ZERO(), 'Should renounce ownership'); + assert(state.ownable.owner() == ZERO(), 'Should renounce ownership'); } #[test] @@ -186,7 +184,7 @@ fn test_renounce_ownership() { #[should_panic(expected: ('Caller is the zero address',))] fn test_renounce_ownership_from_zero_address() { let mut state = setup(); - OwnableImpl::renounce_ownership(ref state); + state.ownable.renounce_ownership(); } #[test] @@ -195,7 +193,7 @@ fn test_renounce_ownership_from_zero_address() { fn test_renounce_ownership_from_nonowner() { let mut state = setup(); testing::set_caller_address(OTHER()); - OwnableImpl::renounce_ownership(ref state); + state.ownable.renounce_ownership(); } #[test] @@ -203,11 +201,11 @@ fn test_renounce_ownership_from_nonowner() { fn test_renounceOwnership() { let mut state = setup(); testing::set_caller_address(OWNER()); - OwnableCamelOnlyImpl::renounceOwnership(ref state); + state.ownable.renounceOwnership(); assert_event_ownership_transferred(OWNER(), ZERO()); - assert(OwnableImpl::owner(@state) == ZERO(), 'Should renounce ownership'); + assert(state.ownable.owner() == ZERO(), 'Should renounce ownership'); } #[test] @@ -215,7 +213,7 @@ fn test_renounceOwnership() { #[should_panic(expected: ('Caller is the zero address',))] fn test_renounceOwnership_from_zero_address() { let mut state = setup(); - OwnableCamelOnlyImpl::renounceOwnership(ref state); + state.ownable.renounceOwnership(); } #[test] @@ -224,7 +222,7 @@ fn test_renounceOwnership_from_zero_address() { fn test_renounceOwnership_from_nonowner() { let mut state = setup(); testing::set_caller_address(OTHER()); - OwnableCamelOnlyImpl::renounceOwnership(ref state); + state.ownable.renounceOwnership(); } // diff --git a/src/tests/account/test_account.cairo b/src/tests/account/test_account.cairo index 2ca9550a8..92811652e 100644 --- a/src/tests/account/test_account.cairo +++ b/src/tests/account/test_account.cairo @@ -2,14 +2,14 @@ use openzeppelin::account::Account::OwnerAdded; use openzeppelin::account::Account::OwnerRemoved; use openzeppelin::account::Account::PublicKeyCamelImpl; use openzeppelin::account::Account::PublicKeyImpl; +use openzeppelin::account::Account::{TRANSACTION_VERSION, QUERY_VERSION}; use openzeppelin::account::Account; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; -use openzeppelin::account::Account::{TRANSACTION_VERSION, QUERY_VERSION}; use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::introspection::interface::ISRC5_ID; -use openzeppelin::tests::utils; use openzeppelin::tests::utils::constants::ZERO; +use openzeppelin::tests::utils; use openzeppelin::token::erc20::ERC20; use openzeppelin::token::erc20::interface::IERC20Dispatcher; use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; diff --git a/src/tests/mocks/dual_ownable_mocks.cairo b/src/tests/mocks/dual_ownable_mocks.cairo index 7826e859e..82a7abb7a 100644 --- a/src/tests/mocks/dual_ownable_mocks.cairo +++ b/src/tests/mocks/dual_ownable_mocks.cairo @@ -1,68 +1,101 @@ use openzeppelin::access::ownable::Ownable; #[starknet::contract] -mod SnakeOwnableMock { +mod DualCaseOwnableMock { + use openzeppelin::access::ownable::Ownable as ownable_component; use starknet::ContractAddress; use super::Ownable; + component!(path: ownable_component, storage: ownable, event: OwnableEvent); + + #[abi(embed_v0)] + impl OwnableImpl = ownable_component::OwnableImpl; + #[abi(embed_v0)] + impl OwnableCamelOnlyImpl = + ownable_component::OwnableCamelOnlyImpl; + impl InternalImpl = ownable_component::InternalImpl; + #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + ownable: ownable_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + OwnableEvent: ownable_component::Event + } #[constructor] - fn constructor(self: @ContractState, owner: ContractAddress) { - let mut unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::InternalImpl::initializer(ref unsafe_state, owner); + fn constructor(ref self: ContractState, owner: ContractAddress) { + self.ownable.initializer(owner); } +} - #[external(v0)] - fn owner(self: @ContractState) -> ContractAddress { - let unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::OwnableImpl::owner(@unsafe_state) +#[starknet::contract] +mod SnakeOwnableMock { + use openzeppelin::access::ownable::Ownable as ownable_component; + use starknet::ContractAddress; + use super::Ownable; + + component!(path: ownable_component, storage: ownable, event: OwnableEvent); + + #[abi(embed_v0)] + impl OwnableImpl = ownable_component::OwnableImpl; + impl InternalImpl = ownable_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + ownable: ownable_component::Storage } - #[external(v0)] - fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { - let mut unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::OwnableImpl::transfer_ownership(ref unsafe_state, new_owner); + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + OwnableEvent: ownable_component::Event } - #[external(v0)] - fn renounce_ownership(ref self: ContractState) { - let mut unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::OwnableImpl::renounce_ownership(ref unsafe_state); + #[constructor] + fn constructor(ref self: ContractState, owner: ContractAddress) { + self.ownable.initializer(owner); } } #[starknet::contract] mod CamelOwnableMock { + use openzeppelin::access::ownable::Ownable as ownable_component; use starknet::ContractAddress; use super::Ownable; - #[storage] - struct Storage {} + component!(path: ownable_component, storage: ownable, event: OwnableEvent); - #[constructor] - fn constructor(self: @ContractState, owner: ContractAddress) { - let mut unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::InternalImpl::initializer(ref unsafe_state, owner); + #[abi(embed_v0)] + impl OwnableCamelOnlyImpl = + ownable_component::OwnableCamelOnlyImpl; + impl InternalImpl = ownable_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + ownable: ownable_component::Storage } - #[external(v0)] - fn owner(self: @ContractState) -> ContractAddress { - let unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::OwnableImpl::owner(@unsafe_state) + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + OwnableEvent: ownable_component::Event } - #[external(v0)] - fn transferOwnership(ref self: ContractState, newOwner: ContractAddress) { - let mut unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::OwnableCamelOnlyImpl::transferOwnership(ref unsafe_state, newOwner); + #[constructor] + fn constructor(ref self: ContractState, owner: ContractAddress) { + self.ownable.initializer(owner); } #[external(v0)] - fn renounceOwnership(ref self: ContractState) { - let mut unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::OwnableCamelOnlyImpl::renounceOwnership(ref unsafe_state); + fn owner(self: @ContractState) -> ContractAddress { + self.ownable.Ownable_owner.read() } } diff --git a/src/tests/mocks/upgrades_v1.cairo b/src/tests/mocks/upgrades_v1.cairo index 37d5c19b3..eec4cca81 100644 --- a/src/tests/mocks/upgrades_v1.cairo +++ b/src/tests/mocks/upgrades_v1.cairo @@ -21,10 +21,10 @@ trait UpgradesV1Trait { #[starknet::contract] mod UpgradesV1 { use array::ArrayTrait; - use starknet::ClassHash; - use starknet::ContractAddress; use openzeppelin::upgrades::interface::IUpgradeable; use openzeppelin::upgrades::upgradeable::Upgradeable; + use starknet::ClassHash; + use starknet::ContractAddress; #[storage] struct Storage { diff --git a/src/tests/mocks/upgrades_v2.cairo b/src/tests/mocks/upgrades_v2.cairo index 322c47ba1..fc3749613 100644 --- a/src/tests/mocks/upgrades_v2.cairo +++ b/src/tests/mocks/upgrades_v2.cairo @@ -23,10 +23,10 @@ trait UpgradesV2Trait { #[starknet::contract] mod UpgradesV2 { use array::ArrayTrait; - use starknet::ClassHash; - use starknet::ContractAddress; use openzeppelin::upgrades::interface::IUpgradeable; use openzeppelin::upgrades::upgradeable::Upgradeable; + use starknet::ClassHash; + use starknet::ContractAddress; #[storage] struct Storage { diff --git a/src/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo index faf1fcfc6..f1aff256e 100644 --- a/src/tests/security/test_pausable.cairo +++ b/src/tests/security/test_pausable.cairo @@ -5,8 +5,8 @@ use openzeppelin::security::pausable::Pausable::Unpaused; use openzeppelin::security::pausable::Pausable; use openzeppelin::tests::utils::constants::{CALLER, ZERO}; use openzeppelin::tests::utils; -use starknet::contract_address_const; use starknet::ContractAddress; +use starknet::contract_address_const; use starknet::testing; // diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index 4299928f9..5687dca0a 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -20,8 +20,8 @@ use openzeppelin::token::erc721::ERC721::{ }; use openzeppelin::token::erc721::ERC721; use openzeppelin::token::erc721; -use starknet::contract_address_const; use starknet::ContractAddress; +use starknet::contract_address_const; use starknet::testing; // diff --git a/src/tests/upgrades/test_upgradeable.cairo b/src/tests/upgrades/test_upgradeable.cairo index c43f8518f..d96d936c5 100644 --- a/src/tests/upgrades/test_upgradeable.cairo +++ b/src/tests/upgrades/test_upgradeable.cairo @@ -1,8 +1,8 @@ use openzeppelin::tests::mocks::upgrades_v1::IUpgradesV1Dispatcher; use openzeppelin::tests::mocks::upgrades_v1::IUpgradesV1DispatcherTrait; +use openzeppelin::tests::mocks::upgrades_v1::UpgradesV1; use openzeppelin::tests::mocks::upgrades_v2::IUpgradesV2Dispatcher; use openzeppelin::tests::mocks::upgrades_v2::IUpgradesV2DispatcherTrait; -use openzeppelin::tests::mocks::upgrades_v1::UpgradesV1; use openzeppelin::tests::mocks::upgrades_v2::UpgradesV2; use openzeppelin::tests::utils::constants::{CLASS_HASH_ZERO, ZERO}; use openzeppelin::tests::utils; diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index e0ebeacb3..cb3224555 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -4,8 +4,8 @@ use array::ArrayTrait; use array::SpanTrait; use core::result::ResultTrait; use option::OptionTrait; -use starknet::class_hash::Felt252TryIntoClassHash; use starknet::ContractAddress; +use starknet::class_hash::Felt252TryIntoClassHash; use starknet::testing; fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index d67952f2d..fa9942364 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -352,7 +352,6 @@ mod ERC721 { } } - #[internal] fn _check_on_erc721_received( from: ContractAddress, to: ContractAddress, token_id: u256, data: Span ) -> bool { diff --git a/src/upgrades.cairo b/src/upgrades.cairo index 18d78fc73..5e4801d5b 100644 --- a/src/upgrades.cairo +++ b/src/upgrades.cairo @@ -1,2 +1,2 @@ -mod upgradeable; mod interface; +mod upgradeable; From 2f4b1f051d9628405a44e33312097f50bed421ce Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 27 Sep 2023 21:34:54 +0200 Subject: [PATCH 101/124] feat: update workflow --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1dccc55bf..2894bb7db 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v3 - uses: software-mansion/setup-scarb@v1 with: - scarb-version: "0.7.0" + scarb-version: "2.3.0-rc0" - name: Markdown lint uses: DavidAnson/markdownlint-cli2-action@5b7c9f74fec47e6b15667b2cc23c63dff11e449e # v9 with: From 715e47351ef572babf47ffdca710e6cbef73162f Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 15:45:24 +0200 Subject: [PATCH 102/124] feat: update logic --- .github/workflows/test.yml | 2 +- Scarb.toml | 7 +- src/access/accesscontrol/accesscontrol.cairo | 33 ++++------ src/account/account.cairo | 43 +++++------- src/introspection/src5.cairo | 39 ++++++----- src/lib.cairo | 6 +- .../access/test_dual_accesscontrol.cairo | 16 ++--- src/tests/access/test_ownable.cairo | 2 +- src/tests/account/test_account.cairo | 4 +- src/tests/introspection/test_dual_src5.cairo | 4 -- src/tests/introspection/test_src5.cairo | 29 +++++---- src/tests/mocks/dual721_receiver_mocks.cairo | 56 ++++++++++------ src/tests/mocks/erc721_receiver.cairo | 39 ++++++----- src/tests/mocks/src5_mocks.cairo | 65 ++++++++++++++++--- src/tests/mocks/upgrades_v1.cairo | 4 +- src/tests/mocks/upgrades_v2.cairo | 4 +- src/tests/security/test_pausable.cairo | 2 +- src/tests/token/test_erc721.cairo | 2 +- src/tests/upgrades/test_upgradeable.cairo | 2 +- src/tests/utils.cairo | 2 +- src/token/erc721/erc721.cairo | 39 ++++------- src/upgrades.cairo | 2 +- 22 files changed, 222 insertions(+), 180 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1dccc55bf..2894bb7db 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v3 - uses: software-mansion/setup-scarb@v1 with: - scarb-version: "0.7.0" + scarb-version: "2.3.0-rc0" - name: Markdown lint uses: DavidAnson/markdownlint-cli2-action@5b7c9f74fec47e6b15667b2cc23c63dff11e449e # v9 with: diff --git a/Scarb.toml b/Scarb.toml index 13ffeb95c..5fb2794ae 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,7 +1,7 @@ [package] name = "openzeppelin" version = "0.7.0-rc.0" -cairo-version = "2.2.0" +cairo-version = "2.3.0-rc0" authors = ["OpenZeppelin Community "] description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" documentation = "https://docs.openzeppelin.com/contracts-cairo" @@ -11,7 +11,7 @@ license-file = "LICENSE" keywords = ["openzeppelin", "starknet", "cairo", "contracts", "security", "standards"] [dependencies] -starknet = ">=2.2.0" +starknet = "=2.3.0-rc0" [lib] @@ -19,3 +19,6 @@ starknet = ">=2.2.0" allowed-libfuncs-list.name = "experimental" sierra = true casm = false + +[tool.fmt] +sort-module-level-items = true diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index cd7cdde3a..beb7fffc5 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -4,17 +4,24 @@ #[starknet::contract] mod AccessControl { use openzeppelin::access::accesscontrol::interface; - use openzeppelin::introspection::interface::ISRC5; - use openzeppelin::introspection::interface::ISRC5Camel; - use openzeppelin::introspection::src5::SRC5; - use openzeppelin::introspection::src5::unsafe_state as src5_state; + use openzeppelin::introspection::src5::SRC5 as src5_component; use starknet::ContractAddress; use starknet::get_caller_address; + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + #[abi(embed_v0)] + impl SRC5CamelImpl = src5_component::SRC5CamelImpl; + impl SRC5InternalImpl = src5_component::InternalImpl; + #[storage] struct Storage { AccessControl_role_admin: LegacyMap, AccessControl_role_member: LegacyMap<(felt252, ContractAddress), bool>, + #[substorage(v0)] + src5: src5_component::Storage } #[event] @@ -23,6 +30,7 @@ mod AccessControl { RoleGranted: RoleGranted, RoleRevoked: RoleRevoked, RoleAdminChanged: RoleAdminChanged, + SRC5Event: src5_component::Event } /// Emitted when `account` is granted `role`. @@ -64,20 +72,6 @@ mod AccessControl { const MISSING_ROLE: felt252 = 'Caller is missing role'; } - #[external(v0)] - impl SRC5Impl of ISRC5 { - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - SRC5::SRC5Impl::supports_interface(@src5_state(), interface_id) - } - } - - #[external(v0)] - impl SRC5CamelImpl of ISRC5Camel { - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - SRC5::SRC5CamelImpl::supportsInterface(@src5_state(), interfaceId) - } - } - #[external(v0)] impl AccessControlImpl of interface::IAccessControl { fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { @@ -137,8 +131,7 @@ mod AccessControl { #[generate_trait] impl InternalImpl of InternalTrait { fn initializer(ref self: ContractState) { - let mut unsafe_state = src5_state(); - SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IACCESSCONTROL_ID); + self.src5.register_interface(interface::IACCESSCONTROL_ID); } fn assert_only_role(self: @ContractState, role: felt252) { diff --git a/src/account/account.cairo b/src/account/account.cairo index ef73ef44a..30160dfbe 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -14,12 +14,8 @@ trait PublicKeyCamelTrait { #[starknet::contract] mod Account { use ecdsa::check_ecdsa_signature; - use openzeppelin::account::interface; - use openzeppelin::introspection::interface::ISRC5; - use openzeppelin::introspection::interface::ISRC5Camel; - use openzeppelin::introspection::src5::SRC5; - use openzeppelin::introspection::src5::unsafe_state as src5_state; + use openzeppelin::introspection::src5::SRC5 as src5_component; use starknet::account::Call; use starknet::get_caller_address; use starknet::get_contract_address; @@ -29,9 +25,19 @@ mod Account { // 2**128 + TRANSACTION_VERSION const QUERY_VERSION: felt252 = 0x100000000000000000000000000000001; + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + #[abi(embed_v0)] + impl SRC5CamelImpl = src5_component::SRC5CamelImpl; + impl SRC5InternalImpl = src5_component::InternalImpl; + #[storage] struct Storage { - Account_public_key: felt252 + Account_public_key: felt252, + #[substorage(v0)] + src5: src5_component::Storage } #[event] @@ -39,6 +45,7 @@ mod Account { enum Event { OwnerAdded: OwnerAdded, OwnerRemoved: OwnerRemoved, + SRC5Event: src5_component::Event } #[derive(Drop, starknet::Event)] @@ -116,20 +123,6 @@ mod Account { } } - #[external(v0)] - impl SRC5Impl of ISRC5 { - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - SRC5::SRC5Impl::supports_interface(@src5_state(), interface_id) - } - } - - #[external(v0)] - impl SRC5CamelImpl of ISRC5Camel { - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - SRC5::SRC5CamelImpl::supportsInterface(@src5_state(), interfaceId) - } - } - #[external(v0)] impl PublicKeyImpl of super::PublicKeyTrait { fn get_public_key(self: @ContractState) -> felt252 { @@ -171,8 +164,7 @@ mod Account { #[generate_trait] impl InternalImpl of InternalTrait { fn initializer(ref self: ContractState, _public_key: felt252) { - let mut unsafe_state = src5_state(); - SRC5::InternalImpl::register_interface(ref unsafe_state, interface::ISRC6_ID); + self.src5.register_interface(interface::ISRC6_ID); self._set_public_key(_public_key); } @@ -204,14 +196,12 @@ mod Account { } } - #[internal] fn assert_only_self() { let caller = get_caller_address(); let self = get_contract_address(); assert(self == caller, Errors::UNAUTHORIZED); } - #[private] fn _execute_calls(mut calls: Array) -> Array> { let mut res = ArrayTrait::new(); loop { @@ -220,15 +210,12 @@ mod Account { let _res = _execute_single_call(call); res.append(_res); }, - Option::None(_) => { - break (); - }, + Option::None(_) => { break (); }, }; }; res } - #[private] fn _execute_single_call(call: Call) -> Span { let Call{to, selector, calldata } = call; starknet::call_contract_syscall(to, selector, calldata.span()).unwrap() diff --git a/src/introspection/src5.cairo b/src/introspection/src5.cairo index ec8ec85b5..6918c36d4 100644 --- a/src/introspection/src5.cairo +++ b/src/introspection/src5.cairo @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (introspection/src5.cairo) -#[starknet::contract] +#[starknet::component] mod SRC5 { use openzeppelin::introspection::interface; @@ -14,9 +14,13 @@ mod SRC5 { const INVALID_ID: felt252 = 'SRC5: invalid id'; } - #[external(v0)] - impl SRC5Impl of interface::ISRC5 { - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + #[embeddable_as(SRC5Impl)] + impl SRC5< + TContractState, +HasComponent + > of interface::ISRC5> { + fn supports_interface( + self: @ComponentState, interface_id: felt252 + ) -> bool { if interface_id == interface::ISRC5_ID { return true; } @@ -24,27 +28,30 @@ mod SRC5 { } } - #[external(v0)] - impl SRC5CamelImpl of interface::ISRC5Camel { - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - SRC5Impl::supports_interface(self, interfaceId) + #[embeddable_as(SRC5CamelImpl)] + impl SRC5Camel< + TContractState, +HasComponent + > of interface::ISRC5Camel> { + fn supportsInterface(self: @ComponentState, interfaceId: felt252) -> bool { + self.supports_interface(interfaceId) } } - #[generate_trait] - impl InternalImpl of InternalTrait { - fn register_interface(ref self: ContractState, interface_id: felt252) { + impl InternalImpl< + TContractState, +HasComponent + > of InternalTrait> { + fn register_interface(ref self: ComponentState, interface_id: felt252) { self.SRC5_supported_interfaces.write(interface_id, true); } - fn deregister_interface(ref self: ContractState, interface_id: felt252) { + fn deregister_interface(ref self: ComponentState, interface_id: felt252) { assert(interface_id != interface::ISRC5_ID, Errors::INVALID_ID); self.SRC5_supported_interfaces.write(interface_id, false); } } -} -#[inline(always)] -fn unsafe_state() -> SRC5::ContractState { - SRC5::unsafe_new_contract_state() + trait InternalTrait { + fn register_interface(ref self: TContractState, interface_id: felt252); + fn deregister_interface(ref self: TContractState, interface_id: felt252); + } } diff --git a/src/lib.cairo b/src/lib.cairo index ea35f72ca..4a1fa8cc3 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -2,9 +2,9 @@ mod access; mod account; mod introspection; mod security; -mod token; -mod upgrades; -mod utils; #[cfg(test)] mod tests; +mod token; +mod upgrades; +mod utils; diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index b7f922963..5a666a6db 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -1,16 +1,16 @@ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; +use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; -use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; -use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; -use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcher; -use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControlTrait; -use openzeppelin::access::accesscontrol::dual_accesscontrol::DualCaseAccessControl; -use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; -use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; +use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; use openzeppelin::tests::mocks::accesscontrol_panic_mock::CamelAccessControlPanicMock; +use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; +use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; use openzeppelin::tests::utils::constants::{ADMIN, AUTHORIZED, ROLE}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index 8bb58ac01..292bda3de 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -1,8 +1,8 @@ use openzeppelin::access::ownable::Ownable::InternalImpl; use openzeppelin::access::ownable::Ownable::OwnableCamelOnlyImpl; use openzeppelin::access::ownable::Ownable::OwnableImpl; -use openzeppelin::access::ownable::Ownable::OwnershipTransferred; use openzeppelin::access::ownable::Ownable::Ownable_owner::InternalContractMemberStateTrait; +use openzeppelin::access::ownable::Ownable::OwnershipTransferred; use openzeppelin::access::ownable::Ownable; use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; use openzeppelin::tests::utils; diff --git a/src/tests/account/test_account.cairo b/src/tests/account/test_account.cairo index 2ca9550a8..92811652e 100644 --- a/src/tests/account/test_account.cairo +++ b/src/tests/account/test_account.cairo @@ -2,14 +2,14 @@ use openzeppelin::account::Account::OwnerAdded; use openzeppelin::account::Account::OwnerRemoved; use openzeppelin::account::Account::PublicKeyCamelImpl; use openzeppelin::account::Account::PublicKeyImpl; +use openzeppelin::account::Account::{TRANSACTION_VERSION, QUERY_VERSION}; use openzeppelin::account::Account; use openzeppelin::account::AccountABIDispatcher; use openzeppelin::account::AccountABIDispatcherTrait; -use openzeppelin::account::Account::{TRANSACTION_VERSION, QUERY_VERSION}; use openzeppelin::account::interface::ISRC6_ID; use openzeppelin::introspection::interface::ISRC5_ID; -use openzeppelin::tests::utils; use openzeppelin::tests::utils::constants::ZERO; +use openzeppelin::tests::utils; use openzeppelin::token::erc20::ERC20; use openzeppelin::token::erc20::interface::IERC20Dispatcher; use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; diff --git a/src/tests/introspection/test_dual_src5.cairo b/src/tests/introspection/test_dual_src5.cairo index 9720e8968..80c13e56a 100644 --- a/src/tests/introspection/test_dual_src5.cairo +++ b/src/tests/introspection/test_dual_src5.cairo @@ -1,9 +1,5 @@ use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; -use openzeppelin::introspection::interface::ISRC5CamelDispatcher; -use openzeppelin::introspection::interface::ISRC5CamelDispatcherTrait; -use openzeppelin::introspection::interface::ISRC5Dispatcher; -use openzeppelin::introspection::interface::ISRC5DispatcherTrait; use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::mocks::src5_mocks::CamelSRC5Mock; diff --git a/src/tests/introspection/test_src5.cairo b/src/tests/introspection/test_src5.cairo index a8ca2b699..70b9f87a3 100644 --- a/src/tests/introspection/test_src5.cairo +++ b/src/tests/introspection/test_src5.cairo @@ -1,25 +1,26 @@ -use openzeppelin::introspection::interface::ISRC5_ID; -use openzeppelin::introspection::src5::SRC5::InternalImpl; -use openzeppelin::introspection::src5::SRC5::SRC5Impl; -use openzeppelin::introspection::src5::SRC5; +use openzeppelin::introspection::interface::{ISRC5_ID, ISRC5, ISRC5Camel}; +use openzeppelin::introspection::src5::SRC5::InternalTrait; +use openzeppelin::tests::mocks::src5_mocks::DualCaseSRC5Mock; const OTHER_ID: felt252 = 0x12345678; -fn STATE() -> SRC5::ContractState { - SRC5::contract_state_for_testing() +fn STATE() -> DualCaseSRC5Mock::ContractState { + DualCaseSRC5Mock::contract_state_for_testing() } #[test] #[available_gas(2000000)] fn test_default_behavior() { - let supports_default_interface = SRC5Impl::supports_interface(@STATE(), ISRC5_ID); + let state = @STATE(); + let supports_default_interface = state.src5.supports_interface(ISRC5_ID); assert(supports_default_interface, 'Should support base interface'); } #[test] #[available_gas(2000000)] fn test_not_registered_interface() { - let supports_unregistered_interface = SRC5Impl::supports_interface(@STATE(), OTHER_ID); + let state = @STATE(); + let supports_unregistered_interface = state.src5.supports_interface(OTHER_ID); assert(!supports_unregistered_interface, 'Should not support unregistered'); } @@ -27,8 +28,8 @@ fn test_not_registered_interface() { #[available_gas(2000000)] fn test_register_interface() { let mut state = STATE(); - InternalImpl::register_interface(ref state, OTHER_ID); - let supports_new_interface = SRC5Impl::supports_interface(@state, OTHER_ID); + state.src5.register_interface(OTHER_ID); + let supports_new_interface = state.src5.supports_interface(OTHER_ID); assert(supports_new_interface, 'Should support new interface'); } @@ -36,9 +37,9 @@ fn test_register_interface() { #[available_gas(2000000)] fn test_deregister_interface() { let mut state = STATE(); - InternalImpl::register_interface(ref state, OTHER_ID); - InternalImpl::deregister_interface(ref state, OTHER_ID); - let supports_old_interface = SRC5Impl::supports_interface(@state, OTHER_ID); + state.src5.register_interface(OTHER_ID); + state.src5.deregister_interface(OTHER_ID); + let supports_old_interface = state.src5.supports_interface(OTHER_ID); assert(!supports_old_interface, 'Should not support interface'); } @@ -47,5 +48,5 @@ fn test_deregister_interface() { #[should_panic(expected: ('SRC5: invalid id',))] fn test_deregister_default_interface() { let mut state = STATE(); - InternalImpl::deregister_interface(ref state, ISRC5_ID); + state.src5.deregister_interface(ISRC5_ID); } diff --git a/src/tests/mocks/dual721_receiver_mocks.cairo b/src/tests/mocks/dual721_receiver_mocks.cairo index a6e4f5f2a..ff0d65f3e 100644 --- a/src/tests/mocks/dual721_receiver_mocks.cairo +++ b/src/tests/mocks/dual721_receiver_mocks.cairo @@ -4,18 +4,32 @@ use openzeppelin::tests::mocks::erc721_receiver::ERC721Receiver; #[starknet::contract] mod SnakeERC721ReceiverMock { + use openzeppelin::introspection::src5::SRC5 as src5_component; use starknet::ContractAddress; use super::ERC721Receiver; use super::IERC721_RECEIVER_ID; - use super::SRC5; + + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl InternalImpl = src5_component::InternalImpl; #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + SRC5Event: src5_component::Event + } #[constructor] fn constructor(ref self: ContractState) { - let mut unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::InternalImpl::register_interface(ref unsafe_state, IERC721_RECEIVER_ID); + self.src5.register_interface(IERC721_RECEIVER_ID); } #[external(v0)] @@ -29,28 +43,36 @@ mod SnakeERC721ReceiverMock { let unsafe_state = ERC721Receiver::unsafe_new_contract_state(); ERC721Receiver::on_erc721_received(@unsafe_state, operator, from, token_id, data) } - - #[external(v0)] - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - let unsafe_state = ERC721Receiver::unsafe_new_contract_state(); - ERC721Receiver::supports_interface(@unsafe_state, interface_id) - } } #[starknet::contract] mod CamelERC721ReceiverMock { + use openzeppelin::introspection::src5::SRC5 as src5_component; use starknet::ContractAddress; use super::ERC721Receiver; use super::IERC721_RECEIVER_ID; - use super::SRC5; + + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5CamelImpl = src5_component::SRC5CamelImpl; + impl InternalImpl = src5_component::InternalImpl; #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + SRC5Event: src5_component::Event + } #[constructor] fn constructor(ref self: ContractState) { - let mut unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::InternalImpl::register_interface(ref unsafe_state, IERC721_RECEIVER_ID); + self.src5.register_interface(IERC721_RECEIVER_ID); } #[external(v0)] @@ -64,12 +86,6 @@ mod CamelERC721ReceiverMock { let unsafe_state = ERC721Receiver::unsafe_new_contract_state(); ERC721Receiver::on_erc721_received(@unsafe_state, operator, from, tokenId, data) } - - #[external(v0)] - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - let unsafe_state = ERC721Receiver::unsafe_new_contract_state(); - ERC721Receiver::supportsInterface(@unsafe_state, interfaceId) - } } #[starknet::contract] diff --git a/src/tests/mocks/erc721_receiver.cairo b/src/tests/mocks/erc721_receiver.cairo index 240246019..b65082c8c 100644 --- a/src/tests/mocks/erc721_receiver.cairo +++ b/src/tests/mocks/erc721_receiver.cairo @@ -4,32 +4,47 @@ use openzeppelin::tests::utils::constants::{FAILURE, SUCCESS}; mod ERC721Receiver { use openzeppelin::introspection::interface::ISRC5; use openzeppelin::introspection::interface::ISRC5Camel; + use openzeppelin::introspection::src5::SRC5 as src5_component; use openzeppelin::introspection::src5::SRC5; use openzeppelin::token::erc721::interface::IERC721Receiver; use openzeppelin::token::erc721::interface::IERC721ReceiverCamel; use openzeppelin::token::erc721::interface::IERC721_RECEIVER_ID; use starknet::ContractAddress; + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + #[abi(embed_v0)] + impl SRC5CamelImpl = src5_component::SRC5CamelImpl; + impl InternalImpl = src5_component::InternalImpl; + #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + SRC5Event: src5_component::Event + } #[constructor] fn constructor(ref self: ContractState) { - let mut unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::InternalImpl::register_interface(ref unsafe_state, IERC721_RECEIVER_ID); + self.src5.register_interface(IERC721_RECEIVER_ID); } impl ISRC5Impl of ISRC5 { fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - let unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) + self.src5.supports_interface(interface_id) } } impl ISRC5CamelImpl of ISRC5Camel { fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - let unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) + self.src5.supportsInterface(interfaceId) } } @@ -61,16 +76,6 @@ mod ERC721Receiver { } } - #[external(v0)] - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - ISRC5Impl::supports_interface(self, interface_id) - } - - #[external(v0)] - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - ISRC5CamelImpl::supportsInterface(self, interfaceId) - } - #[external(v0)] fn on_erc721_received( self: @ContractState, diff --git a/src/tests/mocks/src5_mocks.cairo b/src/tests/mocks/src5_mocks.cairo index cebdd0910..d325d39e9 100644 --- a/src/tests/mocks/src5_mocks.cairo +++ b/src/tests/mocks/src5_mocks.cairo @@ -1,26 +1,71 @@ use openzeppelin::introspection::src5::SRC5; +#[starknet::contract] +mod DualCaseSRC5Mock { + use openzeppelin::introspection::src5::SRC5 as src5_component; + + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + #[abi(embed_v0)] + impl SRC5CamelOnlyImpl = src5_component::SRC5CamelImpl; + impl InternalImpl = src5_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + SRC5Event: src5_component::Event + } +} + #[starknet::contract] mod SnakeSRC5Mock { + use openzeppelin::introspection::src5::SRC5 as src5_component; + + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage + } - #[external(v0)] - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - let unsafe_state = super::SRC5::unsafe_new_contract_state(); - super::SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + SRC5Event: src5_component::Event } } #[starknet::contract] mod CamelSRC5Mock { + use openzeppelin::introspection::src5::SRC5 as src5_component; + + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5CamelImpl = src5_component::SRC5CamelImpl; + #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage + } - #[external(v0)] - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - let unsafe_state = super::SRC5::unsafe_new_contract_state(); - super::SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + SRC5Event: src5_component::Event } } diff --git a/src/tests/mocks/upgrades_v1.cairo b/src/tests/mocks/upgrades_v1.cairo index 37d5c19b3..eec4cca81 100644 --- a/src/tests/mocks/upgrades_v1.cairo +++ b/src/tests/mocks/upgrades_v1.cairo @@ -21,10 +21,10 @@ trait UpgradesV1Trait { #[starknet::contract] mod UpgradesV1 { use array::ArrayTrait; - use starknet::ClassHash; - use starknet::ContractAddress; use openzeppelin::upgrades::interface::IUpgradeable; use openzeppelin::upgrades::upgradeable::Upgradeable; + use starknet::ClassHash; + use starknet::ContractAddress; #[storage] struct Storage { diff --git a/src/tests/mocks/upgrades_v2.cairo b/src/tests/mocks/upgrades_v2.cairo index 322c47ba1..fc3749613 100644 --- a/src/tests/mocks/upgrades_v2.cairo +++ b/src/tests/mocks/upgrades_v2.cairo @@ -23,10 +23,10 @@ trait UpgradesV2Trait { #[starknet::contract] mod UpgradesV2 { use array::ArrayTrait; - use starknet::ClassHash; - use starknet::ContractAddress; use openzeppelin::upgrades::interface::IUpgradeable; use openzeppelin::upgrades::upgradeable::Upgradeable; + use starknet::ClassHash; + use starknet::ContractAddress; #[storage] struct Storage { diff --git a/src/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo index faf1fcfc6..f1aff256e 100644 --- a/src/tests/security/test_pausable.cairo +++ b/src/tests/security/test_pausable.cairo @@ -5,8 +5,8 @@ use openzeppelin::security::pausable::Pausable::Unpaused; use openzeppelin::security::pausable::Pausable; use openzeppelin::tests::utils::constants::{CALLER, ZERO}; use openzeppelin::tests::utils; -use starknet::contract_address_const; use starknet::ContractAddress; +use starknet::contract_address_const; use starknet::testing; // diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index 4299928f9..5687dca0a 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -20,8 +20,8 @@ use openzeppelin::token::erc721::ERC721::{ }; use openzeppelin::token::erc721::ERC721; use openzeppelin::token::erc721; -use starknet::contract_address_const; use starknet::ContractAddress; +use starknet::contract_address_const; use starknet::testing; // diff --git a/src/tests/upgrades/test_upgradeable.cairo b/src/tests/upgrades/test_upgradeable.cairo index c43f8518f..d96d936c5 100644 --- a/src/tests/upgrades/test_upgradeable.cairo +++ b/src/tests/upgrades/test_upgradeable.cairo @@ -1,8 +1,8 @@ use openzeppelin::tests::mocks::upgrades_v1::IUpgradesV1Dispatcher; use openzeppelin::tests::mocks::upgrades_v1::IUpgradesV1DispatcherTrait; +use openzeppelin::tests::mocks::upgrades_v1::UpgradesV1; use openzeppelin::tests::mocks::upgrades_v2::IUpgradesV2Dispatcher; use openzeppelin::tests::mocks::upgrades_v2::IUpgradesV2DispatcherTrait; -use openzeppelin::tests::mocks::upgrades_v1::UpgradesV1; use openzeppelin::tests::mocks::upgrades_v2::UpgradesV2; use openzeppelin::tests::utils::constants::{CLASS_HASH_ZERO, ZERO}; use openzeppelin::tests::utils; diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index e0ebeacb3..cb3224555 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -4,8 +4,8 @@ use array::ArrayTrait; use array::SpanTrait; use core::result::ResultTrait; use option::OptionTrait; -use starknet::class_hash::Felt252TryIntoClassHash; use starknet::ContractAddress; +use starknet::class_hash::Felt252TryIntoClassHash; use starknet::testing; fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index d67952f2d..58bc0c495 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -6,16 +6,20 @@ mod ERC721 { use openzeppelin::account; use openzeppelin::introspection::dual_src5::DualCaseSRC5; use openzeppelin::introspection::dual_src5::DualCaseSRC5Trait; - use openzeppelin::introspection::interface::ISRC5; - use openzeppelin::introspection::interface::ISRC5Camel; - use openzeppelin::introspection::src5::unsafe_state as src5_state; - use openzeppelin::introspection::src5; + use openzeppelin::introspection::src5::SRC5 as src5_component; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721Receiver; use openzeppelin::token::erc721::dual721_receiver::DualCaseERC721ReceiverTrait; use openzeppelin::token::erc721::interface; use starknet::ContractAddress; use starknet::get_caller_address; + component!(path: src5_component, storage: src5, event: SRC5Event); + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + #[abi(embed_v0)] + impl SRC5CamelImpl = src5_component::SRC5CamelImpl; + impl SRC5InternalImpl = src5_component::InternalImpl; + #[storage] struct Storage { ERC721_name: felt252, @@ -25,6 +29,8 @@ mod ERC721 { ERC721_token_approvals: LegacyMap, ERC721_operator_approvals: LegacyMap<(ContractAddress, ContractAddress), bool>, ERC721_token_uri: LegacyMap, + #[substorage(v0)] + src5: src5_component::Storage } #[event] @@ -32,7 +38,8 @@ mod ERC721 { enum Event { Transfer: Transfer, Approval: Approval, - ApprovalForAll: ApprovalForAll + ApprovalForAll: ApprovalForAll, + SRC5Event: src5_component::Event } #[derive(Drop, starknet::Event)] @@ -85,20 +92,6 @@ mod ERC721 { // External // - #[external(v0)] - impl SRC5Impl of ISRC5 { - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - src5::SRC5::SRC5Impl::supports_interface(@src5_state(), interface_id) - } - } - - #[external(v0)] - impl SRC5CamelImpl of ISRC5Camel { - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - src5::SRC5::SRC5CamelImpl::supportsInterface(@src5_state(), interfaceId) - } - } - #[external(v0)] impl ERC721MetadataImpl of interface::IERC721Metadata { fn name(self: @ContractState) -> felt252 { @@ -236,11 +229,8 @@ mod ERC721 { self.ERC721_name.write(name); self.ERC721_symbol.write(symbol); - let mut unsafe_state = src5_state(); - src5::SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IERC721_ID); - src5::SRC5::InternalImpl::register_interface( - ref unsafe_state, interface::IERC721_METADATA_ID - ); + self.src5.register_interface(interface::IERC721_ID); + self.src5.register_interface(interface::IERC721_METADATA_ID); } fn _owner_of(self: @ContractState, token_id: u256) -> ContractAddress { @@ -352,7 +342,6 @@ mod ERC721 { } } - #[internal] fn _check_on_erc721_received( from: ContractAddress, to: ContractAddress, token_id: u256, data: Span ) -> bool { diff --git a/src/upgrades.cairo b/src/upgrades.cairo index 18d78fc73..5e4801d5b 100644 --- a/src/upgrades.cairo +++ b/src/upgrades.cairo @@ -1,2 +1,2 @@ -mod upgradeable; mod interface; +mod upgradeable; From 354a2cd46e024174699f0e7cc708a1a5ef09c28d Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 2 Oct 2023 12:16:27 +0200 Subject: [PATCH 103/124] fix: docs --- docs/modules/ROOT/pages/api/account.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 698aa9d36..74fd497c3 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -98,6 +98,10 @@ Account contract implementation extending xref:ISRC6[`ISRC6`]. * xref:#Account-\\__validate_declare__[`++__validate_declare__(self, class_hash)++`] +.PublicKeyImpl + +* xref:#Account-set_public_key[`++set_public_key(self, new_public_key)++`] +* xref:#Account-get_public_key[`++get_public_key(self)++`] -- [.contract-index] From ea0a956d5fcc9de59c6afaf277bbdb0df1c85954 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 2 Oct 2023 14:19:11 +0200 Subject: [PATCH 104/124] feat: add main logic with dependencies --- src/access/accesscontrol/accesscontrol.cairo | 10 +- src/tests/access/test_accesscontrol.cairo | 210 ++++++++---------- .../access/test_dual_accesscontrol.cairo | 8 +- src/tests/mocks.cairo | 3 - src/tests/mocks/accesscontrol_mocks.cairo | 209 +++++++++++++++++ .../mocks/accesscontrol_panic_mock.cairo | 87 -------- .../mocks/camel_accesscontrol_mock.cairo | 53 ----- .../mocks/snake_accesscontrol_mock.cairo | 53 ----- 8 files changed, 309 insertions(+), 324 deletions(-) create mode 100644 src/tests/mocks/accesscontrol_mocks.cairo delete mode 100644 src/tests/mocks/accesscontrol_panic_mock.cairo delete mode 100644 src/tests/mocks/camel_accesscontrol_mock.cairo delete mode 100644 src/tests/mocks/snake_accesscontrol_mock.cairo diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index e640a614c..33a723671 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -5,9 +5,8 @@ mod AccessControl { use openzeppelin::access::accesscontrol::interface; use openzeppelin::introspection::interface::ISRC5; - use openzeppelin::introspection::src5::SRC5::InternalTrait; + use openzeppelin::introspection::src5::SRC5::InternalTrait as SRC5InternalTrait; use openzeppelin::introspection::src5::SRC5; - use starknet::ContractAddress; use starknet::get_caller_address; @@ -68,7 +67,6 @@ mod AccessControl { impl AccessControl< TContractState, +HasComponent, - +ISRC5, +SRC5::HasComponent, +Drop > of interface::IAccessControl> { @@ -111,7 +109,6 @@ mod AccessControl { impl AccessControlCamel< TContractState, +HasComponent, - +ISRC5, +SRC5::HasComponent, +Drop > of interface::IAccessControlCamel> { @@ -147,13 +144,14 @@ mod AccessControl { impl InternalImpl< TContractState, +HasComponent, - +ISRC5, +SRC5::HasComponent, +Drop > of InternalTrait> { fn initializer(ref self: ComponentState) { let mut contract = self.get_contract_mut(); - let mut src5_component = SRC5::HasComponent::::get_component(@contract); + let mut src5_component = SRC5::HasComponent::< + TContractState + >::get_component_mut(ref contract); src5_component.register_interface(interface::IACCESSCONTROL_ID); } diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index d86dd4490..3e81628f0 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -1,31 +1,30 @@ -use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; -use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; use openzeppelin::access::accesscontrol::AccessControl::InternalImpl; use openzeppelin::access::accesscontrol::AccessControl::RoleAdminChanged; use openzeppelin::access::accesscontrol::AccessControl::RoleGranted; use openzeppelin::access::accesscontrol::AccessControl::RoleRevoked; -use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; +use openzeppelin::access::accesscontrol::interface::{IAccessControl, IAccessControlCamel}; +use openzeppelin::introspection::interface::{ISRC5, ISRC5Camel}; +use openzeppelin::tests::mocks::accesscontrol_mocks::DualCaseAccessControlMock; use openzeppelin::tests::utils::constants::{ ADMIN, AUTHORIZED, OTHER, OTHER_ADMIN, ROLE, OTHER_ROLE, ZERO }; use openzeppelin::tests::utils; use starknet::ContractAddress; -use starknet::contract_address_const; use starknet::testing; // // Setup // -fn STATE() -> AccessControl::ContractState { - AccessControl::contract_state_for_testing() +fn STATE() -> DualCaseAccessControlMock::ContractState { + DualCaseAccessControlMock::contract_state_for_testing() } -fn setup() -> AccessControl::ContractState { +fn setup() -> DualCaseAccessControlMock::ContractState { let mut state = STATE(); - InternalImpl::_grant_role(ref state, DEFAULT_ADMIN_ROLE, ADMIN()); + state.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, ADMIN()); utils::drop_event(ZERO()); state } @@ -38,11 +37,8 @@ fn setup() -> AccessControl::ContractState { #[available_gas(2000000)] fn test_initializer() { let mut state = STATE(); - InternalImpl::initializer(ref state); - assert( - AccessControl::SRC5Impl::supports_interface(@state, IACCESSCONTROL_ID), - 'Should support own interface' - ); + state.accesscontrol.initializer(); + assert(state.src5.supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); } // // supports_interface & supportsInterface @@ -52,22 +48,16 @@ fn test_initializer() { #[available_gas(2000000)] fn test_supports_interface() { let mut state = STATE(); - InternalImpl::initializer(ref state); - assert( - AccessControl::SRC5Impl::supports_interface(@state, IACCESSCONTROL_ID), - 'Should support own interface' - ); + state.accesscontrol.initializer(); + assert(state.src5.supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); } #[test] #[available_gas(2000000)] fn test_supportsInterface() { let mut state = STATE(); - InternalImpl::initializer(ref state); - assert( - AccessControl::SRC5CamelImpl::supportsInterface(@state, IACCESSCONTROL_ID), - 'Should support own interface' - ); + state.accesscontrol.initializer(); + assert(state.src5.supportsInterface(IACCESSCONTROL_ID), 'Should support own interface'); } // @@ -78,18 +68,18 @@ fn test_supportsInterface() { #[available_gas(2000000)] fn test_has_role() { let mut state = setup(); - assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'should not have role'); - InternalImpl::_grant_role(ref state, ROLE, AUTHORIZED()); - assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'should have role'); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'should not have role'); + state.accesscontrol._grant_role(ROLE, AUTHORIZED()); + assert(state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'should have role'); } #[test] #[available_gas(2000000)] fn test_hasRole() { let mut state = setup(); - assert(!AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'should not have role'); - InternalImpl::_grant_role(ref state, ROLE, AUTHORIZED()); - assert(AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'should have role'); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'should not have role'); + state.accesscontrol._grant_role(ROLE, AUTHORIZED()); + assert(state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'should have role'); } @@ -102,10 +92,10 @@ fn test_hasRole() { fn test_assert_only_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); testing::set_caller_address(AUTHORIZED()); - InternalImpl::assert_only_role(@state, ROLE); + state.accesscontrol.assert_only_role(ROLE); } #[test] @@ -114,7 +104,7 @@ fn test_assert_only_role() { fn test_assert_only_role_unauthorized() { let state = setup(); testing::set_caller_address(OTHER()); - InternalImpl::assert_only_role(@state, ROLE); + state.accesscontrol.assert_only_role(ROLE); } #[test] @@ -122,10 +112,10 @@ fn test_assert_only_role_unauthorized() { #[should_panic(expected: ('Caller is missing role',))] fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { let mut state = setup(); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); testing::set_caller_address(AUTHORIZED()); - InternalImpl::assert_only_role(@state, OTHER_ROLE); + state.accesscontrol.assert_only_role(OTHER_ROLE); } // @@ -137,10 +127,10 @@ fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { fn test_grant_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); assert_event_role_granted(ROLE, AUTHORIZED(), ADMIN()); - assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be granted'); + assert(state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should be granted'); } #[test] @@ -148,10 +138,10 @@ fn test_grant_role() { fn test_grantRole() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); assert_event_role_granted(ROLE, AUTHORIZED(), ADMIN()); - assert(AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be granted'); + assert(state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should be granted'); } #[test] @@ -160,9 +150,9 @@ fn test_grant_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be granted'); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + assert(state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should still be granted'); } #[test] @@ -171,11 +161,9 @@ fn test_grantRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - assert( - AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should still be granted' - ); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); + assert(state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should still be granted'); } #[test] @@ -184,7 +172,7 @@ fn test_grantRole_multiple_times_for_granted_role() { fn test_grant_role_unauthorized() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); } #[test] @@ -193,7 +181,7 @@ fn test_grant_role_unauthorized() { fn test_grantRole_unauthorized() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); } // @@ -205,7 +193,7 @@ fn test_grantRole_unauthorized() { fn test_revoke_role_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); } #[test] @@ -213,7 +201,7 @@ fn test_revoke_role_for_role_not_granted() { fn test_revokeRole_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); } #[test] @@ -222,13 +210,13 @@ fn test_revoke_role_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); utils::drop_event(ZERO()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), ADMIN()); - assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be revoked'); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should be revoked'); } #[test] @@ -237,13 +225,13 @@ fn test_revokeRole_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); utils::drop_event(ZERO()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), ADMIN()); - assert(!AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be revoked'); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should be revoked'); } #[test] @@ -252,12 +240,10 @@ fn test_revoke_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be revoked' - ); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should still be revoked'); } #[test] @@ -266,12 +252,10 @@ fn test_revokeRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should still be revoked' - ); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should still be revoked'); } #[test] @@ -280,7 +264,7 @@ fn test_revokeRole_multiple_times_for_granted_role() { fn test_revoke_role_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); } #[test] @@ -289,7 +273,7 @@ fn test_revoke_role_unauthorized() { fn test_revokeRole_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); } // @@ -301,7 +285,7 @@ fn test_revokeRole_unauthorized() { fn test_renounce_role_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); } #[test] @@ -309,7 +293,7 @@ fn test_renounce_role_for_role_not_granted() { fn test_renounceRole_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); } #[test] @@ -318,14 +302,14 @@ fn test_renounce_role_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); utils::drop_event(ZERO()); testing::set_caller_address(AUTHORIZED()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), AUTHORIZED()); - assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be renounced'); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should be renounced'); } #[test] @@ -334,16 +318,14 @@ fn test_renounceRole_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); utils::drop_event(ZERO()); testing::set_caller_address(AUTHORIZED()); - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), AUTHORIZED()); - assert( - !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be renounced' - ); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should be renounced'); } #[test] @@ -351,14 +333,12 @@ fn test_renounceRole_for_granted_role() { fn test_renounce_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); testing::set_caller_address(AUTHORIZED()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be renounced' - ); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should still be renounced'); } #[test] @@ -366,15 +346,12 @@ fn test_renounce_role_multiple_times_for_granted_role() { fn test_renounceRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); testing::set_caller_address(AUTHORIZED()); - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), - 'Role should still be renounced' - ); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should still be renounced'); } #[test] @@ -383,10 +360,10 @@ fn test_renounceRole_multiple_times_for_granted_role() { fn test_renounce_role_unauthorized() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); testing::set_caller_address(ZERO()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); } #[test] @@ -395,10 +372,10 @@ fn test_renounce_role_unauthorized() { fn test_renounceRole_unauthorized() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); // Admin is unauthorized caller - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); } // @@ -410,15 +387,14 @@ fn test_renounceRole_unauthorized() { fn test__set_role_admin() { let mut state = setup(); assert( - AccessControlImpl::get_role_admin(@state, ROLE) == DEFAULT_ADMIN_ROLE, + state.accesscontrol.get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'ROLE admin default should be 0' ); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); assert_event_role_admin_changed(ROLE, DEFAULT_ADMIN_ROLE, OTHER_ROLE); assert( - AccessControlImpl::get_role_admin(@state, ROLE) == OTHER_ROLE, - 'ROLE admin should be OTHER_ROLE' + state.accesscontrol.get_role_admin(ROLE) == OTHER_ROLE, 'ROLE admin should be OTHER_ROLE' ); } @@ -426,31 +402,29 @@ fn test__set_role_admin() { #[available_gas(2000000)] fn test_new_admin_can_grant_roles() { let mut state = setup(); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, OTHER_ROLE, OTHER_ADMIN()); + state.accesscontrol.grant_role(OTHER_ROLE, OTHER_ADMIN()); testing::set_caller_address(OTHER_ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'AUTHORIZED should have ROLE'); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + assert(state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should have ROLE'); } #[test] #[available_gas(2000000)] fn test_new_admin_can_revoke_roles() { let mut state = setup(); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, OTHER_ROLE, OTHER_ADMIN()); + state.accesscontrol.grant_role(OTHER_ROLE, OTHER_ADMIN()); testing::set_caller_address(OTHER_ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'AUTHORIZED should not have ROLE' - ); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should not have ROLE'); } #[test] @@ -458,9 +432,9 @@ fn test_new_admin_can_revoke_roles() { #[should_panic(expected: ('Caller is missing role',))] fn test_previous_admin_cannot_grant_roles() { let mut state = setup(); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); } #[test] @@ -468,9 +442,9 @@ fn test_previous_admin_cannot_grant_roles() { #[should_panic(expected: ('Caller is missing role',))] fn test_previous_admin_cannot_revoke_roles() { let mut state = setup(); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); testing::set_caller_address(ADMIN()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); } // @@ -482,7 +456,7 @@ fn test_previous_admin_cannot_revoke_roles() { fn test_other_role_admin_is_the_default_admin_role() { let state = setup(); assert( - AccessControlImpl::get_role_admin(@state, OTHER_ROLE) == DEFAULT_ADMIN_ROLE, + state.accesscontrol.get_role_admin(OTHER_ROLE) == DEFAULT_ADMIN_ROLE, 'Should be DEFAULT_ADMIN_ROLE' ); } @@ -492,7 +466,7 @@ fn test_other_role_admin_is_the_default_admin_role() { fn test_default_admin_role_is_its_own_admin() { let state = setup(); assert( - AccessControlImpl::get_role_admin(@state, DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE, + state.accesscontrol.get_role_admin(DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE, 'Should be DEFAULT_ADMIN_ROLE' ); } diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index 5a666a6db..5c61e4d36 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -6,11 +6,11 @@ use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatche use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::CamelAccessControlPanicMock; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; -use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; +use openzeppelin::tests::mocks::accesscontrol_mocks::{ + CamelAccessControlMock, SnakeAccessControlMock, CamelAccessControlPanicMock, + SnakeAccessControlPanicMock +}; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; -use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; use openzeppelin::tests::utils::constants::{ADMIN, AUTHORIZED, ROLE}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; diff --git a/src/tests/mocks.cairo b/src/tests/mocks.cairo index de3d1adee..e770f6479 100644 --- a/src/tests/mocks.cairo +++ b/src/tests/mocks.cairo @@ -1,9 +1,7 @@ mod accesscontrol_mocks; -mod accesscontrol_panic_mock; mod account_panic_mock; mod camel20_mock; mod camel721_mock; -mod camel_accesscontrol_mock; mod camel_account_mock; mod dual721_receiver_mocks; mod dual_ownable_mocks; @@ -15,7 +13,6 @@ mod reentrancy_attacker_mock; mod reentrancy_mock; mod snake20_mock; mod snake721_mock; -mod snake_accesscontrol_mock; mod snake_account_mock; mod src5_mocks; mod upgrades_v1; diff --git a/src/tests/mocks/accesscontrol_mocks.cairo b/src/tests/mocks/accesscontrol_mocks.cairo new file mode 100644 index 000000000..099335699 --- /dev/null +++ b/src/tests/mocks/accesscontrol_mocks.cairo @@ -0,0 +1,209 @@ +#[starknet::contract] +mod DualCaseAccessControlMock { + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::introspection::src5::SRC5 as src5_component; + use starknet::ContractAddress; + + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl AccessControlCamelImpl = + accesscontrol_component::AccessControlCamelImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage, + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, admin: ContractAddress) { + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin); + } +} + +#[starknet::contract] +mod SnakeAccessControlMock { + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::introspection::src5::SRC5 as src5_component; + use starknet::ContractAddress; + + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage, + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, admin: ContractAddress) { + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin); + } +} + +#[starknet::contract] +mod CamelAccessControlMock { + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::introspection::src5::SRC5 as src5_component; + use starknet::ContractAddress; + + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlCamelImpl = + accesscontrol_component::AccessControlCamelImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage, + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, admin: ContractAddress) { + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin); + } +} + +// Although these modules are designed to panic, functions +// still need a valid return value. We chose: +// +// 3 for felt252 +// false for bool + +#[starknet::contract] +mod SnakeAccessControlPanicMock { + use starknet::ContractAddress; + + #[storage] + struct Storage {} + + #[external(v0)] + fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + panic_with_felt252('Some error'); + false + } + + #[external(v0)] + fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[external(v0)] + fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + panic_with_felt252('Some error'); + false + } +} + +#[starknet::contract] +mod CamelAccessControlPanicMock { + use starknet::ContractAddress; + + #[storage] + struct Storage {} + + #[external(v0)] + fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + panic_with_felt252('Some error'); + false + } + + #[external(v0)] + fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[external(v0)] + fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + panic_with_felt252('Some error'); + false + } +} diff --git a/src/tests/mocks/accesscontrol_panic_mock.cairo b/src/tests/mocks/accesscontrol_panic_mock.cairo deleted file mode 100644 index 8ccfe80dc..000000000 --- a/src/tests/mocks/accesscontrol_panic_mock.cairo +++ /dev/null @@ -1,87 +0,0 @@ -// Although these modules are designed to panic, functions -// still need a valid return value. We chose: -// -// 3 for felt252 -// false for bool - -#[starknet::contract] -mod SnakeAccessControlPanicMock { - use starknet::ContractAddress; - - #[storage] - struct Storage {} - - #[external(v0)] - fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - panic_with_felt252('Some error'); - false - } - - #[external(v0)] - fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { - panic_with_felt252('Some error'); - 3 - } - - #[external(v0)] - fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - panic_with_felt252('Some error'); - false - } -} - -#[starknet::contract] -mod CamelAccessControlPanicMock { - use starknet::ContractAddress; - - #[storage] - struct Storage {} - - #[external(v0)] - fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - panic_with_felt252('Some error'); - false - } - - #[external(v0)] - fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { - panic_with_felt252('Some error'); - 3 - } - - #[external(v0)] - fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - panic_with_felt252('Some error'); - false - } -} diff --git a/src/tests/mocks/camel_accesscontrol_mock.cairo b/src/tests/mocks/camel_accesscontrol_mock.cairo deleted file mode 100644 index 09e2fbf92..000000000 --- a/src/tests/mocks/camel_accesscontrol_mock.cairo +++ /dev/null @@ -1,53 +0,0 @@ -#[starknet::contract] -mod CamelAccessControlMock { - use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; - use openzeppelin::access::accesscontrol::AccessControl; - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; - use starknet::ContractAddress; - - #[storage] - struct Storage {} - - #[constructor] - fn constructor(ref self: ContractState, admin: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref unsafe_state); - AccessControl::InternalImpl::_grant_role(ref unsafe_state, DEFAULT_ADMIN_ROLE, admin); - } - - #[external(v0)] - fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::hasRole(@unsafe_state, role, account) - } - - #[external(v0)] - fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::getRoleAdmin(@unsafe_state, role) - } - - #[external(v0)] - fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::grantRole(ref unsafe_state, role, account); - } - - #[external(v0)] - fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::revokeRole(ref unsafe_state, role, account); - } - - #[external(v0)] - fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::renounceRole(ref unsafe_state, role, account); - } - - #[external(v0)] - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) - } -} diff --git a/src/tests/mocks/snake_accesscontrol_mock.cairo b/src/tests/mocks/snake_accesscontrol_mock.cairo deleted file mode 100644 index 614b00627..000000000 --- a/src/tests/mocks/snake_accesscontrol_mock.cairo +++ /dev/null @@ -1,53 +0,0 @@ -#[starknet::contract] -mod SnakeAccessControlMock { - use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; - use openzeppelin::access::accesscontrol::AccessControl; - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; - use starknet::ContractAddress; - - #[storage] - struct Storage {} - - #[constructor] - fn constructor(ref self: ContractState, admin: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref unsafe_state); - AccessControl::InternalImpl::_grant_role(ref unsafe_state, DEFAULT_ADMIN_ROLE, admin); - } - - #[external(v0)] - fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::has_role(@unsafe_state, role, account) - } - - #[external(v0)] - fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::get_role_admin(@unsafe_state, role) - } - - #[external(v0)] - fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::grant_role(ref unsafe_state, role, account); - } - - #[external(v0)] - fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::revoke_role(ref unsafe_state, role, account); - } - - #[external(v0)] - fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::renounce_role(ref unsafe_state, role, account); - } - - #[external(v0)] - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::SRC5Impl::supports_interface(@unsafe_state, interface_id) - } -} From 9a274be93db55e8795b579f6689bfeea1d315c85 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 5 Oct 2023 18:20:59 -0400 Subject: [PATCH 105/124] feat: apply review updates --- src/introspection/src5.cairo | 8 ++------ src/tests/introspection/test_src5.cairo | 2 +- src/tests/mocks/erc721_receiver.cairo | 12 ------------ 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/introspection/src5.cairo b/src/introspection/src5.cairo index 6918c36d4..eeb919dc8 100644 --- a/src/introspection/src5.cairo +++ b/src/introspection/src5.cairo @@ -37,9 +37,10 @@ mod SRC5 { } } + #[generate_trait] impl InternalImpl< TContractState, +HasComponent - > of InternalTrait> { + > of InternalTrait { fn register_interface(ref self: ComponentState, interface_id: felt252) { self.SRC5_supported_interfaces.write(interface_id, true); } @@ -49,9 +50,4 @@ mod SRC5 { self.SRC5_supported_interfaces.write(interface_id, false); } } - - trait InternalTrait { - fn register_interface(ref self: TContractState, interface_id: felt252); - fn deregister_interface(ref self: TContractState, interface_id: felt252); - } } diff --git a/src/tests/introspection/test_src5.cairo b/src/tests/introspection/test_src5.cairo index 70b9f87a3..7c8023d29 100644 --- a/src/tests/introspection/test_src5.cairo +++ b/src/tests/introspection/test_src5.cairo @@ -1,4 +1,4 @@ -use openzeppelin::introspection::interface::{ISRC5_ID, ISRC5, ISRC5Camel}; +use openzeppelin::introspection::interface::{ISRC5_ID, ISRC5}; use openzeppelin::introspection::src5::SRC5::InternalTrait; use openzeppelin::tests::mocks::src5_mocks::DualCaseSRC5Mock; diff --git a/src/tests/mocks/erc721_receiver.cairo b/src/tests/mocks/erc721_receiver.cairo index b65082c8c..13f3037d4 100644 --- a/src/tests/mocks/erc721_receiver.cairo +++ b/src/tests/mocks/erc721_receiver.cairo @@ -36,18 +36,6 @@ mod ERC721Receiver { self.src5.register_interface(IERC721_RECEIVER_ID); } - impl ISRC5Impl of ISRC5 { - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - self.src5.supports_interface(interface_id) - } - } - - impl ISRC5CamelImpl of ISRC5Camel { - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - self.src5.supportsInterface(interfaceId) - } - } - impl ERC721ReceiverImpl of IERC721Receiver { fn on_erc721_received( self: @ContractState, From f0d8c6fa08d270a07944f4a2ea980e9e2b3165b8 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 5 Oct 2023 18:36:41 -0400 Subject: [PATCH 106/124] feat: remove unnecesary imports --- src/tests/utils.cairo | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index 6a6468eef..d8546c289 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -1,9 +1,5 @@ mod constants; -use array::ArrayTrait; -use array::SpanTrait; -use core::result::ResultTrait; -use option::OptionTrait; use starknet::ContractAddress; use starknet::class_hash::Felt252TryIntoClassHash; use starknet::testing; From cb5b828f0eeee00ef058cb4b0f593046bebddbab Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 5 Oct 2023 18:43:37 -0400 Subject: [PATCH 107/124] feat: add in-code comments --- src/introspection/src5.cairo | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/introspection/src5.cairo b/src/introspection/src5.cairo index eeb919dc8..1c2529771 100644 --- a/src/introspection/src5.cairo +++ b/src/introspection/src5.cairo @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (introspection/src5.cairo) - +/// +/// # SRC5 Component +/// +/// The SRC5 component allows contracts to expose the interfaces they implement. #[starknet::component] mod SRC5 { use openzeppelin::introspection::interface; @@ -18,6 +21,7 @@ mod SRC5 { impl SRC5< TContractState, +HasComponent > of interface::ISRC5> { + /// Returns whether the contract implements the given interface. fn supports_interface( self: @ComponentState, interface_id: felt252 ) -> bool { @@ -41,10 +45,12 @@ mod SRC5 { impl InternalImpl< TContractState, +HasComponent > of InternalTrait { + /// Registers the given interface as supported by the contract. fn register_interface(ref self: ComponentState, interface_id: felt252) { self.SRC5_supported_interfaces.write(interface_id, true); } + /// Deregisters the given interface as supported by the contract. fn deregister_interface(ref self: ComponentState, interface_id: felt252) { assert(interface_id != interface::ISRC5_ID, Errors::INVALID_ID); self.SRC5_supported_interfaces.write(interface_id, false); From 09c47ad1bd8bf773108ae4a10815685f6dbbea42 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 6 Oct 2023 11:15:28 -0400 Subject: [PATCH 108/124] feat: apply review updates --- .../modules/ROOT/pages/api/introspection.adoc | 8 +++--- docs/modules/ROOT/pages/introspection.adoc | 28 +++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/docs/modules/ROOT/pages/api/introspection.adoc b/docs/modules/ROOT/pages/api/introspection.adoc index 2e58603b6..c43b2a99c 100644 --- a/docs/modules/ROOT/pages/api/introspection.adoc +++ b/docs/modules/ROOT/pages/api/introspection.adoc @@ -50,10 +50,10 @@ on how to compute this ID. use openzeppelin::introspection::src5::SRC5; ``` -SRC5 contract implementation extending xref:ISRC5[`ISRC5`]. +SRC5 component extending xref:ISRC5[`ISRC5`]. [.contract-index] -.External Functions +.Embeddable Implementations -- .SRC5Impl @@ -69,8 +69,8 @@ SRC5 contract implementation extending xref:ISRC5[`ISRC5`]. * xref:#SRC5-deregister_interface[`++deregister_interface(self, interface_id)++`] -- -[#SRC5-External-Functions] -==== External Functions +[#SRC5-Embeddable-Implementations-Functions] +==== Embeddable Implementations Functions [.contract-item] [[SRC5-supports_interface]] diff --git a/docs/modules/ROOT/pages/introspection.adoc b/docs/modules/ROOT/pages/introspection.adoc index 9c162374b..896fabaa7 100644 --- a/docs/modules/ROOT/pages/introspection.adoc +++ b/docs/modules/ROOT/pages/introspection.adoc @@ -35,24 +35,37 @@ extended function selectors. There are tools such as {src5-rs} that can help wit === Registering interfaces -For a contract to declare its support for a given interface, the contract should import the SRC5 module and -register its support. It's recommended to register interface support upon contract deployment through a constructor -either directly or indirectly (as an initializer) like this: +For a contract to declare its support for a given interface, we recommend using the the SRC5 component to do it upon contract deployment through a constructor either directly or indirectly (as an initializer) like this: [,javascript] ---- #[starknet::contract] mod MyContract { use openzeppelin::account::interface; - use openzeppelin::introspection::src5::SRC5; + use openzeppelin::introspection::src5::SRC5 as src5_component; + + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl InternalImpl = src5_component::InternalImpl; #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + src5: src5_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + SRC5Event: src5_component::Event + } #[constructor] fn constructor(ref self: ContractState) { - let mut unsafe_state = SRC5::unsafe_new_contract_state(); - SRC5::InternalImpl::register_interface(ref unsafe_state, interface::ISRC6_ID); + // Register the contract's support for the ISRC6 interface + self.src5.register_interface(interface::ISRC6_ID); } (...) @@ -70,7 +83,6 @@ mod MyContract { use openzeppelin::account::interface; use openzeppelin::introspection::interface::ISRC5DispatcherTrait; use openzeppelin::introspection::interface::ISRC5Dispatcher; - use openzeppelin::introspection::src5::SRC5; use starknet::ContractAddress; #[storage] From f090a838e126ebfec8eb4b830bf58d7111da8c62 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 6 Oct 2023 11:20:21 -0400 Subject: [PATCH 109/124] refactor: remove unnecessary trait --- src/access/accesscontrol/accesscontrol.cairo | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index 33a723671..4d33f9d54 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -141,12 +141,13 @@ mod AccessControl { } } + #[generate_trait] impl InternalImpl< TContractState, +HasComponent, +SRC5::HasComponent, +Drop - > of InternalTrait> { + > of InternalTrait { fn initializer(ref self: ComponentState) { let mut contract = self.get_contract_mut(); let mut src5_component = SRC5::HasComponent::< @@ -189,12 +190,4 @@ mod AccessControl { self.emit(RoleAdminChanged { role, previous_admin_role, new_admin_role: admin_role }); } } - - trait InternalTrait { - fn initializer(ref self: TContractState); - fn assert_only_role(self: @TContractState, role: felt252); - fn _grant_role(ref self: TContractState, role: felt252, account: ContractAddress); - fn _revoke_role(ref self: TContractState, role: felt252, account: ContractAddress); - fn _set_role_admin(ref self: TContractState, role: felt252, admin_role: felt252); - } } From 95706b1b2c73bc2b85283bb5e9e072ac87ad0a41 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 6 Oct 2023 11:44:42 -0400 Subject: [PATCH 110/124] feat: apply update reviews --- docs/modules/ROOT/pages/access.adoc | 39 ++++++++++++++++-------- docs/modules/ROOT/pages/api/access.adoc | 23 ++++++++++++-- src/access/ownable/ownable.cairo | 23 +++++++++----- src/tests/mocks/dual_ownable_mocks.cairo | 5 --- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index cf9b65989..fef478d83 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -19,26 +19,42 @@ OpenZeppelin Contracts for Cairo provides {ownable-cairo} for implementing owner === Usage -Integrating this module into a contract first requires assigning an owner. +Integrating this component into a contract first requires assigning an owner. The implementing contract's constructor should set the initial owner by passing the owner's address to Ownable's xref:/api/access.adoc#AccessControl-initializer[`initializer`] like this: [,javascript] ---- -use openzeppelin::access::ownable::Ownable; - #[starknet::contract] mod MyContract { + use openzeppelin::access::ownable::Ownable as ownable_component; use starknet::ContractAddress; - use super::Ownable; + + component!(path: ownable_component, storage: ownable, event: OwnableEvent); + + #[abi(embed_v0)] + impl OwnableImpl = ownable_component::OwnableImpl; + #[abi(embed_v0)] + impl OwnableCamelOnlyImpl = + ownable_component::OwnableCamelOnlyImpl; + impl InternalImpl = ownable_component::InternalImpl; #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + ownable: ownable_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + OwnableEvent: ownable_component::Event + } #[constructor] - fn constructor(self: @ContractState, owner: ContractAddress) { - let mut unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::InternalImpl::initializer(ref unsafe_state, owner); + fn constructor(ref self: ContractState, owner: ContractAddress) { + // Set the initial owner of the contract + self.ownable.initializer(owner); } (...) @@ -51,15 +67,12 @@ To restrict a function's access to the owner only, add in the `assert_only_owner ---- #[starknet::contract] mod MyContract { - use openzeppelin::access::ownable::Ownable; - (...) #[external(v0)] - fn foo(ref self: ContractState) { + fn only_owner_allowed(ref self: ContractState) { // This function can only be called by the owner - let unsafe_state = Ownable::unsafe_new_contract_state(); - Ownable::InternalImpl::assert_only_owner(@unsafe_state); + self.ownable.assert_only_owner(); (...) } diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 86fd86e4d..e3eec4fd8 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -30,13 +30,18 @@ use openzeppelin::access::ownable::Ownable; This module includes the `assert_only_owner` internal to restrict a function to be used only by the owner. [.contract-index] -.External Functions +.Embeddable Implementations Functions -- .OwnableImpl * xref:Ownable-owner[`++owner(self)++`] * xref:Ownable-transfer_ownership[`++transfer_ownership(self, new_owner)++`] * xref:Ownable-renounce_ownership[`++renounce_ownership(self)++`] + +.OwnableCamelOnlyImpl + +* xref:Ownable-transferOwnership[`++transferOwnership(self, newOwner)++`] +* xref:Ownable-renounceOwnership[`++renounceOwnership(self)++`] -- [.contract-index] @@ -55,8 +60,8 @@ This module includes the `assert_only_owner` internal to restrict a function to * xref:Ownable-OwnershipTransferred[`++OwnershipTransferred(previous_owner, new_owner)++`] -- -[#Ownable-External-Functions] -==== External Functions +[#Ownable-Embeddable-Implementations-Functions] +==== Embeddable Implementations Functions [.contract-item] [[Ownable-owner]] @@ -83,6 +88,18 @@ Leaves the contract without owner. It will not be possible to call NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner. +[.contract-item] +[[Ownable-transferOwnership]] +==== `[.contract-item-name]#++transferOwnership++#++(ref self: ContractState, newOwner: ContractAddress)++` [.item-kind]#external# + +See xref:Ownable-transfer_ownership[transfer_ownership]. + +[.contract-item] +[[Ownable-renounceOwnership]] +==== `[.contract-item-name]#++renounceOwnership++#++(ref self: ContractState)++` [.item-kind]#external# + +See xref:Ownable-renounce_ownership[renounce_ownership]. + [#Ownable-Internal-Functions] ==== Internal Functions diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index e5f1bd7e9..145df2740 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/ownable.cairo) - +// +// # Ownable Component +// +// The Ownable component provides basic authorization control functions from a single owner. #[starknet::component] mod Ownable { use openzeppelin::access::ownable::interface; @@ -34,10 +37,12 @@ mod Ownable { impl Ownable< TContractState, +HasComponent > of interface::IOwnable> { + /// Returns the address of the current owner. fn owner(self: @ComponentState) -> ContractAddress { self.Ownable_owner.read() } + /// Transfers ownership of the contract to a new address. fn transfer_ownership( ref self: ComponentState, new_owner: ContractAddress ) { @@ -46,6 +51,8 @@ mod Ownable { self._transfer_ownership(new_owner); } + /// Leaves the contract without owner. It will not be possible to call `assert_only_owner` + /// functions anymore. Can only be called by the current owner. fn renounce_ownership(ref self: ComponentState) { self.assert_only_owner(); self._transfer_ownership(Zeroable::zero()); @@ -65,13 +72,17 @@ mod Ownable { } } + #[generate_trait] impl InternalImpl< TContractState, +HasComponent - > of InternalTrait> { + > of InternalTrait { + /// Sets the contract's initial owner. This function should called at construction time. fn initializer(ref self: ComponentState, owner: ContractAddress) { self._transfer_ownership(owner); } + /// Panics if called by any account other than the owner. Use this + /// to restrict access to certain functions to the owner. fn assert_only_owner(self: @ComponentState) { let owner: ContractAddress = self.Ownable_owner.read(); let caller: ContractAddress = get_caller_address(); @@ -79,6 +90,8 @@ mod Ownable { assert(caller == owner, Errors::NOT_OWNER); } + /// Internal function that transfers ownership of the contract to a new address. + /// It doesn't assert the caller. fn _transfer_ownership( ref self: ComponentState, new_owner: ContractAddress ) { @@ -90,10 +103,4 @@ mod Ownable { ); } } - - trait InternalTrait { - fn initializer(ref self: TContractState, owner: ContractAddress); - fn assert_only_owner(self: @TContractState); - fn _transfer_ownership(ref self: TContractState, new_owner: ContractAddress); - } } diff --git a/src/tests/mocks/dual_ownable_mocks.cairo b/src/tests/mocks/dual_ownable_mocks.cairo index 82a7abb7a..81433d063 100644 --- a/src/tests/mocks/dual_ownable_mocks.cairo +++ b/src/tests/mocks/dual_ownable_mocks.cairo @@ -1,10 +1,7 @@ -use openzeppelin::access::ownable::Ownable; - #[starknet::contract] mod DualCaseOwnableMock { use openzeppelin::access::ownable::Ownable as ownable_component; use starknet::ContractAddress; - use super::Ownable; component!(path: ownable_component, storage: ownable, event: OwnableEvent); @@ -37,7 +34,6 @@ mod DualCaseOwnableMock { mod SnakeOwnableMock { use openzeppelin::access::ownable::Ownable as ownable_component; use starknet::ContractAddress; - use super::Ownable; component!(path: ownable_component, storage: ownable, event: OwnableEvent); @@ -67,7 +63,6 @@ mod SnakeOwnableMock { mod CamelOwnableMock { use openzeppelin::access::ownable::Ownable as ownable_component; use starknet::ContractAddress; - use super::Ownable; component!(path: ownable_component, storage: ownable, event: OwnableEvent); From 83c1203e8e4117076da9719025fb85b0655d2541 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 6 Oct 2023 12:11:15 -0400 Subject: [PATCH 111/124] refactor: remove imports --- src/access/ownable/dual_ownable.cairo | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/access/ownable/dual_ownable.cairo b/src/access/ownable/dual_ownable.cairo index de951a683..c53e1ce06 100644 --- a/src/access/ownable/dual_ownable.cairo +++ b/src/access/ownable/dual_ownable.cairo @@ -1,13 +1,11 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/dual_ownable.cairo) -// use openzeppelin::utils::Felt252TryIntoBool; use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use openzeppelin::utils::try_selector_with_fallback; use starknet::ContractAddress; -// use starknet::Felt252TryIntoContractAddress; use starknet::SyscallResultTrait; use starknet::call_contract_syscall; From 2ae81393a944a335e589bb5e97bf6b83fd2029bd Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 6 Oct 2023 17:13:21 -0400 Subject: [PATCH 112/124] Update src/access/ownable/ownable.cairo Co-authored-by: Andrew Fleming --- src/access/ownable/ownable.cairo | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index 145df2740..2eaeefda9 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/ownable.cairo) -// -// # Ownable Component -// -// The Ownable component provides basic authorization control functions from a single owner. +//! +//! # Ownable Component +//! +//! The Ownable component provides basic authorization-control functions from a single owner. #[starknet::component] mod Ownable { use openzeppelin::access::ownable::interface; From fb514e1aed7d3c1d882bcf0b809ac57933e5ba9a Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 6 Oct 2023 17:15:25 -0400 Subject: [PATCH 113/124] feat: apply review updates --- src/access/ownable/ownable.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index 145df2740..91402fd1f 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -76,7 +76,7 @@ mod Ownable { impl InternalImpl< TContractState, +HasComponent > of InternalTrait { - /// Sets the contract's initial owner. This function should called at construction time. + /// Sets the contract's initial owner. This function should be called at construction time. fn initializer(ref self: ComponentState, owner: ContractAddress) { self._transfer_ownership(owner); } From 54396a6a4a62795fcdf3ab13b2f7b7c8c6776e5c Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 6 Oct 2023 17:29:58 -0400 Subject: [PATCH 114/124] feat: add comments to camelCase functions --- src/access/ownable/ownable.cairo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index 2c93ce134..befe1a28b 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -63,10 +63,12 @@ mod Ownable { impl OwnableCamelOnly< TContractState, +HasComponent > of interface::IOwnableCamelOnly> { + /// camelCase support for `transfer_ownership`. fn transferOwnership(ref self: ComponentState, newOwner: ContractAddress) { self.transfer_ownership(newOwner); } + /// camelCase support for `renounce_ownership`. fn renounceOwnership(ref self: ComponentState) { self.renounce_ownership(); } From 3fc22bc275060e4b1b36b5a31e6ecb145b0a9a22 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 9 Oct 2023 12:00:17 -0400 Subject: [PATCH 115/124] fix: comment --- src/access/ownable/ownable.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index befe1a28b..ffe3000fe 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/ownable.cairo) +//! SPDX-License-Identifier: MIT +//! OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/ownable.cairo) //! //! # Ownable Component //! From 4f24b82a03330facc4efaf589ff3a7c7718f2829 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Tue, 10 Oct 2023 14:44:18 -0400 Subject: [PATCH 116/124] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index e3eec4fd8..17120509f 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -27,7 +27,7 @@ use openzeppelin::access::ownable::Ownable; `Ownable` provides a basic access control mechanism where an account (an owner) can be granted exclusive access to specific functions. -This module includes the `assert_only_owner` internal to restrict a function to be used only by the owner. +This module includes the internal `assert_only_owner` to restrict a function to be used only by the owner. [.contract-index] .Embeddable Implementations Functions From e112ba1135e4e57a0e4915320ce83edcffe1ac64 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 11 Oct 2023 12:28:29 -0400 Subject: [PATCH 117/124] feat: apply review updates --- src/access/ownable/ownable.cairo | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index ffe3000fe..1175b9749 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -1,9 +1,9 @@ -//! SPDX-License-Identifier: MIT -//! OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/ownable.cairo) -//! -//! # Ownable Component -//! -//! The Ownable component provides basic authorization-control functions from a single owner. +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.7.0 (access/ownable/ownable.cairo) + +/// # Ownable Component +/// +/// The Ownable component provides basic authorization-control functions from a single owner. #[starknet::component] mod Ownable { use openzeppelin::access::ownable::interface; @@ -63,12 +63,12 @@ mod Ownable { impl OwnableCamelOnly< TContractState, +HasComponent > of interface::IOwnableCamelOnly> { - /// camelCase support for `transfer_ownership`. + /// Adds camelCase support for `transfer_ownership`. fn transferOwnership(ref self: ComponentState, newOwner: ContractAddress) { self.transfer_ownership(newOwner); } - /// camelCase support for `renounce_ownership`. + /// Adds camelCase support for `renounce_ownership`. fn renounceOwnership(ref self: ComponentState) { self.renounce_ownership(); } From d13b688342f8d2069503f4b49cce57e681172897 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 11 Oct 2023 12:36:57 -0400 Subject: [PATCH 118/124] feat: update docs --- docs/modules/ROOT/pages/api/access.adoc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index c770e7432..71b017914 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -30,14 +30,18 @@ use openzeppelin::access::ownable::Ownable; This module includes the internal `assert_only_owner` to restrict a function to be used only by the owner. [.contract-index] -.Embeddable Implementations Functions +.Embeddable Functions -- .OwnableImpl * xref:Ownable-owner[`++owner(self)++`] * xref:Ownable-transfer_ownership[`++transfer_ownership(self, new_owner)++`] * xref:Ownable-renounce_ownership[`++renounce_ownership(self)++`] +-- +[.contract-index] +.camelCase Support +-- .OwnableCamelOnlyImpl * xref:Ownable-transferOwnership[`++transferOwnership(self, newOwner)++`] @@ -60,8 +64,8 @@ This module includes the internal `assert_only_owner` to restrict a function to * xref:Ownable-OwnershipTransferred[`++OwnershipTransferred(previous_owner, new_owner)++`] -- -[#Ownable-Embeddable-Implementations-Functions] -==== Embeddable Implementations Functions +[#Ownable-Embeddable-Functions] +==== Embeddable Functions [.contract-item] [[Ownable-owner]] @@ -88,6 +92,9 @@ Leaves the contract without owner. It will not be possible to call NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner. +[#Ownable-camelCase-Support] +==== camelCase Support + [.contract-item] [[Ownable-transferOwnership]] ==== `[.contract-item-name]#++transferOwnership++#++(ref self: ContractState, newOwner: ContractAddress)++` [.item-kind]#external# From 7ec2ce808d1627d166d1b9776d1c8ec652f6a71c Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 11 Oct 2023 13:16:34 -0400 Subject: [PATCH 119/124] docs: add in-code documentation --- src/access/accesscontrol/accesscontrol.cairo | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index a376aca5e..e314b0f67 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -1,6 +1,10 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/accesscontrol/accesscontrol.cairo) +/// # AccessControl Component + +/// The AccessControl component allows contracts to implement role-based access control mechanisms. +/// Roles are referred to by their `felt252` identifier: #[starknet::component] mod AccessControl { use openzeppelin::access::accesscontrol::interface; @@ -69,16 +73,25 @@ mod AccessControl { +SRC5::HasComponent, +Drop > of interface::IAccessControl> { + /// Returns whether `account` has been granted `role`. fn has_role( self: @ComponentState, role: felt252, account: ContractAddress ) -> bool { self.AccessControl_role_member.read((role, account)) } + /// Returns the admin role that controls `role`. fn get_role_admin(self: @ComponentState, role: felt252) -> felt252 { self.AccessControl_role_admin.read(role) } + /// Grants `role` to `account`. + /// + /// If `account` had not been already granted `role`, emits a `RoleGranted` event. + /// + /// Requirements: + /// + /// - the caller must have `role`'s admin role. fn grant_role( ref self: ComponentState, role: felt252, account: ContractAddress ) { @@ -87,6 +100,13 @@ mod AccessControl { self._grant_role(role, account); } + /// Revokes `role` from `account`. + /// + /// If `account` had been granted `role`, emits a `RoleRevoked` event. + /// + /// Requirements: + /// + /// - the caller must have `role`'s admin role. fn revoke_role( ref self: ComponentState, role: felt252, account: ContractAddress ) { @@ -95,6 +115,18 @@ mod AccessControl { self._revoke_role(role, account); } + /// Revokes `role` from the calling account. + /// + /// Roles are often managed via `grantRole` and `revokeRole`: this function's + /// purpose is to provide a mechanism for accounts to lose their privileges + /// if they are compromised (such as when a trusted device is misplaced). + /// + /// If the calling account had been revoked `role`, emits a `RoleRevoked` + /// event. + /// + /// Requirements: + /// + /// - the caller must be `account`. fn renounce_role( ref self: ComponentState, role: felt252, account: ContractAddress ) { @@ -104,6 +136,7 @@ mod AccessControl { } } + /// Adds camelCase support for `IAccessControl`. #[embeddable_as(AccessControlCamelImpl)] impl AccessControlCamel< TContractState, @@ -147,6 +180,7 @@ mod AccessControl { +SRC5::HasComponent, +Drop > of InternalTrait { + /// Initializes the contract by registering the IAccessControl interface Id. fn initializer(ref self: ComponentState) { let mut contract = self.get_contract_mut(); let mut src5_component = SRC5::HasComponent::< @@ -155,12 +189,18 @@ mod AccessControl { src5_component.register_interface(interface::IACCESSCONTROL_ID); } + /// Validates that the caller has the given role. Otherwise it panics. fn assert_only_role(self: @ComponentState, role: felt252) { let caller: ContractAddress = get_caller_address(); let authorized: bool = self.has_role(role, caller); assert(authorized, Errors::MISSING_ROLE); } + /// Attempts to grant `role` to `account`. + /// + /// Internal function without access restriction. + /// + /// May emit a `RoleGranted` event. fn _grant_role( ref self: ComponentState, role: felt252, account: ContractAddress ) { @@ -171,6 +211,11 @@ mod AccessControl { } } + /// Attempts to revoke `role` to `account`. + /// + /// Internal function without access restriction. + /// + /// May emit a `RoleRevoked` event. fn _revoke_role( ref self: ComponentState, role: felt252, account: ContractAddress ) { @@ -181,6 +226,9 @@ mod AccessControl { } } + /// Sets `admin_role` as `role`'s admin role. + /// + /// Emits a `RoleAdminChanged` event. fn _set_role_admin( ref self: ComponentState, role: felt252, admin_role: felt252 ) { From c823416d55663f8603569c33fee58f87bc3b98ae Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 11 Oct 2023 13:24:14 -0400 Subject: [PATCH 120/124] feat: update comments --- src/access/ownable/ownable.cairo | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index 1175b9749..d85e27f35 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -3,7 +3,12 @@ /// # Ownable Component /// -/// The Ownable component provides basic authorization-control functions from a single owner. +/// The Ownable component provides a basic access control mechanism, where +/// there is an account (an owner) that can be granted exclusive access to +/// specific functions. +/// +/// The initial owner can be set by using the `initializer` function in +/// construction time. This can later be changed with `transfer_ownership`. #[starknet::component] mod Ownable { use openzeppelin::access::ownable::interface; @@ -59,16 +64,15 @@ mod Ownable { } } + /// Adds camelCase support for `IOwnable`. #[embeddable_as(OwnableCamelOnlyImpl)] impl OwnableCamelOnly< TContractState, +HasComponent > of interface::IOwnableCamelOnly> { - /// Adds camelCase support for `transfer_ownership`. fn transferOwnership(ref self: ComponentState, newOwner: ContractAddress) { self.transfer_ownership(newOwner); } - /// Adds camelCase support for `renounce_ownership`. fn renounceOwnership(ref self: ComponentState) { self.renounce_ownership(); } @@ -78,7 +82,9 @@ mod Ownable { impl InternalImpl< TContractState, +HasComponent > of InternalTrait { - /// Sets the contract's initial owner. This function should be called at construction time. + /// Sets the contract's initial owner. + /// + /// This function should be called at construction time. fn initializer(ref self: ComponentState, owner: ContractAddress) { self._transfer_ownership(owner); } @@ -92,8 +98,9 @@ mod Ownable { assert(caller == owner, Errors::NOT_OWNER); } - /// Internal function that transfers ownership of the contract to a new address. - /// It doesn't assert the caller. + /// Transfers ownership of the contract to a new address. + /// + /// Internal function without access restriction. fn _transfer_ownership( ref self: ComponentState, new_owner: ContractAddress ) { From 34dea75acd547c4a56d45674adfd6f2ba7ee8f08 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 12 Oct 2023 13:21:11 -0400 Subject: [PATCH 121/124] feat: apply review --- src/tests/utils.cairo | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index d8546c289..2c429c5a3 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -1,7 +1,6 @@ mod constants; use starknet::ContractAddress; -use starknet::class_hash::Felt252TryIntoClassHash; use starknet::testing; fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { From 169314739f4c58f40872be2a59e649364a17637e Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 12 Oct 2023 14:00:57 -0400 Subject: [PATCH 122/124] docs: update access page --- docs/modules/ROOT/pages/access.adoc | 167 +++++++++++-------- docs/modules/ROOT/pages/api/access.adoc | 2 +- src/access/accesscontrol/accesscontrol.cairo | 2 +- src/tests/mocks/accesscontrol_mocks.cairo | 12 +- 4 files changed, 101 insertions(+), 82 deletions(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index 6c63f53eb..90e358838 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -132,18 +132,40 @@ and sets a 'minter' role: [,javascript] ---- -const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); +const MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); #[starknet::contract] mod MyContract { - use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; - use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::introspection::src5::SRC5 as src5_component; use openzeppelin::token::erc20::ERC20; use starknet::ContractAddress; use super::MINTER_ROLE; + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage, + #[substorage(v0)] + src5: src5_component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } #[constructor] fn constructor( @@ -160,22 +182,16 @@ mod MyContract { ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); // AccessControl related initialization - let mut access_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref access_state); - AccessControl::InternalImpl::_grant_role( - ref access_state, - MINTER_ROLE, - minter - ); + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(MINTER_ROLE, minter); } - // This function can only be called by a minter + /// This function can only be called by a minter. #[external(v0)] fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, MINTER_ROLE); + self.accesscontrol.assert_only_role(MINTER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); } } @@ -192,19 +208,41 @@ Let's augment our ERC20 token example by also defining a 'burner' role, which le [,javascript] ---- -const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); -const BURNER_ROLE: felt252 = selector!('BURNER_ROLE'); +const MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); +const BURNER_ROLE: felt252 = selector!("BURNER_ROLE"); #[starknet::contract] mod MyContract { - use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; - use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::introspection::src5::SRC5 as src5_component; use openzeppelin::token::erc20::ERC20; use starknet::ContractAddress; use super::{MINTER_ROLE, BURNER_ROLE}; + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage, + #[substorage(v0)] + src5: src5_component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } #[constructor] fn constructor( @@ -222,38 +260,26 @@ mod MyContract { ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); // AccessControl related initialization - let mut access_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref access_state); - AccessControl::InternalImpl::_grant_role( - ref access_state, - MINTER_ROLE, - minter - ); - AccessControl::InternalImpl::_grant_role( - ref access_state, - BURNER_ROLE, - burner - ); + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(MINTER_ROLE, minter); + self.accesscontrol._grant_role(BURNER_ROLE, burner); } - - // This function can only be called by a minter + /// This function can only be called by a minter. #[external(v0)] fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, MINTER_ROLE); + self.accesscontrol.assert_only_role(MINTER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); } - // This function can only be called by a burner + /// This function can only be called by a burner. #[external(v0)] fn burn(ref self: ContractState, account: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, BURNER_ROLE); + self.accesscontrol.assert_only_role(BURNER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_burn(ref erc20_state, account, amount); } } @@ -292,20 +318,29 @@ Let's take a look at the ERC20 token example, this time taking advantage of the [,javascript] ---- -const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); -const BURNER_ROLE: felt252 = selector!('BURNER_ROLE'); +const MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); +const BURNER_ROLE: felt252 = selector!("BURNER_ROLE"); #[starknet::contract] mod MyContract { - use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; - use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::introspection::src5::SRC5 as src5_component; use openzeppelin::token::erc20::ERC20; use starknet::ContractAddress; use super::{MINTER_ROLE, BURNER_ROLE}; - #[storage] - struct Storage {} + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + + (...) #[constructor] fn constructor( @@ -322,49 +357,33 @@ mod MyContract { ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); // AccessControl related initialization - let mut access_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref access_state); - AccessControl::InternalImpl::_grant_role( - ref access_state, - DEFAULT_ADMIN_ROLE, - admin - ); + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin); } - // This function can only be called by a minter + /// This function can only be called by a minter. #[external(v0)] fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, MINTER_ROLE); + self.accesscontrol.assert_only_role(MINTER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); } - // This function can only be called by a burner + /// This function can only be called by a burner. #[external(v0)] fn burn(ref self: ContractState, account: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, BURNER_ROLE); + self.accesscontrol.assert_only_role(BURNER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_burn(ref erc20_state, account, amount); } - - // These function can only be called by the roles' admin - #[external(v0)] - fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::AccessControlImpl::grant_role(ref unsafe_state, role, account); - } - #[external(v0)] - fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::AccessControlImpl::revoke_role(ref unsafe_state, role, account); - } } ---- +TIP: The `grant_role` and `revoke_role` functions are automatically exposed as `external` functions +from the `AccessControlImpl` by leveraging the `#[abi(embed_v0)]` annotation. + Note that, unlike the previous examples, no accounts are granted the 'minter' or 'burner' roles. However, because those roles' admin role is the default admin role, and that role was granted to the 'admin', that same account can call `grant_role` to give minting or burning permission, and `revoke_role` to remove it. diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 71b017914..16b5c5c39 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -291,7 +291,7 @@ Contract module that allows children to implement role-based access control mech Roles are referred to by their `felt252` identifier: ```javascript -const MY_ROLE: felt252 = selector!('MY_ROLE'); +const MY_ROLE: felt252 = selector!("MY_ROLE"); ``` Roles can be used to represent a set of permissions. To restrict access to a diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index e314b0f67..8895075b1 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -2,7 +2,7 @@ // OpenZeppelin Contracts for Cairo v0.7.0 (access/accesscontrol/accesscontrol.cairo) /// # AccessControl Component - +/// /// The AccessControl component allows contracts to implement role-based access control mechanisms. /// Roles are referred to by their `felt252` identifier: #[starknet::component] diff --git a/src/tests/mocks/accesscontrol_mocks.cairo b/src/tests/mocks/accesscontrol_mocks.cairo index 099335699..e187734ac 100644 --- a/src/tests/mocks/accesscontrol_mocks.cairo +++ b/src/tests/mocks/accesscontrol_mocks.cairo @@ -22,9 +22,9 @@ mod DualCaseAccessControlMock { #[storage] struct Storage { #[substorage(v0)] - src5: src5_component::Storage, + accesscontrol: accesscontrol_component::Storage, #[substorage(v0)] - accesscontrol: accesscontrol_component::Storage + src5: src5_component::Storage } #[event] @@ -61,9 +61,9 @@ mod SnakeAccessControlMock { #[storage] struct Storage { #[substorage(v0)] - src5: src5_component::Storage, + accesscontrol: accesscontrol_component::Storage, #[substorage(v0)] - accesscontrol: accesscontrol_component::Storage + src5: src5_component::Storage, } #[event] @@ -101,9 +101,9 @@ mod CamelAccessControlMock { #[storage] struct Storage { #[substorage(v0)] - src5: src5_component::Storage, + accesscontrol: accesscontrol_component::Storage, #[substorage(v0)] - accesscontrol: accesscontrol_component::Storage + src5: src5_component::Storage } #[event] From 83c7c2a9816e123c62b1d8180019b03f38ac05d4 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 12 Oct 2023 14:11:44 -0400 Subject: [PATCH 123/124] docs: update api --- docs/modules/ROOT/pages/api/access.adoc | 79 +++++++++++++++++++------ 1 file changed, 60 insertions(+), 19 deletions(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 16b5c5c39..bea3fbd66 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -287,7 +287,7 @@ Emitted when `account` is revoked `role`. use openzeppelin::access::accesscontrol::AccessControl; ``` -Contract module that allows children to implement role-based access control mechanisms. +Component that allows contracts to implement role-based access control mechanisms. Roles are referred to by their `felt252` identifier: ```javascript @@ -298,17 +298,13 @@ Roles can be used to represent a set of permissions. To restrict access to a function call, use {assert_only_role}[`assert_only_role`]: ```javascript -use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; -use openzeppelin::access::accesscontrol::AccessControl; -use openzeppelin::token::erc20::ERC20; +(...) #[external(v0)] -fn foo(ref self: ContractState, account: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, BURNER_ROLE); +fn foo(ref self: ContractState) { + self.accesscontrol.assert_only_role(MY_ROLE); - let mut erc20_state = ERC20::unsafe_new_contract_state(); - ERC20::InternalImpl::_burn(ref erc20_state, account, amount); + // Do something } ``` @@ -326,7 +322,7 @@ grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. [.contract-index] -.External Functions +.Embeddable Functions -- .AccessControlImpl @@ -340,16 +336,28 @@ accounts that have been granted it. * xref:#AccessControl-supports_interface[`++supports_interface(self, interface_id: felt252)++`] -- +[.contract-index] +.camelCase Support +-- +.AccessControlCamelImpl + +* xref:#AccessControl-hasRole[`++hasRole(self, role, account)++`] +* xref:#AccessControl-getRoleAdmin[`++getRoleAdmin(self, role)++`] +* xref:#AccessControl-grantRole[`++grantRole(self, role, account)++`] +* xref:#AccessControl-revokeRole[`++revokeRole(self, role, account)++`] +* xref:#AccessControl-renounceRole[`++renounceRole(self, role, account)++`] +-- + [.contract-index] .Internal Functions -- .InternalImpl * xref:#AccessControl-initializer[`++initializer(self)++`] +* xref:#AccessControl-assert_only_role[`++assert_only_role(self, role)++`] * xref:#AccessControl-_set_role_admin[`++_set_role_admin(self, role, admin_role)++`] * xref:#AccessControl-_grant_role[`++_grant_role(self, role, account)++`] * xref:#AccessControl-_revoke_role[`++_revoke_role(self, role, account)++`] -* xref:#AccessControl-assert_only_role[`++assert_only_role(self, role)++`] -- [.contract-index] @@ -361,8 +369,8 @@ accounts that have been granted it. * xref:#AccessControl-RoleRevoked[`++RoleRevoked(role, account, sender)++`] -- -[#AccessControl-External-Functions] -==== External Functions +[#AccessControl-Embeddable-Functions] +==== Embeddable Functions [.contract-item] [[AccessControl-has_role]] @@ -433,6 +441,39 @@ May emit a {RoleRevoked} event. See xref:api/introspection.adoc#ISRC5-supports_interface[ISRC5::supports_interface]. +[#AccessControl-camelCase-Support] +==== camelCase Support + +[.contract-item] +[[AccessControl-hasRole]] +==== `[.contract-item-name]#++hasRole++#++(self: @ContractState, role: felt252, account: ContractAddress) → bool++` [.item-kind]#external# + +See xref:AccessControl-has_role[has_role]. + +[.contract-item] +[[AccessControl-getRoleAdmin]] +==== `[.contract-item-name]#++getRoleAdmin++#++(self: @ContractState, role: felt252) → felt252++` [.item-kind]#external# + +See xref:AccessControl-get_role_admin[get_role_admin]. + +[.contract-item] +[[AccessControl-grantRole]] +==== `[.contract-item-name]#++grantRole++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +See xref:AccessControl-grant_role[grant_role]. + +[.contract-item] +[[AccessControl-revokeRole]] +==== `[.contract-item-name]#++revokeRole++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +See xref:AccessControl-revoke_role[revoke_role]. + +[.contract-item] +[[AccessControl-renounceRole]] +==== `[.contract-item-name]#++renounceRole++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +See xref:AccessControl-renounce_role[renounce_role]. + [#AccessControl-Internal-Functions] ==== Internal Functions @@ -442,6 +483,12 @@ See xref:api/introspection.adoc#ISRC5-supports_interface[ISRC5::supports_interfa Initializes the contract by registering the xref:#IAccessControl[IAccessControl] interface ID. +[.contract-item] +[[AccessControl-assert_only_role]] +==== `[.contract-item-name]#++assert_only_role++#++(self: @ContractState, role: felt252)++` [.item-kind]#internal# + +Panics if called by any account without the given `role`. + [.contract-item] [[AccessControl-_set_role_admin]] ==== `[.contract-item-name]#++_set_role_admin++#++(ref self: ContractState, role: felt252, admin_role: felt252)++` [.item-kind]#internal# @@ -470,12 +517,6 @@ Internal function without access restriction. May emit a {RoleRevoked} event. -[.contract-item] -[[AccessControl-assert_only_role]] -==== `[.contract-item-name]#++assert_only_role++#++(self: @ContractState, role: felt252)++` [.item-kind]#internal# - -Panics if called by any account without the given `role`. - [#AccessControl-Events] ==== Events From c8b49f122147f3477cc1f442d872f9cc36f0a55f Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 12 Oct 2023 14:18:23 -0400 Subject: [PATCH 124/124] feat: apply review updates --- src/access/accesscontrol/accesscontrol.cairo | 6 +++--- src/tests/access/test_dual_ownable.cairo | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index 8895075b1..2c5ec554e 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -4,7 +4,7 @@ /// # AccessControl Component /// /// The AccessControl component allows contracts to implement role-based access control mechanisms. -/// Roles are referred to by their `felt252` identifier: +/// Roles are referred to by their `felt252` identifier. #[starknet::component] mod AccessControl { use openzeppelin::access::accesscontrol::interface; @@ -117,7 +117,7 @@ mod AccessControl { /// Revokes `role` from the calling account. /// - /// Roles are often managed via `grantRole` and `revokeRole`: this function's + /// Roles are often managed via `grant_role` and `revoke_role`: this function's /// purpose is to provide a mechanism for accounts to lose their privileges /// if they are compromised (such as when a trusted device is misplaced). /// @@ -211,7 +211,7 @@ mod AccessControl { } } - /// Attempts to revoke `role` to `account`. + /// Attempts to revoke `role` from `account`. /// /// Internal function without access restriction. /// diff --git a/src/tests/access/test_dual_ownable.cairo b/src/tests/access/test_dual_ownable.cairo index 1338c32b5..16588be16 100644 --- a/src/tests/access/test_dual_ownable.cairo +++ b/src/tests/access/test_dual_ownable.cairo @@ -4,10 +4,9 @@ use openzeppelin::access::ownable::interface::IOwnableCamelOnlyDispatcher; use openzeppelin::access::ownable::interface::IOwnableDispatcher; use openzeppelin::access::ownable::interface::IOwnableDispatcherTrait; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; -use openzeppelin::tests::mocks::ownable_mocks::CamelOwnableMock; -use openzeppelin::tests::mocks::ownable_mocks::CamelOwnablePanicMock; -use openzeppelin::tests::mocks::ownable_mocks::SnakeOwnableMock; -use openzeppelin::tests::mocks::ownable_mocks::SnakeOwnablePanicMock; +use openzeppelin::tests::mocks::ownable_mocks::{ + CamelOwnableMock, CamelOwnablePanicMock, SnakeOwnableMock, SnakeOwnablePanicMock +}; use openzeppelin::tests::utils::constants::{OWNER, NEW_OWNER}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend;