From 16c61ea4f9af64a9934fc79a10c6cd3e6f810daa Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Fri, 14 Jun 2024 13:28:05 +0100 Subject: [PATCH] Update examples ERC-20 and ERC-721 --- examples/erc20/.cargo/{config => config.toml} | 0 examples/erc20/Cargo.lock | 267 +++--- examples/erc20/Cargo.toml | 3 + examples/erc20/src/erc20.rs | 101 ++- examples/erc20/src/lib.rs | 59 ++ examples/erc20/src/main.rs | 69 +- examples/erc721/.cargo/config.toml | 7 + examples/erc721/Cargo.lock | 825 ++++++++++++++++++ examples/erc721/Cargo.toml | 25 + examples/erc721/src/erc721.rs | 358 ++++++++ examples/erc721/src/lib.rs | 68 ++ examples/erc721/src/main.rs | 4 + 12 files changed, 1542 insertions(+), 244 deletions(-) rename examples/erc20/.cargo/{config => config.toml} (100%) create mode 100644 examples/erc20/src/lib.rs create mode 100644 examples/erc721/.cargo/config.toml create mode 100644 examples/erc721/Cargo.lock create mode 100644 examples/erc721/Cargo.toml create mode 100644 examples/erc721/src/erc721.rs create mode 100644 examples/erc721/src/lib.rs create mode 100644 examples/erc721/src/main.rs diff --git a/examples/erc20/.cargo/config b/examples/erc20/.cargo/config.toml similarity index 100% rename from examples/erc20/.cargo/config rename to examples/erc20/.cargo/config.toml diff --git a/examples/erc20/Cargo.lock b/examples/erc20/Cargo.lock index bbedfee..302302a 100644 --- a/examples/erc20/Cargo.lock +++ b/examples/erc20/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -32,13 +32,12 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f938f00332d63a5b0ac687bd6f46d03884638948921d9f8b50c59563d421ae25" +checksum = "b155716bab55763c95ba212806cf43d05bcc70e5f35b02bad20cf5ec7fe11fed" dependencies = [ "arrayvec", "bytes", - "smol_str", ] [[package]] @@ -51,7 +50,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.66", "syn-solidity", "tiny-keccak", ] @@ -76,9 +75,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bit-set" @@ -97,15 +96,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.3.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -116,26 +109,11 @@ dependencies = [ "generic-array", ] -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.83" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cfg-if" @@ -151,13 +129,14 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const-hex" -version = "1.8.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08849ed393c907c90016652a01465a12d86361cd38ad2a7de026c56a520cc259" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" dependencies = [ "cfg-if 1.0.0", "cpufeatures", "hex", + "proptest", "serde", ] @@ -178,9 +157,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -253,30 +232,19 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "errno-dragonfly", "libc", "windows-sys", ] -[[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 = "fastrand" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fnv" @@ -296,9 +264,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if 1.0.0", "libc", @@ -325,15 +293,15 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -352,27 +320,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "memchr" -version = "2.6.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memory_units" @@ -382,7 +350,7 @@ checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" [[package]] name = "mini-alloc" -version = "0.4.3" +version = "0.5.0" dependencies = [ "cfg-if 1.0.0", "wee_alloc", @@ -390,9 +358,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -406,28 +374,28 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", - "bitflags 1.3.2", - "byteorder", + "bit-vec", + "bitflags", "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.6.29", + "regex-syntax", "rusty-fork", "tempfile", "unarray", @@ -441,9 +409,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -487,55 +455,40 @@ dependencies = [ "rand_core", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "regex" -version = "1.9.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.7.5", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.3.7" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "ruint" -version = "1.10.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95294d6e3a6192f3aabf91c38f56505a625aa495533442744185a36d75a790c4" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" dependencies = [ "proptest", "rand", @@ -547,9 +500,9 @@ dependencies = [ [[package]] name = "ruint-macro" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc_version" @@ -562,11 +515,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.10" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -587,28 +540,28 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.66", ] [[package]] @@ -621,18 +574,9 @@ dependencies = [ "keccak", ] -[[package]] -name = "smol_str" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", -] - [[package]] name = "stylus-proc" -version = "0.4.3" +version = "0.5.0" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -649,13 +593,12 @@ dependencies = [ [[package]] name = "stylus-sdk" -version = "0.4.3" +version = "0.5.0" dependencies = [ "alloy-primitives", "alloy-sol-types", "cfg-if 1.0.0", "derivative", - "fnv", "hex", "keccak-const", "lazy_static", @@ -676,9 +619,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -693,18 +636,17 @@ checksum = "e5f995d2140b0f751dbe94365be2591edbf3d1b75dcfaeac14183abbd2ff07bd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.66", ] [[package]] name = "tempfile" -version = "3.8.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if 1.0.0", "fastrand", - "redox_syscall", "rustix", "windows-sys", ] @@ -720,9 +662,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unarray" @@ -732,15 +674,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "valuable" @@ -805,22 +747,23 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -829,48 +772,54 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "zeroize" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/examples/erc20/Cargo.toml b/examples/erc20/Cargo.toml index 055cfff..8ecab43 100644 --- a/examples/erc20/Cargo.toml +++ b/examples/erc20/Cargo.toml @@ -12,6 +12,9 @@ mini-alloc = { path = "../../mini-alloc" } [features] export-abi = ["stylus-sdk/export-abi"] +[lib] +crate-type = ["lib", "cdylib"] + [profile.release] codegen-units = 1 strip = true diff --git a/examples/erc20/src/erc20.rs b/examples/erc20/src/erc20.rs index 2ebc562..be23bb1 100644 --- a/examples/erc20/src/erc20.rs +++ b/examples/erc20/src/erc20.rs @@ -1,15 +1,32 @@ +//! Implementation of the ERC-20 standard +//! +//! The eponymous [`Erc20`] type provides all the standard methods, +//! and is intended to be inherited by other contract types. +//! +//! You can configure the behavior of [`Erc20`] via the [`Erc20Params`] trait, +//! which allows specifying the name, symbol, and decimals of the token. +//! +//! Note that this code is unaudited and not fit for production use. + +// Imported packages use alloc::string::String; +use alloy_primitives::{Address, U256}; +use alloy_sol_types::sol; use core::marker::PhantomData; use stylus_sdk::{ - alloy_primitives::{Address, U256}, - alloy_sol_types::sol, - evm, msg, + evm, + msg, prelude::*, }; pub trait Erc20Params { + /// Immutable token name const NAME: &'static str; + + /// Immutable token symbol const SYMBOL: &'static str; + + /// Immutable token decimals const DECIMALS: u8; } @@ -36,6 +53,7 @@ sol! { error InsufficientAllowance(address owner, address spender, uint256 have, uint256 want); } +/// Represents the ways methods may fail. #[derive(SolidityError)] pub enum Erc20Error { InsufficientBalance(InsufficientBalance), @@ -43,14 +61,18 @@ pub enum Erc20Error { } // These methods aren't exposed to other contracts +// Methods marked as "pub" here are usable outside of the erc20 module (i.e. they're callable from lib.rs) // Note: modifying storage will become much prettier soon impl Erc20 { - pub fn transfer_impl( + /// Movement of funds between 2 accounts + /// (invoked by the external transfer() and transfer_from() functions ) + pub fn _transfer( &mut self, from: Address, to: Address, value: U256, ) -> Result<(), Erc20Error> { + // Decreasing sender balance let mut sender_balance = self.balances.setter(from); let old_sender_balance = sender_balance.get(); if old_sender_balance < value { @@ -61,26 +83,40 @@ impl Erc20 { })); } sender_balance.set(old_sender_balance - value); + + // Increasing receiver balance let mut to_balance = self.balances.setter(to); let new_to_balance = to_balance.get() + value; to_balance.set(new_to_balance); + + // Emitting the transfer event evm::log(Transfer { from, to, value }); Ok(()) } - pub fn mint(&mut self, address: Address, value: U256) { + /// Mints `value` tokens to `address` + pub fn mint(&mut self, address: Address, value: U256) -> Result<(), Erc20Error> { + // Increasing balance let mut balance = self.balances.setter(address); let new_balance = balance.get() + value; balance.set(new_balance); + + // Increasing total supply self.total_supply.set(self.total_supply.get() + value); + + // Emitting the transfer event evm::log(Transfer { from: Address::ZERO, to: address, value, }); + + Ok(()) } + /// Burns `value` tokens from `address` pub fn burn(&mut self, address: Address, value: U256) -> Result<(), Erc20Error> { + // Decreasing balance let mut balance = self.balances.setter(address); let old_balance = balance.get(); if old_balance < value { @@ -91,12 +127,17 @@ impl Erc20 { })); } balance.set(old_balance - value); + + // Decreasing the total supply self.total_supply.set(self.total_supply.get() - value); + + // Emitting the transfer event evm::log(Transfer { from: address, to: Address::ZERO, value, }); + Ok(()) } } @@ -105,43 +146,46 @@ impl Erc20 { // Note: modifying storage will become much prettier soon #[external] impl Erc20 { + /// Immutable token name pub fn name() -> String { T::NAME.into() } + /// Immutable token symbol pub fn symbol() -> String { T::SYMBOL.into() } + /// Immutable token decimals pub fn decimals() -> u8 { T::DECIMALS } - pub fn balance_of(&self, address: Address) -> U256 { - self.balances.get(address) + /// Total supply of tokens + pub fn total_supply(&self) -> U256 { + self.total_supply.get() } - pub fn transfer(&mut self, to: Address, value: U256) -> Result { - self.transfer_impl(msg::sender(), to, value)?; - Ok(true) + /// Balance of `address` + pub fn balance_of(&self, owner: Address) -> U256 { + self.balances.get(owner) } - pub fn approve(&mut self, spender: Address, value: U256) -> bool { - self.allowances.setter(msg::sender()).insert(spender, value); - evm::log(Approval { - owner: msg::sender(), - spender, - value, - }); - true + /// Transfers `value` tokens from msg::sender() to `to` + pub fn transfer(&mut self, to: Address, value: U256) -> Result { + self._transfer(msg::sender(), to, value)?; + Ok(true) } + /// Transfers `value` tokens from `from` to `to` + /// (msg::sender() must be able to spend at least `value` tokens from `from`) pub fn transfer_from( &mut self, from: Address, to: Address, value: U256, ) -> Result { + // Check msg::sender() allowance let mut sender_allowances = self.allowances.setter(from); let mut allowance = sender_allowances.setter(msg::sender()); let old_allowance = allowance.get(); @@ -153,12 +197,29 @@ impl Erc20 { want: value, })); } + + // Decreases allowance allowance.set(old_allowance - value); - self.transfer_impl(from, to, value)?; + + // Calls the internal transfer function + self._transfer(from, to, value)?; + Ok(true) } + /// Approves the spenditure of `value` tokens of msg::sender() to `spender` + pub fn approve(&mut self, spender: Address, value: U256) -> bool { + self.allowances.setter(msg::sender()).insert(spender, value); + evm::log(Approval { + owner: msg::sender(), + spender, + value, + }); + true + } + + /// Returns the allowance of `spender` on `owner`'s tokens pub fn allowance(&self, owner: Address, spender: Address) -> U256 { self.allowances.getter(owner).get(spender) } -} +} \ No newline at end of file diff --git a/examples/erc20/src/lib.rs b/examples/erc20/src/lib.rs new file mode 100644 index 0000000..2f5e41a --- /dev/null +++ b/examples/erc20/src/lib.rs @@ -0,0 +1,59 @@ +// Only run this as a WASM if the export-abi feature is not set. +#![cfg_attr(not(any(feature = "export-abi", test)), no_main)] +extern crate alloc; + +// Modules and imports +mod erc20; + +use alloy_primitives::{Address, U256}; +use stylus_sdk::{ + msg, + prelude::* +}; +use crate::erc20::{Erc20, Erc20Params, Erc20Error}; + +/// Initializes a custom, global allocator for Rust programs compiled to WASM. +#[global_allocator] +static ALLOC: mini_alloc::MiniAlloc = mini_alloc::MiniAlloc::INIT; + +/// Immutable definitions +struct StylusTestTokenParams; +impl Erc20Params for StylusTestTokenParams { + const NAME: &'static str = "StylusTestToken"; + const SYMBOL: &'static str = "STTK"; + const DECIMALS: u8 = 18; +} + +// Define the entrypoint as a Solidity storage object. The sol_storage! macro +// will generate Rust-equivalent structs with all fields mapped to Solidity-equivalent +// storage slots and types. +sol_storage! { + #[entrypoint] + struct StylusTestToken { + // Allows erc20 to access StylusTestToken's storage and make calls + #[borrow] + Erc20 erc20; + } +} + +#[external] +#[inherit(Erc20)] +impl StylusTestToken { + /// Mints tokens + pub fn mint(&mut self, value: U256) -> Result<(), Erc20Error> { + self.erc20.mint(msg::sender(), value)?; + Ok(()) + } + + /// Mints tokens to another address + pub fn mint_to(&mut self, to: Address, value: U256) -> Result<(), Erc20Error> { + self.erc20.mint(to, value)?; + Ok(()) + } + + /// Burns tokens + pub fn burn(&mut self, value: U256) -> Result<(), Erc20Error> { + self.erc20.burn(msg::sender(), value)?; + Ok(()) + } +} \ No newline at end of file diff --git a/examples/erc20/src/main.rs b/examples/erc20/src/main.rs index c36693e..b88071a 100644 --- a/examples/erc20/src/main.rs +++ b/examples/erc20/src/main.rs @@ -1,65 +1,4 @@ -#![cfg_attr(not(feature = "export-abi"), no_main, no_std)] -extern crate alloc; - -use crate::erc20::{Erc20, Erc20Params}; -use alloc::{string::String, vec::Vec}; -use stylus_sdk::{alloy_primitives::U256, call, msg, prelude::*}; - -#[cfg(target_arch = "wasm32")] -#[global_allocator] -static ALLOC: mini_alloc::MiniAlloc = mini_alloc::MiniAlloc::INIT; - -mod erc20; - -struct WethParams; - -/// Immutable definitions -impl Erc20Params for WethParams { - const NAME: &'static str = "Wrapped Ether Example"; - const SYMBOL: &'static str = "WETH"; - const DECIMALS: u8 = 18; -} - -// The contract -sol_storage! { - #[entrypoint] // Makes Weth the entrypoint - struct Weth { - #[borrow] // Allows erc20 to access Weth's storage and make calls - Erc20 erc20; - } -} - -// Another contract we'd like to call -sol_interface! { - interface IMath { - function sum(uint256[] values) pure returns (string, uint256); - } -} - -#[external] -#[inherit(Erc20)] -impl Weth { - #[payable] - pub fn deposit(&mut self) { - self.erc20.mint(msg::sender(), msg::value()); - } - - pub fn withdraw(&mut self, amount: U256) -> Result<(), Vec> { - self.erc20.burn(msg::sender(), amount)?; - - // send the user their funds - call::transfer_eth(msg::sender(), amount) - } - - // sums numbers - pub fn sum(values: Vec) -> (String, U256) { - ("sum".into(), values.iter().sum()) - } - - // calls the sum() method from the interface - pub fn sum_with_helper(&self, helper: IMath, values: Vec) -> Result> { - let (text, sum) = helper.sum(self, values)?; - assert_eq!(&text, "sum"); - Ok(sum) - } -} +#[cfg(feature = "export-abi")] +fn main() { + erc20::print_abi("MIT-OR-APACHE-2.0", "pragma solidity ^0.8.23;"); +} \ No newline at end of file diff --git a/examples/erc721/.cargo/config.toml b/examples/erc721/.cargo/config.toml new file mode 100644 index 0000000..3b7ee2e --- /dev/null +++ b/examples/erc721/.cargo/config.toml @@ -0,0 +1,7 @@ +[build] +target = "wasm32-unknown-unknown" + +[target.wasm32-unknown-unknown] +rustflags = [ + "-C", "link-arg=-zstack-size=32768", +] diff --git a/examples/erc721/Cargo.lock b/examples/erc721/Cargo.lock new file mode 100644 index 0000000..ad8ce55 --- /dev/null +++ b/examples/erc721/Cargo.lock @@ -0,0 +1,825 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloy-primitives" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e416903084d3392ebd32d94735c395d6709415b76c7728e594d3f996f2b03e65" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if 1.0.0", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "proptest", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b155716bab55763c95ba212806cf43d05bcc70e5f35b02bad20cf5ec7fe11fed" +dependencies = [ + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74ceeffdacf9dd0910404d743d07273776fd17b85f9cb17b49a97e5c6055ce9" +dependencies = [ + "dunce", + "heck", + "proc-macro2", + "quote", + "syn 2.0.66", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-types" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f347cb6bb307b3802ec455ef43ce00f5e590e0ceca3d2f3b070f5ee367e235" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[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 = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[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.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[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 = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "erc721" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "mini-alloc", + "stylus-sdk", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-const" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea" + +[[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.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "mini-alloc" +version = "0.5.0" +dependencies = [ + "cfg-if 1.0.0", + "wee_alloc", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "proptest", + "rand", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[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.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "stylus-proc" +version = "0.5.0" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "cfg-if 1.0.0", + "convert_case 0.6.0", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "sha3", + "syn 1.0.109", + "syn-solidity", +] + +[[package]] +name = "stylus-sdk" +version = "0.5.0" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "cfg-if 1.0.0", + "derivative", + "hex", + "keccak-const", + "lazy_static", + "regex", + "stylus-proc", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f995d2140b0f751dbe94365be2591edbf3d1b75dcfaeac14183abbd2ff07bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "rustix", + "windows-sys", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + +[[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-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.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/examples/erc721/Cargo.toml b/examples/erc721/Cargo.toml new file mode 100644 index 0000000..79f289b --- /dev/null +++ b/examples/erc721/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "erc721" +version = "0.1.0" +edition = "2021" + +[dependencies] +alloy-primitives = "0.3.1" +alloy-sol-types = "0.3.1" +stylus-sdk = { path = "../../stylus-sdk" } +mini-alloc = { path = "../../mini-alloc" } + +[features] +export-abi = ["stylus-sdk/export-abi"] + +[lib] +crate-type = ["lib", "cdylib"] + +[profile.release] +codegen-units = 1 +strip = true +lto = true +panic = "abort" +opt-level = "s" + +[workspace] diff --git a/examples/erc721/src/erc721.rs b/examples/erc721/src/erc721.rs new file mode 100644 index 0000000..df7bd5e --- /dev/null +++ b/examples/erc721/src/erc721.rs @@ -0,0 +1,358 @@ +//! Implementation of the ERC-721 standard +//! +//! The eponymous [`Erc721`] type provides all the standard methods, +//! and is intended to be inherited by other contract types. +//! +//! You can configure the behavior of [`Erc721`] via the [`Erc721Params`] trait, +//! which allows specifying the name, symbol, and token uri. +//! +//! Note that this code is unaudited and not fit for production use. + +use alloc::{string::String, vec, vec::Vec}; +use alloy_primitives::{Address, U256, FixedBytes}; +use alloy_sol_types::sol; +use core::{borrow::BorrowMut, marker::PhantomData}; +use stylus_sdk::{ + abi::Bytes, + evm, + msg, + prelude::* +}; + +pub trait Erc721Params { + /// Immutable NFT name. + const NAME: &'static str; + + /// Immutable NFT symbol. + const SYMBOL: &'static str; + + /// The NFT's Uniform Resource Identifier. + fn token_uri(token_id: U256) -> String; +} + +sol_storage! { + /// Erc721 implements all ERC-721 methods + pub struct Erc721 { + /// Token id to owner map + mapping(uint256 => address) owners; + /// User to balance map + mapping(address => uint256) balances; + /// Token id to approved user map + mapping(uint256 => address) token_approvals; + /// User to operator map (the operator can manage all NFTs of the owner) + mapping(address => mapping(address => bool)) operator_approvals; + /// Total supply + uint256 total_supply; + /// Used to allow [`Erc721Params`] + PhantomData phantom; + } +} + +// Declare events and Solidity error types +sol! { + event Transfer(address indexed from, address indexed to, uint256 indexed token_id); + event Approval(address indexed owner, address indexed approved, uint256 indexed token_id); + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + // Token id has not been minted, or it has been burned + error InvalidTokenId(uint256 token_id); + // The specified address is not the owner of the specified token id + error NotOwner(address from, uint256 token_id, address real_owner); + // The specified address does not have allowance to spend the specified token id + error NotApproved(address owner, address spender, uint256 token_id); + // Attempt to transfer token id to the Zero address + error TransferToZero(uint256 token_id); + // The receiver address refused to receive the specified token id + error ReceiverRefused(address receiver, uint256 token_id, bytes4 returned); +} + +/// Represents the ways methods may fail. +#[derive(SolidityError)] +pub enum Erc721Error { + InvalidTokenId(InvalidTokenId), + NotOwner(NotOwner), + NotApproved(NotApproved), + TransferToZero(TransferToZero), + ReceiverRefused(ReceiverRefused), +} + +// External interfaces +sol_interface! { + /// Allows calls to the `onERC721Received` method of other contracts implementing `IERC721TokenReceiver`. + interface IERC721TokenReceiver { + function onERC721Received(address operator, address from, uint256 token_id, bytes data) external returns(bytes4); + } +} + +/// Selector for `onERC721Received`, which is returned by contracts implementing `IERC721TokenReceiver`. +const ERC721_TOKEN_RECEIVER_ID: u32 = 0x150b7a02; + +// These methods aren't external, but are helpers used by external methods. +// Methods marked as "pub" here are usable outside of the erc721 module (i.e. they're callable from lib.rs). +impl Erc721 { + /// Requires that msg::sender() is authorized to spend a given token + fn require_authorized_to_spend(&self, from: Address, token_id: U256) -> Result<(), Erc721Error> { + // `from` must be the owner of the token_id + let owner = self.owner_of(token_id)?; + if from != owner { + return Err(Erc721Error::NotOwner(NotOwner { + from, + token_id, + real_owner: owner, + })); + } + + // caller is the owner + if msg::sender() == owner { + return Ok(()); + } + + // caller is an operator for the owner (can manage their tokens) + if self.operator_approvals.getter(owner).get(msg::sender()) { + return Ok(()); + } + + // caller is approved to manage this token_id + if msg::sender() == self.token_approvals.get(token_id) { + return Ok(()); + } + + // otherwise, caller is not allowed to manage this token_id + Err(Erc721Error::NotApproved(NotApproved { + owner, + spender: msg::sender(), + token_id, + })) + } + + /// Transfers `token_id` from `from` to `to`. + /// This function does check that `from` is the owner of the token, but it does not check + /// that `to` is not the zero address, as this function is usable for burning. + pub fn transfer(&mut self, token_id: U256, from: Address, to: Address) -> Result<(), Erc721Error> { + let mut owner = self.owners.setter(token_id); + let previous_owner = owner.get(); + if previous_owner != from { + return Err(Erc721Error::NotOwner(NotOwner { + from, + token_id, + real_owner: previous_owner, + })); + } + owner.set(to); + + // right now working with storage can be verbose, but this will change upcoming version of the Stylus SDK + let mut from_balance = self.balances.setter(from); + let balance = from_balance.get() - U256::from(1); + from_balance.set(balance); + + let mut to_balance = self.balances.setter(to); + let balance = to_balance.get() + U256::from(1); + to_balance.set(balance); + + // cleaning app the approved mapping for this token + self.token_approvals.delete(token_id); + + evm::log(Transfer { from, to, token_id }); + Ok(()) + } + + /// Calls `onERC721Received` on the `to` address if it is a contract. + /// Otherwise it does nothing + fn call_receiver( + storage: &mut S, + token_id: U256, + from: Address, + to: Address, + data: Vec, + ) -> Result<(), Erc721Error> { + if to.has_code() { + let receiver = IERC721TokenReceiver::new(to); + let received = receiver + .on_erc_721_received(&mut *storage, msg::sender(), from, token_id, data) + .map_err(|_e| Erc721Error::ReceiverRefused(ReceiverRefused { + receiver: receiver.address, + token_id, + returned: 0_u32.to_be_bytes(), + }))? + .0; + + if u32::from_be_bytes(received) != ERC721_TOKEN_RECEIVER_ID { + return Err(Erc721Error::ReceiverRefused(ReceiverRefused { + receiver: receiver.address, + token_id, + returned: received, + })); + } + } + Ok(()) + } + + /// Transfers and calls `onERC721Received` + pub fn safe_transfer>( + storage: &mut S, + token_id: U256, + from: Address, + to: Address, + data: Vec, + ) -> Result<(), Erc721Error> { + storage.borrow_mut().transfer(token_id, from, to)?; + Self::call_receiver(storage, token_id, from, to, data) + } + + /// Mints a new token and transfers it to `to` + pub fn mint(&mut self, to: Address) -> Result<(), Erc721Error> { + let new_token_id = self.total_supply.get(); + self.total_supply.set(new_token_id + U256::from(1u8)); + self.transfer(new_token_id, Address::default(), to)?; + Ok(()) + } + + /// Burns the token `token_id` from `from` + /// Note that total_supply is not reduced since it's used to calculate the next token_id to mint + pub fn burn(&mut self, from: Address, token_id: U256) -> Result<(), Erc721Error> { + self.transfer(token_id, from, Address::default())?; + Ok(()) + } +} + +// these methods are external to other contracts +#[external] +impl Erc721 { + /// Immutable NFT name. + pub fn name() -> Result { + Ok(T::NAME.into()) + } + + /// Immutable NFT symbol. + pub fn symbol() -> Result { + Ok(T::SYMBOL.into()) + } + + /// The NFT's Uniform Resource Identifier. + #[selector(name = "tokenURI")] + pub fn token_uri(&self, token_id: U256) -> Result { + self.owner_of(token_id)?; // require NFT exist + Ok(T::token_uri(token_id)) + } + + /// Gets the number of NFTs owned by an account. + pub fn balance_of(&self, owner: Address) -> Result { + Ok(self.balances.get(owner)) + } + + /// Gets the owner of the NFT, if it exists. + pub fn owner_of(&self, token_id: U256) -> Result { + let owner = self.owners.get(token_id); + if owner.is_zero() { + return Err(Erc721Error::InvalidTokenId(InvalidTokenId { token_id })); + } + Ok(owner) + } + + /// Transfers an NFT, but only after checking the `to` address can receive the NFT. + /// It includes additional data for the receiver. + #[selector(name = "safeTransferFrom")] + pub fn safe_transfer_from_with_data>( + storage: &mut S, + from: Address, + to: Address, + token_id: U256, + data: Bytes, + ) -> Result<(), Erc721Error> { + if to.is_zero() { + return Err(Erc721Error::TransferToZero(TransferToZero { token_id })); + } + storage + .borrow_mut() + .require_authorized_to_spend(from, token_id)?; + + Self::safe_transfer(storage, token_id, from, to, data.0) + } + + /// Equivalent to [`safe_transfer_from_with_data`], but without the additional data. + /// + /// Note: because Rust doesn't allow multiple methods with the same name, + /// we use the `#[selector]` macro attribute to simulate solidity overloading. + #[selector(name = "safeTransferFrom")] + pub fn safe_transfer_from>( + storage: &mut S, + from: Address, + to: Address, + token_id: U256, + ) -> Result<(), Erc721Error> { + Self::safe_transfer_from_with_data(storage, from, to, token_id, Bytes(vec![])) + } + + /// Transfers the NFT. + pub fn transfer_from(&mut self, from: Address, to: Address, token_id: U256) -> Result<(), Erc721Error> { + if to.is_zero() { + return Err(Erc721Error::TransferToZero(TransferToZero { token_id })); + } + self.require_authorized_to_spend(from, token_id)?; + self.transfer(token_id, from, to)?; + Ok(()) + } + + /// Grants an account the ability to manage the sender's NFT. + pub fn approve(&mut self, approved: Address, token_id: U256) -> Result<(), Erc721Error> { + let owner = self.owner_of(token_id)?; + + // require authorization + if msg::sender() != owner && !self.operator_approvals.getter(owner).get(msg::sender()) { + return Err(Erc721Error::NotApproved(NotApproved { + owner, + spender: msg::sender(), + token_id, + })); + } + self.token_approvals.insert(token_id, approved); + + evm::log(Approval { + approved, + owner, + token_id, + }); + Ok(()) + } + + /// Grants an account the ability to manage all of the sender's NFTs. + pub fn set_approval_for_all(&mut self, operator: Address, approved: bool) -> Result<(), Erc721Error> { + let owner = msg::sender(); + self.operator_approvals + .setter(owner) + .insert(operator, approved); + + evm::log(ApprovalForAll { + owner, + operator, + approved, + }); + Ok(()) + } + + /// Gets the account managing an NFT, or zero if unmanaged. + pub fn get_approved(&mut self, token_id: U256) -> Result { + Ok(self.token_approvals.get(token_id)) + } + + /// Determines if an account has been authorized to managing all of a user's NFTs. + pub fn is_approved_for_all(&mut self, owner: Address, operator: Address) -> Result { + Ok(self.operator_approvals.getter(owner).get(operator)) + } + + /// Whether the NFT supports a given standard. + pub fn supports_interface(interface: FixedBytes<4>) -> Result { + let interface_slice_array: [u8; 4] = interface.as_slice().try_into().unwrap(); + + if u32::from_be_bytes(interface_slice_array) == 0xffffffff { + // special cased in the ERC165 standard + return Ok(false); + } + + const IERC165: u32 = 0x01ffc9a7; + const IERC721: u32 = 0x80ac58cd; + const IERC721_METADATA: u32 = 0x5b5e139f; + + Ok(matches!(u32::from_be_bytes(interface_slice_array), IERC165 | IERC721 | IERC721_METADATA)) + } +} \ No newline at end of file diff --git a/examples/erc721/src/lib.rs b/examples/erc721/src/lib.rs new file mode 100644 index 0000000..33db176 --- /dev/null +++ b/examples/erc721/src/lib.rs @@ -0,0 +1,68 @@ +// Only run this as a WASM if the export-abi feature is not set. +#![cfg_attr(not(any(feature = "export-abi", test)), no_main)] +extern crate alloc; + +// Modules and imports +mod erc721; + +use alloy_primitives::{U256, Address}; +/// Import the Stylus SDK along with alloy primitive types for use in our program. +use stylus_sdk::{ + msg, prelude::* +}; +use crate::erc721::{Erc721, Erc721Params, Erc721Error}; + +/// Initializes a custom, global allocator for Rust programs compiled to WASM. +#[global_allocator] +static ALLOC: mini_alloc::MiniAlloc = mini_alloc::MiniAlloc::INIT; + +/// Immutable definitions +struct StylusTestNFTParams; +impl Erc721Params for StylusTestNFTParams { + const NAME: &'static str = "StylusTestNFT"; + const SYMBOL: &'static str = "STNFT"; + + fn token_uri(token_id: U256) -> String { + format!("{}{}{}", "https://my-nft-metadata.com/", token_id, ".json") + } +} + +// Define the entrypoint as a Solidity storage object. The sol_storage! macro +// will generate Rust-equivalent structs with all fields mapped to Solidity-equivalent +// storage slots and types. +sol_storage! { + #[entrypoint] + struct StylusTestNFT { + #[borrow] // Allows erc721 to access StylusTestNFT's storage and make calls + Erc721 erc721; + } +} + +#[external] +#[inherit(Erc721)] +impl StylusTestNFT { + /// Mints an NFT + pub fn mint(&mut self) -> Result<(), Erc721Error> { + let minter = msg::sender(); + self.erc721.mint(minter)?; + Ok(()) + } + + /// Mints an NFT to another address + pub fn mint_to(&mut self, to: Address) -> Result<(), Erc721Error> { + self.erc721.mint(to)?; + Ok(()) + } + + /// Burns an NFT + pub fn burn(&mut self, token_id: U256) -> Result<(), Erc721Error> { + // This function checks that msg::sender() owns the specified token_id + self.erc721.burn(msg::sender(), token_id)?; + Ok(()) + } + + /// Total supply + pub fn total_supply(&mut self) -> Result { + Ok(self.erc721.total_supply.get()) + } +} \ No newline at end of file diff --git a/examples/erc721/src/main.rs b/examples/erc721/src/main.rs new file mode 100644 index 0000000..968be84 --- /dev/null +++ b/examples/erc721/src/main.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "export-abi")] +fn main() { + erc721::print_abi("MIT-OR-APACHE-2.0", "pragma solidity ^0.8.23;"); +} \ No newline at end of file