difftreelog
refactor move evm-coder out of the repo
in: master
51 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -172,9 +172,9 @@
[[package]]
name = "anyhow"
-version = "1.0.68"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
+checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
[[package]]
name = "app-promotion-rpc"
@@ -343,9 +343,9 @@
[[package]]
name = "async-trait"
-version = "0.1.63"
+version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1"
+checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2"
dependencies = [
"proc-macro2",
"quote",
@@ -706,20 +706,9 @@
[[package]]
name = "bstr"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
-dependencies = [
- "lazy_static",
- "memchr",
- "regex-automata",
-]
-
-[[package]]
-name = "bstr"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b"
+checksum = "b7f0778972c64420fdedc63f09919c8a88bda7b25135357fd25a5d9f3257e832"
dependencies = [
"memchr",
"serde",
@@ -760,9 +749,9 @@
[[package]]
name = "bytes"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "bzip2-sys"
@@ -808,9 +797,9 @@
[[package]]
name = "cc"
-version = "1.0.78"
+version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
dependencies = [
"jobserver",
]
@@ -1027,18 +1016,6 @@
]
[[package]]
-name = "console"
-version = "0.15.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60"
-dependencies = [
- "encode_unicode",
- "lazy_static",
- "libc",
- "windows-sys 0.42.0",
-]
-
-[[package]]
name = "const-oid"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1221,9 +1198,9 @@
[[package]]
name = "crc"
-version = "3.0.0"
+version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3"
+checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
dependencies = [
"crc-catalog",
]
@@ -1874,9 +1851,9 @@
[[package]]
name = "curve25519-dalek"
-version = "4.0.0-pre.5"
+version = "4.0.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f"
+checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac"
dependencies = [
"cfg-if",
"fiat-crypto",
@@ -1888,9 +1865,9 @@
[[package]]
name = "cxx"
-version = "1.0.87"
+version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b61a7545f753a88bcbe0a70de1fcc0221e10bfc752f576754fa91e663db1622e"
+checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -1900,9 +1877,9 @@
[[package]]
name = "cxx-build"
-version = "1.0.87"
+version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f464457d494b5ed6905c63b0c4704842aba319084a0a3561cdc1359536b53200"
+checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d"
dependencies = [
"cc",
"codespan-reporting",
@@ -1915,15 +1892,15 @@
[[package]]
name = "cxxbridge-flags"
-version = "1.0.87"
+version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43c7119ce3a3701ed81aca8410b9acf6fc399d2629d057b87e2efa4e63a3aaea"
+checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.87"
+version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65e07508b90551e610910fa648a1878991d367064997a596135b86df30daf07e"
+checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2"
dependencies = [
"proc-macro2",
"quote",
@@ -2268,9 +2245,9 @@
[[package]]
name = "either"
-version = "1.8.0"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "elliptic-curve"
@@ -2295,12 +2272,6 @@
]
[[package]]
-name = "encode_unicode"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
-
-[[package]]
name = "enum-as-inner"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2474,24 +2445,20 @@
[[package]]
name = "evm-coder"
-version = "0.1.6"
+version = "0.3.0"
+source = "git+https://github.com/uniquenetwork/evm-coder?tag=v0.3.0#c4bfdf39d84fbe74c6178417177f2a7f81d92bdd"
dependencies = [
"ethereum",
"evm-coder-procedural",
- "evm-core",
- "frame-support",
- "hex",
- "hex-literal",
"impl-trait-for-tuples",
"primitive-types",
"sha3-const",
- "similar-asserts",
- "trybuild",
]
[[package]]
name = "evm-coder-procedural"
-version = "0.2.3"
+version = "0.3.0"
+source = "git+https://github.com/uniquenetwork/evm-coder?tag=v0.3.0#c4bfdf39d84fbe74c6178417177f2a7f81d92bdd"
dependencies = [
"Inflector",
"hex",
@@ -2502,6 +2469,15 @@
]
[[package]]
+name = "evm-coder-substrate-procedural"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "evm-core"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3227,9 +3203,9 @@
[[package]]
name = "fs_extra"
-version = "1.2.0"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "funty"
@@ -3239,9 +3215,9 @@
[[package]]
name = "futures"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
+checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
dependencies = [
"futures-channel",
"futures-core",
@@ -3254,9 +3230,9 @@
[[package]]
name = "futures-channel"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
+checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5"
dependencies = [
"futures-core",
"futures-sink",
@@ -3264,15 +3240,15 @@
[[package]]
name = "futures-core"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
+checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
[[package]]
name = "futures-executor"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
+checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e"
dependencies = [
"futures-core",
"futures-task",
@@ -3282,9 +3258,9 @@
[[package]]
name = "futures-io"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
+checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
[[package]]
name = "futures-lite"
@@ -3303,9 +3279,9 @@
[[package]]
name = "futures-macro"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
+checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
dependencies = [
"proc-macro2",
"quote",
@@ -3325,15 +3301,15 @@
[[package]]
name = "futures-sink"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
+checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364"
[[package]]
name = "futures-task"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
+checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
[[package]]
name = "futures-timer"
@@ -3343,9 +3319,9 @@
[[package]]
name = "futures-util"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
+checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
dependencies = [
"futures-channel",
"futures-core",
@@ -3469,7 +3445,7 @@
checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
dependencies = [
"aho-corasick",
- "bstr 1.1.0",
+ "bstr",
"fnv",
"log",
"regex",
@@ -3545,9 +3521,9 @@
[[package]]
name = "heck"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
@@ -3568,6 +3544,12 @@
]
[[package]]
+name = "hermit-abi"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01"
+
+[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3697,9 +3679,9 @@
[[package]]
name = "hyper"
-version = "0.14.23"
+version = "0.14.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c"
+checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c"
dependencies = [
"bytes",
"futures-channel",
@@ -3914,12 +3896,12 @@
[[package]]
name = "io-lifetimes"
-version = "1.0.4"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
+checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
dependencies = [
"libc",
- "windows-sys 0.42.0",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -3948,14 +3930,14 @@
[[package]]
name = "is-terminal"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
+checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef"
dependencies = [
- "hermit-abi 0.2.6",
- "io-lifetimes 1.0.4",
- "rustix 0.36.7",
- "windows-sys 0.42.0",
+ "hermit-abi 0.3.0",
+ "io-lifetimes 1.0.5",
+ "rustix 0.36.8",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -3984,9 +3966,9 @@
[[package]]
name = "js-sys"
-version = "0.3.60"
+version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
dependencies = [
"wasm-bindgen",
]
@@ -4974,7 +4956,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb"
dependencies = [
- "rustix 0.36.7",
+ "rustix 0.36.8",
]
[[package]]
@@ -5284,9 +5266,9 @@
[[package]]
name = "netlink-packet-utils"
-version = "0.5.1"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e"
+checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34"
dependencies = [
"anyhow",
"byteorder",
@@ -6248,6 +6230,8 @@
version = "0.1.3"
dependencies = [
"evm-coder",
+ "evm-coder-substrate-procedural",
+ "evm-core",
"frame-benchmarking",
"frame-support",
"frame-system",
@@ -6256,6 +6240,7 @@
"scale-info",
"sp-core",
"sp-std",
+ "spez",
"up-data-structs",
]
@@ -7272,9 +7257,9 @@
[[package]]
name = "parity-scale-codec"
-version = "3.2.2"
+version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ab01d0f889e957861bc65888d5ccbe82c158d0270136ba46820d43837cdf72"
+checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed"
dependencies = [
"arrayvec 0.7.2",
"bitvec",
@@ -7333,7 +7318,7 @@
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
- "parking_lot_core 0.9.6",
+ "parking_lot_core 0.9.7",
]
[[package]]
@@ -7352,15 +7337,15 @@
[[package]]
name = "parking_lot_core"
-version = "0.9.6"
+version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
+checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
- "windows-sys 0.42.0",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -8838,10 +8823,16 @@
]
[[package]]
+name = "proc-macro-hack"
+version = "0.5.20+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
+
+[[package]]
name = "proc-macro2"
-version = "1.0.50"
+version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
+checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
@@ -9675,16 +9666,16 @@
[[package]]
name = "rustix"
-version = "0.36.7"
+version = "0.36.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
+checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
dependencies = [
"bitflags",
"errno",
- "io-lifetimes 1.0.4",
+ "io-lifetimes 1.0.5",
"libc",
"linux-raw-sys 0.1.4",
- "windows-sys 0.42.0",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -10996,9 +10987,9 @@
[[package]]
name = "security-framework"
-version = "2.8.1"
+version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c4437699b6d34972de58652c68b98cb5b53a4199ab126db8e20ec8ded29a721"
+checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
dependencies = [
"bitflags",
"core-foundation",
@@ -11072,9 +11063,9 @@
[[package]]
name = "serde_json"
-version = "1.0.91"
+version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
+checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a"
dependencies = [
"itoa",
"ryu",
@@ -11206,26 +11197,6 @@
]
[[package]]
-name = "similar"
-version = "2.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
-dependencies = [
- "bstr 0.2.17",
- "unicode-segmentation",
-]
-
-[[package]]
-name = "similar-asserts"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbf644ad016b75129f01a34a355dcb8d66a5bc803e417c7a77cc5d5ee9fa0f18"
-dependencies = [
- "console",
- "similar",
-]
-
-[[package]]
name = "slab"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -11275,14 +11246,14 @@
[[package]]
name = "snow"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d"
+checksum = "12ba5f4d4ff12bdb6a169ed51b7c48c0e0ac4b0b4b31012b2571e97d78d3201d"
dependencies = [
"aes-gcm 0.9.4",
"blake2",
"chacha20poly1305",
- "curve25519-dalek 4.0.0-pre.5",
+ "curve25519-dalek 4.0.0-rc.0",
"rand_core 0.6.4",
"ring",
"rustc_version 0.4.0",
@@ -12031,6 +12002,28 @@
]
[[package]]
+name = "spez"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "304d2fd6a79879f77b207ba8cd5079c22f872eaad65a3fb8d71799e5bacf368b"
+dependencies = [
+ "proc-macro-hack",
+ "spez-macros",
+]
+
+[[package]]
+name = "spez-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7fa06037d8ccb6cdadc151129062ebc9e4281c1ea44b2c704582245d017d1dc"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -12612,15 +12605,15 @@
[[package]]
name = "tinyvec_macros"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.24.2"
+version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
+checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af"
dependencies = [
"autocfg",
"bytes",
@@ -12702,9 +12695,9 @@
[[package]]
name = "toml_edit"
-version = "0.18.0"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "729bfd096e40da9c001f778f5cdecbd2957929a24e10e5883d9392220a751581"
+checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
dependencies = [
"indexmap",
"nom8",
@@ -12976,21 +12969,6 @@
"sp-weights",
"substrate-rpc-client",
"zstd",
-]
-
-[[package]]
-name = "trybuild"
-version = "1.0.76"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed2c57956f91546d4d33614265a85d55c8e1ab91484853a10335894786d7db6"
-dependencies = [
- "glob",
- "once_cell",
- "serde",
- "serde_derive",
- "serde_json",
- "termcolor",
- "toml",
]
[[package]]
@@ -13108,12 +13086,6 @@
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"
@@ -13446,9 +13418,9 @@
[[package]]
name = "uuid"
-version = "1.2.2"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
+checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
dependencies = [
"getrandom 0.2.8",
]
@@ -13543,9 +13515,9 @@
[[package]]
name = "wasm-bindgen"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -13553,9 +13525,9 @@
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
dependencies = [
"bumpalo",
"log",
@@ -13568,9 +13540,9 @@
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.33"
+version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
+checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
dependencies = [
"cfg-if",
"js-sys",
@@ -13580,9 +13552,9 @@
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -13590,9 +13562,9 @@
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
dependencies = [
"proc-macro2",
"quote",
@@ -13603,9 +13575,9 @@
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "wasm-instrument"
@@ -13886,9 +13858,9 @@
[[package]]
name = "web-sys"
-version = "0.3.60"
+version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
+checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -14338,6 +14310,30 @@
]
[[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.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.1",
+ "windows_i686_gnu 0.42.1",
+ "windows_i686_msvc 0.42.1",
+ "windows_x86_64_gnu 0.42.1",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.1",
+]
+
+[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -14644,9 +14640,9 @@
[[package]]
name = "zstd-sys"
-version = "2.0.5+zstd.1.5.2"
+version = "2.0.6+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edc50ffce891ad571e9f9afe5039c4837bede781ac4bb13052ed7ae695518596"
+checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b"
dependencies = [
"cc",
"libc",
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,7 @@
[workspace.dependencies]
# Unique
-evm-coder = { default-features = false, path = "crates/evm-coder" }
+evm-coder = { git = "https://github.com/uniquenetwork/evm-coder", tag = "v0.3.0", default-features = false }
struct-versioning = { path = "crates/struct-versioning" }
precompile-utils-macro = { path = "runtime/common/ethereum/precompiles/utils/macro" }
up-common = { path = "primitives/common", default-features = false }
crates/evm-coder/CHANGELOG.mddiffbeforeafterboth--- a/crates/evm-coder/CHANGELOG.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-
-<!-- bureaucrate goes here -->
-## [v0.1.6] - 2023-01-12
-
-### Added
-- Support Option<T> type.
-### Removed
-- Frontier dependency.
-
-## [v0.1.5] - 2022-11-30
-
-### Added
-- Derive macro to support structures and enums.
-
-## [v0.1.4] - 2022-11-02
-
-### Added
-
-- Named structures support.
-
-## [v0.1.3] - 2022-08-29
-
-### Fixed
-
-- Parsing simple values.
-
-## [v0.1.2] 2022-08-19
-
-### Added
-
-- Implementation `AbiWrite` for tuples.
-
-### Fixes
-
-- Tuple generation for solidity.
-
-## [v0.1.1] 2022-08-16
-
-### Other changes
-
-- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
-
-- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
-
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
crates/evm-coder/Cargo.tomldiffbeforeafterboth--- a/crates/evm-coder/Cargo.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-[package]
-edition = "2021"
-license = "GPLv3"
-name = "evm-coder"
-version = "0.1.6"
-
-[dependencies]
-sha3-const = { version = "0.1.1", default-features = false }
-# evm-coder reexports those proc-macro
-evm-coder-procedural = { path = "./procedural" }
-# Evm uses primitive-types for H160, H256 and others
-primitive-types = { workspace = true }
-# Evm doesn't have reexports for log and others
-ethereum = { workspace = true }
-frame-support = { workspace = true }
-# Error types for execution
-evm-core = { workspace = true }
-# We have tuple-heavy code in solidity.rs
-impl-trait-for-tuples = { workspace = true }
-
-[dev-dependencies]
-# We want to assert some large binary blobs equality in tests
-hex = "0.4.3"
-hex-literal = { workspace = true }
-similar-asserts = "1.4.2"
-trybuild = "1.0"
-
-[features]
-default = ["std"]
-std = ["ethereum/std", "evm-core/std", "frame-support/std", "primitive-types/std"]
-# Stub/interface generation
-stubgen = []
crates/evm-coder/README.mddiffbeforeafterboth--- a/crates/evm-coder/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# evm-coder
-
-Library for seamless call translation between Rust and Solidity code
-
-By encoding solidity definitions in Rust, this library also provides generation of
-solidity interfaces for ethereum developers
-
-## Overview
-
-Most of this library functionality shouldn't be used directly, but via macros
-
-- [`solidity_interface`]
-- [`ToLog`]
-
-<!-- TODO: make links useable on github, by publishing crate to docs.rs, and linking it from here instead -->
\ No newline at end of file
crates/evm-coder/procedural/Cargo.tomldiffbeforeafterboth--- a/crates/evm-coder/procedural/Cargo.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[package]
-edition = "2021"
-license = "GPLv3"
-name = "evm-coder-procedural"
-version = "0.2.3"
-
-[lib]
-proc-macro = true
-
-[dependencies]
-# Ethereum uses keccak (=sha3) for selectors
-sha3 = "0.10.1"
-# Value formatting
-Inflector = "0.11.4"
-hex = "0.4.3"
-# General proc-macro utilities
-proc-macro2 = "1.0"
-quote = "1.0"
-syn = { version = "1.0", features = ["full"] }
crates/evm-coder/procedural/src/abi_derive/derive_enum.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/abi_derive/derive_enum.rs
+++ /dev/null
@@ -1,199 +0,0 @@
-use quote::quote;
-
-use super::extract_docs;
-
-pub fn impl_solidity_option<'a>(
- docs: Vec<String>,
- name: &proc_macro2::Ident,
- enum_options: impl Iterator<Item = &'a syn::Variant> + Clone,
-) -> proc_macro2::TokenStream {
- let variant_names = enum_options.clone().map(|opt| {
- let opt = &opt.ident;
- let s = name.to_string() + "." + opt.to_string().as_str();
- let as_string = proc_macro2::Literal::string(s.as_str());
- quote!(#name::#opt => #as_string,)
- });
- let solidity_name = name.to_string();
-
- let solidity_fields = enum_options.map(|v| {
- let docs = extract_docs(&v.attrs).expect("TODO: handle bad docs");
- let name = v.ident.to_string();
- quote! {
- SolidityEnumVariant {
- docs: &[#(#docs),*],
- name: #name,
- }
- }
- });
-
- quote!(
- #[cfg(feature = "stubgen")]
- impl ::evm_coder::solidity::SolidityEnumTy for #name {
- fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector) -> String {
- use evm_coder::solidity::*;
- use core::fmt::Write;
- let interface = SolidityEnum {
- docs: &[#(#docs),*],
- name: #solidity_name,
- fields: &[#(
- #solidity_fields,
- )*],
- };
- let mut out = String::new();
- let _ = interface.format(&mut out, tc);
- tc.collect(out);
- #solidity_name.to_string()
- }
- fn solidity_option(&self) -> &str {
- match self {
- #(#variant_names)*
- }
- }
- }
- )
-}
-
-pub fn impl_enum_from_u8<'a>(
- name: &proc_macro2::Ident,
- enum_options: impl Iterator<Item = &'a syn::Variant>,
-) -> proc_macro2::TokenStream {
- let error_str = format!("Value not convertible into enum \"{name}\"");
- let error_str = proc_macro2::Literal::string(&error_str);
- let enum_options = enum_options.enumerate().map(|(i, opt)| {
- let opt = &opt.ident;
- let n = proc_macro2::Literal::u8_suffixed(i as u8);
- quote! {#n => Ok(#name::#opt),}
- });
-
- quote!(
- impl TryFrom<u8> for #name {
- type Error = &'static str;
-
- fn try_from(value: u8) -> ::core::result::Result<Self, Self::Error> {
- const err: &'static str = #error_str;
- match value {
- #(#enum_options)*
- _ => Err(err)
- }
- }
- }
- )
-}
-
-pub fn impl_enum_abi_type(name: &syn::Ident) -> proc_macro2::TokenStream {
- quote! {
- impl ::evm_coder::abi::AbiType for #name {
- const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = <u8 as ::evm_coder::abi::AbiType>::SIGNATURE;
-
- fn is_dynamic() -> bool {
- <u8 as ::evm_coder::abi::AbiType>::is_dynamic()
- }
- fn size() -> usize {
- <u8 as ::evm_coder::abi::AbiType>::size()
- }
- }
- }
-}
-
-pub fn impl_enum_abi_read(name: &syn::Ident) -> proc_macro2::TokenStream {
- quote!(
- impl ::evm_coder::abi::AbiRead for #name {
- fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Self> {
- Ok(
- <u8 as ::evm_coder::abi::AbiRead>::abi_read(reader)?
- .try_into()?
- )
- }
- }
- )
-}
-
-pub fn impl_enum_abi_write(name: &syn::Ident) -> proc_macro2::TokenStream {
- quote!(
- impl ::evm_coder::abi::AbiWrite for #name {
- fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) {
- ::evm_coder::abi::AbiWrite::abi_write(&(*self as u8), writer);
- }
- }
- )
-}
-
-pub fn impl_enum_solidity_type_name(name: &syn::Ident) -> proc_macro2::TokenStream {
- quote!(
- #[cfg(feature = "stubgen")]
- impl ::evm_coder::solidity::SolidityTypeName for #name {
- fn solidity_name(
- writer: &mut impl ::core::fmt::Write,
- tc: &::evm_coder::solidity::TypeCollector,
- ) -> ::core::fmt::Result {
- write!(writer, "{}", tc.collect_enum::<Self>())
- }
-
- fn is_simple() -> bool {
- true
- }
-
- fn solidity_default(
- writer: &mut impl ::core::fmt::Write,
- tc: &::evm_coder::solidity::TypeCollector,
- ) -> ::core::fmt::Result {
- write!(writer, "{}", <#name as ::evm_coder::solidity::SolidityEnumTy>::solidity_option(&<#name>::default()))
- }
- }
- )
-}
-
-pub fn check_enum_fields(de: &syn::DataEnum) -> syn::Result<()> {
- for v in de.variants.iter() {
- if !v.fields.is_empty() {
- return Err(syn::Error::new(
- v.ident.span(),
- "Enumeration parameters should not have fields",
- ));
- } else if v.discriminant.is_some() {
- return Err(syn::Error::new(
- v.ident.span(),
- "Enumeration options should not have an explicit specified value",
- ));
- }
- }
-
- Ok(())
-}
-
-pub fn check_repr_u8(name: &syn::Ident, attrs: &[syn::Attribute]) -> syn::Result<()> {
- let mut has_repr = false;
- for attr in attrs.iter() {
- if attr.path.is_ident("repr") {
- has_repr = true;
- let meta = attr.parse_meta()?;
- check_meta_u8(&meta)?;
- }
- }
-
- if !has_repr {
- return Err(syn::Error::new(name.span(), "Enum is not \"repr(u8)\""));
- }
-
- Ok(())
-}
-
-fn check_meta_u8(meta: &syn::Meta) -> Result<(), syn::Error> {
- if let syn::Meta::List(p) = meta {
- for nm in p.nested.iter() {
- if let syn::NestedMeta::Meta(syn::Meta::Path(p)) = nm {
- if !p.is_ident("u8") {
- return Err(syn::Error::new(
- p.segments
- .first()
- .expect("repr segments are empty")
- .ident
- .span(),
- "Enum is not \"repr(u8)\"",
- ));
- }
- }
- }
- }
- Ok(())
-}
crates/evm-coder/procedural/src/abi_derive/derive_struct.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs
+++ /dev/null
@@ -1,231 +0,0 @@
-use super::extract_docs;
-use quote::quote;
-use syn::Field;
-
-pub fn tuple_type<'a>(
- field_types: impl Iterator<Item = &'a syn::Type> + Clone,
-) -> proc_macro2::TokenStream {
- let field_types = field_types.map(|ty| quote!(#ty,));
- quote! {(#(#field_types)*)}
-}
-
-pub fn tuple_ref_type<'a>(
- field_types: impl Iterator<Item = &'a syn::Type> + Clone,
-) -> proc_macro2::TokenStream {
- let field_types = field_types.map(|ty| quote!(&#ty,));
- quote! {(#(#field_types)*)}
-}
-
-pub fn tuple_data_as_ref(
- is_named_fields: bool,
- field_names: impl Iterator<Item = syn::Ident> + Clone,
-) -> proc_macro2::TokenStream {
- let field_names = field_names.enumerate().map(|(i, field)| {
- if is_named_fields {
- quote!(&self.#field,)
- } else {
- let field = proc_macro2::Literal::usize_unsuffixed(i);
- quote!(&self.#field,)
- }
- });
- quote! {(#(#field_names)*)}
-}
-
-pub fn tuple_names(
- is_named_fields: bool,
- field_names: impl Iterator<Item = syn::Ident> + Clone,
-) -> proc_macro2::TokenStream {
- let field_names = field_names.enumerate().map(|(i, field)| {
- if is_named_fields {
- quote!(#field,)
- } else {
- let field = proc_macro2::Ident::new(
- format!("field{}", i).as_str(),
- proc_macro2::Span::call_site(),
- );
- quote!(#field,)
- }
- });
- quote! {(#(#field_names)*)}
-}
-
-pub fn struct_from_tuple(
- name: &syn::Ident,
- is_named_fields: bool,
- field_names: impl Iterator<Item = syn::Ident> + Clone,
-) -> proc_macro2::TokenStream {
- let field_names = field_names.enumerate().map(|(i, field)| {
- if is_named_fields {
- quote!(#field,)
- } else {
- let field = proc_macro2::Ident::new(
- format!("field{}", i).as_str(),
- proc_macro2::Span::call_site(),
- );
- quote!(#field,)
- }
- });
-
- if is_named_fields {
- quote! {#name {#(#field_names)*}}
- } else {
- quote! {#name (#(#field_names)*)}
- }
-}
-
-pub fn map_field_to_name(field: (usize, &syn::Field)) -> syn::Ident {
- match field.1.ident.as_ref() {
- Some(name) => name.clone(),
- None => {
- let mut name = "field".to_string();
- name.push_str(field.0.to_string().as_str());
- syn::Ident::new(name.as_str(), proc_macro2::Span::call_site())
- }
- }
-}
-
-pub fn map_field_to_type(field: &syn::Field) -> &syn::Type {
- &field.ty
-}
-
-pub fn impl_can_be_placed_in_vec(ident: &syn::Ident) -> proc_macro2::TokenStream {
- quote! {
- impl ::evm_coder::sealed::CanBePlacedInVec for #ident {}
- }
-}
-
-pub fn impl_struct_abi_type(
- name: &syn::Ident,
- tuple_type: proc_macro2::TokenStream,
-) -> proc_macro2::TokenStream {
- quote! {
- impl ::evm_coder::abi::AbiType for #name {
- const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = <#tuple_type as ::evm_coder::abi::AbiType>::SIGNATURE;
- fn is_dynamic() -> bool {
- <#tuple_type as ::evm_coder::abi::AbiType>::is_dynamic()
- }
- fn size() -> usize {
- <#tuple_type as ::evm_coder::abi::AbiType>::size()
- }
- }
- }
-}
-
-pub fn impl_struct_abi_read(
- name: &syn::Ident,
- tuple_type: proc_macro2::TokenStream,
- tuple_names: proc_macro2::TokenStream,
- struct_from_tuple: proc_macro2::TokenStream,
-) -> proc_macro2::TokenStream {
- quote!(
- impl ::evm_coder::abi::AbiRead for #name {
- fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Self> {
- let #tuple_names = <#tuple_type as ::evm_coder::abi::AbiRead>::abi_read(reader)?;
- Ok(#struct_from_tuple)
- }
- }
- )
-}
-
-pub fn impl_struct_abi_write(
- name: &syn::Ident,
- _is_named_fields: bool,
- tuple_type: proc_macro2::TokenStream,
- tuple_data: proc_macro2::TokenStream,
-) -> proc_macro2::TokenStream {
- quote!(
- impl ::evm_coder::abi::AbiWrite for #name {
- fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) {
- <#tuple_type as ::evm_coder::abi::AbiWrite>::abi_write(&#tuple_data, writer)
- }
- }
- )
-}
-
-pub fn impl_struct_solidity_type<'a>(
- name: &syn::Ident,
- docs: Vec<String>,
- fields: impl Iterator<Item = &'a Field> + Clone,
-) -> proc_macro2::TokenStream {
- let solidity_name = name.to_string();
- let solidity_fields = fields.enumerate().map(|(i, f)| {
- let name = f
- .ident
- .as_ref()
- .map(|i| i.to_string())
- .unwrap_or_else(|| format!("field_{i}"));
- let ty = &f.ty;
- let docs = extract_docs(&f.attrs).expect("TODO: handle bad docs");
- quote! {
- SolidityStructField::<#ty> {
- docs: &[#(#docs),*],
- name: #name,
- ty: ::core::marker::PhantomData,
- }
- }
- });
- quote! {
- #[cfg(feature = "stubgen")]
- impl ::evm_coder::solidity::SolidityStructTy for #name {
- /// Generate solidity definitions for methods described in this struct
- fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector) -> String {
- use evm_coder::solidity::*;
- use core::fmt::Write;
- let interface = SolidityStruct {
- docs: &[#(#docs),*],
- name: #solidity_name,
- fields: (#(
- #solidity_fields,
- )*),
- };
- let mut out = String::new();
- let _ = interface.format(&mut out, tc);
- tc.collect(out);
- #solidity_name.to_string()
- }
- }
- }
-}
-
-pub fn impl_struct_solidity_type_name<'a>(
- name: &syn::Ident,
- field_types: impl Iterator<Item = &'a syn::Type> + Clone,
- params_count: usize,
-) -> proc_macro2::TokenStream {
- let arg_dafaults = field_types.enumerate().map(|(i, ty)| {
- let mut defult_value = quote!(<#ty as ::evm_coder::solidity::SolidityTypeName
- >::solidity_default(writer, tc)?;);
- let last_item = params_count - 1;
- if i != last_item {
- defult_value.extend(quote! {write!(writer, ",")?;})
- }
- defult_value
- });
-
- quote! {
- #[cfg(feature = "stubgen")]
- impl ::evm_coder::solidity::SolidityTypeName for #name {
- fn solidity_name(
- writer: &mut impl ::core::fmt::Write,
- tc: &::evm_coder::solidity::TypeCollector,
- ) -> ::core::fmt::Result {
- write!(writer, "{}", tc.collect_struct::<Self>())
- }
-
- fn is_simple() -> bool {
- false
- }
-
- fn solidity_default(
- writer: &mut impl ::core::fmt::Write,
- tc: &::evm_coder::solidity::TypeCollector,
- ) -> ::core::fmt::Result {
- write!(writer, "{}(", tc.collect_struct::<Self>())?;
-
- #(#arg_dafaults)*
-
- write!(writer, ")")
- }
- }
- }
-}
crates/evm-coder/procedural/src/abi_derive/mod.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/abi_derive/mod.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-mod derive_enum;
-mod derive_struct;
-
-use quote::quote;
-use derive_struct::*;
-use derive_enum::*;
-
-pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
- let name = &ast.ident;
- match &ast.data {
- syn::Data::Struct(ds) => expand_struct(ds, ast),
- syn::Data::Enum(de) => expand_enum(de, ast),
- syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")),
- }
-}
-
-fn expand_struct(
- ds: &syn::DataStruct,
- ast: &syn::DeriveInput,
-) -> syn::Result<proc_macro2::TokenStream> {
- let name = &ast.ident;
- let docs = extract_docs(&ast.attrs)?;
- let (is_named_fields, field_names, field_types, params_count) = match ds.fields {
- syn::Fields::Named(ref fields) => Ok((
- true,
- fields.named.iter().enumerate().map(map_field_to_name),
- fields.named.iter().map(map_field_to_type),
- fields.named.len(),
- )),
- syn::Fields::Unnamed(ref fields) => Ok((
- false,
- fields.unnamed.iter().enumerate().map(map_field_to_name),
- fields.unnamed.iter().map(map_field_to_type),
- fields.unnamed.len(),
- )),
- syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")),
- }?;
-
- if params_count == 0 {
- return Err(syn::Error::new(name.span(), "Empty structs not supported"));
- };
-
- let tuple_type = tuple_type(field_types.clone());
- let tuple_ref_type = tuple_ref_type(field_types.clone());
- let tuple_data = tuple_data_as_ref(is_named_fields, field_names.clone());
- let tuple_names = tuple_names(is_named_fields, field_names.clone());
- let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone());
-
- let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
- let abi_type = impl_struct_abi_type(name, tuple_type.clone());
- let abi_read = impl_struct_abi_read(name, tuple_type, tuple_names, struct_from_tuple);
- let abi_write = impl_struct_abi_write(name, is_named_fields, tuple_ref_type, tuple_data);
- let solidity_type = impl_struct_solidity_type(name, docs, ds.fields.iter());
- let solidity_type_name =
- impl_struct_solidity_type_name(name, field_types.clone(), params_count);
-
- Ok(quote! {
- #can_be_plcaed_in_vec
- #abi_type
- #abi_read
- #abi_write
- #solidity_type
- #solidity_type_name
- })
-}
-
-fn expand_enum(
- de: &syn::DataEnum,
- ast: &syn::DeriveInput,
-) -> syn::Result<proc_macro2::TokenStream> {
- let name = &ast.ident;
- check_repr_u8(name, &ast.attrs)?;
- check_enum_fields(de)?;
- let docs = extract_docs(&ast.attrs)?;
- let enum_options = de.variants.iter();
-
- let from = impl_enum_from_u8(name, enum_options.clone());
- let solidity_option = impl_solidity_option(docs, name, enum_options.clone());
- let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
- let abi_type = impl_enum_abi_type(name);
- let abi_read = impl_enum_abi_read(name);
- let abi_write = impl_enum_abi_write(name);
- let solidity_type_name = impl_enum_solidity_type_name(name);
-
- Ok(quote! {
- #from
- #solidity_option
- #can_be_plcaed_in_vec
- #abi_type
- #abi_read
- #abi_write
- #solidity_type_name
- })
-}
-
-fn extract_docs(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> {
- attrs
- .iter()
- .filter_map(|attr| {
- if let Some(ps) = attr.path.segments.first() {
- if ps.ident == "doc" {
- let meta = match attr.parse_meta() {
- Ok(meta) => meta,
- Err(e) => return Some(Err(e)),
- };
- match meta {
- syn::Meta::NameValue(mnv) => match &mnv.lit {
- syn::Lit::Str(ls) => return Some(Ok(ls.value())),
- _ => unreachable!(),
- },
- _ => unreachable!(),
- }
- }
- }
- None
- })
- .collect()
-}
crates/evm-coder/procedural/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/lib.rs
+++ /dev/null
@@ -1,255 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#![allow(dead_code)]
-
-use inflector::cases;
-use proc_macro::TokenStream;
-use quote::quote;
-use sha3::{Digest, Keccak256};
-use syn::{
- DeriveInput, GenericArgument, Ident, ItemImpl, Pat, Path, PathArguments, PathSegment, Type,
- parse_macro_input, spanned::Spanned,
-};
-
-mod abi_derive;
-mod solidity_interface;
-mod to_log;
-
-fn fn_selector_str(input: &str) -> u32 {
- let mut hasher = Keccak256::new();
- hasher.update(input.as_bytes());
- let result = hasher.finalize();
-
- let mut selector_bytes = [0; 4];
- selector_bytes.copy_from_slice(&result[0..4]);
-
- u32::from_be_bytes(selector_bytes)
-}
-
-/// Returns solidity function selector (first 4 bytes of hash) by its
-/// textual representation
-///
-/// ```ignore
-/// use evm_coder_macros::fn_selector;
-///
-/// assert_eq!(fn_selector!(transfer(address, uint256)), 0xa9059cbb);
-/// ```
-#[proc_macro]
-pub fn fn_selector(input: TokenStream) -> TokenStream {
- let input = input.to_string().replace(' ', "");
- let selector = fn_selector_str(&input);
-
- (quote! {
- #selector
- })
- .into()
-}
-
-fn event_selector_str(input: &str) -> [u8; 32] {
- let mut hasher = Keccak256::new();
- hasher.update(input.as_bytes());
- let result = hasher.finalize();
-
- let mut selector_bytes = [0; 32];
- selector_bytes.copy_from_slice(&result[0..32]);
- selector_bytes
-}
-
-/// Returns solidity topic (hash) by its textual representation
-///
-/// ```ignore
-/// use evm_coder_macros::event_topic;
-///
-/// assert_eq!(
-/// format!("{:x}", event_topic!(Transfer(address, address, uint256))),
-/// "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
-/// );
-/// ```
-#[proc_macro]
-pub fn event_topic(stream: TokenStream) -> TokenStream {
- let input = stream.to_string().replace(' ', "");
- let selector_bytes = event_selector_str(&input);
-
- (quote! {
- ::primitive_types::H256([#(
- #selector_bytes,
- )*])
- })
- .into()
-}
-
-fn parse_path(ty: &Type) -> syn::Result<&Path> {
- match &ty {
- syn::Type::Path(pat) => {
- if let Some(qself) = &pat.qself {
- return Err(syn::Error::new(qself.ty.span(), "no receiver expected"));
- }
- Ok(&pat.path)
- }
- _ => Err(syn::Error::new(ty.span(), "expected ty to be path")),
- }
-}
-
-fn parse_path_segment(path: &Path) -> syn::Result<&PathSegment> {
- if path.segments.len() != 1 {
- return Err(syn::Error::new(
- path.span(),
- "expected path to have only one segment",
- ));
- }
- let last_segment = &path.segments.last().unwrap();
- Ok(last_segment)
-}
-
-fn parse_ident_from_pat(pat: &Pat) -> syn::Result<&Ident> {
- match pat {
- Pat::Ident(i) => Ok(&i.ident),
- _ => Err(syn::Error::new(pat.span(), "expected pat ident")),
- }
-}
-
-fn parse_ident_from_segment(segment: &PathSegment, allow_generics: bool) -> syn::Result<&Ident> {
- if segment.arguments != PathArguments::None && !allow_generics {
- return Err(syn::Error::new(
- segment.arguments.span(),
- "unexpected generic type",
- ));
- }
- Ok(&segment.ident)
-}
-
-fn parse_ident_from_path(path: &Path, allow_generics: bool) -> syn::Result<&Ident> {
- let segment = parse_path_segment(path)?;
- parse_ident_from_segment(segment, allow_generics)
-}
-
-fn parse_ident_from_type(ty: &Type, allow_generics: bool) -> syn::Result<&Ident> {
- let path = parse_path(ty)?;
- parse_ident_from_path(path, allow_generics)
-}
-
-// Gets T out of Result<T>
-fn parse_result_ok(ty: &Type) -> syn::Result<&Type> {
- let path = parse_path(ty)?;
- let segment = parse_path_segment(path)?;
-
- if segment.ident != "Result" {
- return Err(syn::Error::new(
- ty.span(),
- "expected Result as return type (no renamed aliases allowed)",
- ));
- }
- let args = match &segment.arguments {
- PathArguments::AngleBracketed(e) => e,
- _ => {
- return Err(syn::Error::new(
- segment.arguments.span(),
- "missing Result generics",
- ))
- }
- };
-
- let args = &args.args;
- let arg = args.first().unwrap();
-
- let ty = match arg {
- GenericArgument::Type(ty) => ty,
- _ => {
- return Err(syn::Error::new(
- arg.span(),
- "expected first generic to be type",
- ))
- }
- };
-
- Ok(ty)
-}
-
-fn pascal_ident_to_call(ident: &Ident) -> Ident {
- let name = format!("{}Call", ident);
- Ident::new(&name, ident.span())
-}
-fn snake_ident_to_pascal(ident: &Ident) -> Ident {
- let name = ident.to_string();
- let name = cases::pascalcase::to_pascal_case(&name);
- Ident::new(&name, ident.span())
-}
-fn snake_ident_to_screaming(ident: &Ident) -> Ident {
- let name = ident.to_string();
- let name = cases::screamingsnakecase::to_screaming_snake_case(&name);
- Ident::new(&name, ident.span())
-}
-fn pascal_ident_to_snake_call(ident: &Ident) -> Ident {
- let name = ident.to_string();
- let name = cases::snakecase::to_snake_case(&name);
- let name = format!("call_{}", name);
- Ident::new(&name, ident.span())
-}
-
-/// See documentation for this proc-macro reexported in `evm-coder` crate
-#[proc_macro_attribute]
-pub fn solidity_interface(args: TokenStream, stream: TokenStream) -> TokenStream {
- let args = parse_macro_input!(args as solidity_interface::InterfaceInfo);
-
- let input: ItemImpl = match syn::parse(stream) {
- Ok(t) => t,
- Err(e) => return e.to_compile_error().into(),
- };
-
- let expanded = match solidity_interface::SolidityInterface::try_from(args, &input) {
- Ok(v) => v.expand(),
- Err(e) => e.to_compile_error(),
- };
-
- (quote! {
- #input
-
- #expanded
- })
- .into()
-}
-
-#[proc_macro_attribute]
-pub fn solidity(_args: TokenStream, stream: TokenStream) -> TokenStream {
- stream
-}
-#[proc_macro_attribute]
-pub fn weight(_args: TokenStream, stream: TokenStream) -> TokenStream {
- stream
-}
-
-/// See documentation for this proc-macro reexported in `evm-coder` crate
-#[proc_macro_derive(ToLog, attributes(indexed))]
-pub fn to_log(value: TokenStream) -> TokenStream {
- let input = parse_macro_input!(value as DeriveInput);
-
- match to_log::Events::try_from(&input) {
- Ok(e) => e.expand(),
- Err(e) => e.to_compile_error(),
- }
- .into()
-}
-
-#[proc_macro_derive(AbiCoder)]
-pub fn abi_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
- let ast = syn::parse(input).unwrap();
- let ts = match abi_derive::impl_abi_macro(&ast) {
- Ok(e) => e,
- Err(e) => e.to_compile_error(),
- };
- ts.into()
-}
crates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ /dev/null
@@ -1,1099 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#![allow(dead_code)]
-
-// NOTE: In order to understand this Rust macro better, first read this chapter
-// about Procedural Macros in Rust book:
-// https://doc.rust-lang.org/reference/procedural-macros.html
-
-use proc_macro2::TokenStream;
-use quote::{quote, format_ident};
-use inflector::cases;
-use syn::{
- Expr, FnArg, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta, MetaNameValue,
- PatType, ReturnType, Type,
- spanned::Spanned,
- parse::{Parse, ParseStream},
- parenthesized, Token, LitInt, LitStr,
-};
-
-use crate::{
- parse_ident_from_pat, parse_ident_from_path, parse_path, parse_path_segment, parse_result_ok,
- pascal_ident_to_call, pascal_ident_to_snake_call, snake_ident_to_pascal,
- snake_ident_to_screaming,
-};
-
-struct Is {
- name: Ident,
- pascal_call_name: Ident,
- snake_call_name: Ident,
- via: Option<(Type, Ident)>,
- condition: Option<Expr>,
-}
-impl Is {
- fn expand_call_def(&self, gen_ref: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
- let name = &self.name;
- let pascal_call_name = &self.pascal_call_name;
- quote! {
- #name(#pascal_call_name #gen_ref)
- }
- }
-
- fn expand_interface_id(&self) -> proc_macro2::TokenStream {
- let pascal_call_name = &self.pascal_call_name;
- quote! {
- interface_id ^= u32::from_be_bytes(#pascal_call_name::interface_id());
- }
- }
-
- fn expand_supports_interface(
- &self,
- generics: &proc_macro2::TokenStream,
- ) -> proc_macro2::TokenStream {
- let pascal_call_name = &self.pascal_call_name;
- let condition = self.condition.as_ref().map(|condition| {
- quote! {
- (#condition) &&
- }
- });
- quote! {
- #condition <#pascal_call_name #generics>::supports_interface(this, interface_id)
- }
- }
-
- fn expand_variant_weight(&self) -> proc_macro2::TokenStream {
- let name = &self.name;
- quote! {
- Self::#name(call) => call.weight()
- }
- }
-
- fn expand_variant_call(
- &self,
- call_name: &proc_macro2::Ident,
- generics: &proc_macro2::TokenStream,
- ) -> proc_macro2::TokenStream {
- let name = &self.name;
- let pascal_call_name = &self.pascal_call_name;
- let via_typ = self
- .via
- .as_ref()
- .map(|(t, _)| quote! {#t})
- .unwrap_or_else(|| quote! {Self});
- let via_map = self
- .via
- .as_ref()
- .map(|(_, i)| quote! {.#i()})
- .unwrap_or_default();
- let condition = self.condition.as_ref().map(|condition| {
- quote! {
- if ({let this = &self; (#condition)})
- }
- });
- quote! {
- #call_name::#name(call) #condition => return <#via_typ as ::evm_coder::Callable<#pascal_call_name #generics>>::call(self #via_map, Msg {
- call,
- caller: c.caller,
- value: c.value,
- })
- }
- }
-
- fn expand_parse(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
- let name = &self.name;
- let pascal_call_name = &self.pascal_call_name;
- quote! {
- if let Some(parsed_call) = <#pascal_call_name #generics>::parse(method_id, reader)? {
- return Ok(Some(Self::#name(parsed_call)))
- }
- }
- }
-
- fn expand_generator(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
- let pascal_call_name = &self.pascal_call_name;
- quote! {
- <#pascal_call_name #generics>::generate_solidity_interface(tc, is_impl);
- }
- }
-
- fn expand_event_generator(&self) -> proc_macro2::TokenStream {
- let name = &self.name;
- quote! {
- #name::generate_solidity_interface(tc, is_impl);
- }
- }
-}
-
-#[derive(Default)]
-struct IsList(Vec<Is>);
-impl Parse for IsList {
- fn parse(input: ParseStream) -> syn::Result<Self> {
- let mut out = vec![];
- loop {
- if input.is_empty() {
- break;
- }
- let name = input.parse::<Ident>()?;
- let lookahead = input.lookahead1();
-
- let mut condition: Option<Expr> = None;
- let mut via: Option<(Type, Ident)> = None;
-
- if lookahead.peek(syn::token::Paren) {
- let contents;
- parenthesized!(contents in input);
- let input = contents;
-
- while !input.is_empty() {
- let lookahead = input.lookahead1();
- if lookahead.peek(Token![if]) {
- input.parse::<Token![if]>()?;
- let contents;
- parenthesized!(contents in input);
- let contents = contents.parse::<Expr>()?;
-
- if condition.replace(contents).is_some() {
- return Err(syn::Error::new(input.span(), "condition is already set"));
- }
- } else if lookahead.peek(kw::via) {
- input.parse::<kw::via>()?;
- let contents;
- parenthesized!(contents in input);
-
- let method = contents.parse::<Ident>()?;
- contents.parse::<kw::returns>()?;
- let ty = contents.parse::<Type>()?;
-
- if via.replace((ty, method)).is_some() {
- return Err(syn::Error::new(input.span(), "via is already set"));
- }
- } else {
- return Err(lookahead.error());
- }
-
- if input.peek(Token![,]) {
- input.parse::<Token![,]>()?;
- } else if !input.is_empty() {
- return Err(syn::Error::new(input.span(), "expected end"));
- }
- }
- } else if lookahead.peek(Token![,]) || input.is_empty() {
- // Pass
- } else {
- return Err(lookahead.error());
- };
- out.push(Is {
- pascal_call_name: pascal_ident_to_call(&name),
- snake_call_name: pascal_ident_to_snake_call(&name),
- name,
- via,
- condition,
- });
- if input.peek(Token![,]) {
- input.parse::<Token![,]>()?;
- continue;
- } else {
- break;
- }
- }
- Ok(Self(out))
- }
-}
-
-pub struct InterfaceInfo {
- name: Ident,
- is: IsList,
- inline_is: IsList,
- events: IsList,
- expect_selector: Option<u32>,
-}
-impl Parse for InterfaceInfo {
- fn parse(input: ParseStream) -> syn::Result<Self> {
- let mut name = None;
- let mut is = None;
- let mut inline_is = None;
- let mut events = None;
- let mut expect_selector = None;
- // TODO: create proc-macro to optimize proc-macro boilerplate? :D
- loop {
- let lookahead = input.lookahead1();
- if lookahead.peek(kw::name) {
- let k = input.parse::<kw::name>()?;
- input.parse::<Token![=]>()?;
- if name.replace(input.parse::<Ident>()?).is_some() {
- return Err(syn::Error::new(k.span(), "name is already set"));
- }
- } else if lookahead.peek(kw::is) {
- let k = input.parse::<kw::is>()?;
- let contents;
- parenthesized!(contents in input);
- if is.replace(contents.parse::<IsList>()?).is_some() {
- return Err(syn::Error::new(k.span(), "is is already set"));
- }
- } else if lookahead.peek(kw::inline_is) {
- let k = input.parse::<kw::inline_is>()?;
- let contents;
- parenthesized!(contents in input);
- if inline_is.replace(contents.parse::<IsList>()?).is_some() {
- return Err(syn::Error::new(k.span(), "inline_is is already set"));
- }
- } else if lookahead.peek(kw::events) {
- let k = input.parse::<kw::events>()?;
- let contents;
- parenthesized!(contents in input);
- if events.replace(contents.parse::<IsList>()?).is_some() {
- return Err(syn::Error::new(k.span(), "events is already set"));
- }
- } else if lookahead.peek(kw::expect_selector) {
- let k = input.parse::<kw::expect_selector>()?;
- input.parse::<Token![=]>()?;
- let value = input.parse::<LitInt>()?;
- if expect_selector
- .replace(value.base10_parse::<u32>()?)
- .is_some()
- {
- return Err(syn::Error::new(k.span(), "expect_selector is already set"));
- }
- } else if input.is_empty() {
- break;
- } else {
- return Err(lookahead.error());
- }
- if input.peek(Token![,]) {
- input.parse::<Token![,]>()?;
- } else {
- break;
- }
- }
- Ok(Self {
- name: name.ok_or_else(|| syn::Error::new(input.span(), "missing name"))?,
- is: is.unwrap_or_default(),
- inline_is: inline_is.unwrap_or_default(),
- events: events.unwrap_or_default(),
- expect_selector,
- })
- }
-}
-
-struct MethodInfo {
- rename_selector: Option<String>,
- hide: bool,
-}
-impl Parse for MethodInfo {
- fn parse(input: ParseStream) -> syn::Result<Self> {
- let mut rename_selector = None;
- let mut hide = false;
- while !input.is_empty() {
- let lookahead = input.lookahead1();
- if lookahead.peek(kw::rename_selector) {
- let k = input.parse::<kw::rename_selector>()?;
- input.parse::<Token![=]>()?;
- if rename_selector
- .replace(input.parse::<LitStr>()?.value())
- .is_some()
- {
- return Err(syn::Error::new(k.span(), "rename_selector is already set"));
- }
- } else if lookahead.peek(kw::hide) {
- input.parse::<kw::hide>()?;
- hide = true;
- } else {
- return Err(lookahead.error());
- }
-
- if input.peek(Token![,]) {
- input.parse::<Token![,]>()?;
- } else if !input.is_empty() {
- return Err(syn::Error::new(input.span(), "expected end"));
- }
- }
- Ok(Self {
- rename_selector,
- hide,
- })
- }
-}
-
-trait AbiTypeHelper {
- fn plain(&self) -> syn::Result<&Ident>;
- fn is_value(&self) -> bool;
- fn is_caller(&self) -> bool;
- fn is_special(&self) -> bool;
-}
-
-impl AbiTypeHelper for Type {
- fn plain(&self) -> syn::Result<&Ident> {
- let path = parse_path(self)?;
- let segment = parse_path_segment(path)?;
- if !segment.arguments.is_empty() {
- return Err(syn::Error::new(self.span(), "Not plain type"));
- }
- Ok(&segment.ident)
- }
-
- fn is_value(&self) -> bool {
- if let Ok(ident) = self.plain() {
- return ident == "Value";
- }
- false
- }
-
- fn is_caller(&self) -> bool {
- if let Ok(ident) = self.plain() {
- return ident == "Caller";
- }
- false
- }
-
- fn is_special(&self) -> bool {
- self.is_caller() || self.is_value()
- }
-}
-
-#[derive(Debug)]
-struct MethodArg {
- name: Ident,
- camel_name: String,
- ty: Type,
-}
-impl MethodArg {
- fn try_from(value: &PatType) -> syn::Result<Self> {
- let name = parse_ident_from_pat(&value.pat)?.clone();
- Ok(Self {
- camel_name: cases::camelcase::to_camel_case(&name.to_string()),
- name,
- ty: value.ty.as_ref().clone(),
- })
- }
- fn is_value(&self) -> bool {
- self.ty.is_value()
- }
- fn is_caller(&self) -> bool {
- self.ty.is_caller()
- }
- fn is_special(&self) -> bool {
- self.ty.is_special()
- }
-
- fn expand_call_def(&self) -> proc_macro2::TokenStream {
- assert!(!self.is_special());
- let name = &self.name;
- let ty = &self.ty;
-
- quote! {
- #name: #ty
- }
- }
-
- fn expand_parse(&self) -> proc_macro2::TokenStream {
- assert!(!self.is_special());
- let name = &self.name;
- let ty = &self.ty;
- quote! {
- #name: {
- let value = <#ty as ::evm_coder::abi::AbiRead>::abi_read(reader)?;
- if !is_dynamic {reader.bytes_read(<#ty as ::evm_coder::abi::AbiType>::size())};
- value
- }
- }
- }
-
- fn expand_call_arg(&self) -> proc_macro2::TokenStream {
- if self.is_value() {
- quote! {
- c.value.clone()
- }
- } else if self.is_caller() {
- quote! {
- c.caller.clone()
- }
- } else {
- let name = &self.name;
- quote! {
- #name
- }
- }
- }
-
- fn expand_solidity_argument(&self) -> proc_macro2::TokenStream {
- let camel_name = &self.camel_name.to_string();
- let ty = &self.ty;
- quote! {
- <NamedArgument<#ty>>::new(#camel_name)
- }
- }
-}
-
-#[derive(PartialEq)]
-enum Mutability {
- Mutable,
- View,
- Pure,
-}
-
-/// Group all keywords for this macro. Usage example:
-/// #[solidity_interface(name = "B", inline_is(A))]
-mod kw {
- syn::custom_keyword!(weight);
-
- syn::custom_keyword!(via);
- syn::custom_keyword!(returns);
- syn::custom_keyword!(name);
- syn::custom_keyword!(is);
- syn::custom_keyword!(inline_is);
- syn::custom_keyword!(events);
- syn::custom_keyword!(expect_selector);
-
- syn::custom_keyword!(rename_selector);
- syn::custom_keyword!(hide);
-}
-
-/// Rust methods are parsed into this structure when Solidity code is generated
-struct Method {
- name: Ident,
- camel_name: String,
- pascal_name: Ident,
- screaming_name: Ident,
- hide: bool,
- args: Vec<MethodArg>,
- has_normal_args: bool,
- has_value_args: bool,
- mutability: Mutability,
- result: Type,
- weight: Option<Expr>,
- docs: Vec<String>,
-}
-impl Method {
- fn try_from(value: &ImplItemMethod) -> syn::Result<Self> {
- let mut info = MethodInfo {
- rename_selector: None,
- hide: false,
- };
- let mut docs = Vec::new();
- let mut weight = None;
- for attr in &value.attrs {
- let ident = parse_ident_from_path(&attr.path, false)?;
- if ident == "solidity" {
- info = attr.parse_args::<MethodInfo>()?;
- } else if ident == "doc" {
- let args = attr.parse_meta().unwrap();
- let value = match args {
- Meta::NameValue(MetaNameValue {
- lit: Lit::Str(str), ..
- }) => str.value(),
- _ => unreachable!(),
- };
- docs.push(value);
- } else if ident == "weight" {
- weight = Some(attr.parse_args::<Expr>()?);
- }
- }
- let ident = &value.sig.ident;
- let ident_str = ident.to_string();
- if !cases::snakecase::is_snake_case(&ident_str) {
- return Err(syn::Error::new(ident.span(), "method name should be snake_cased\nif alternative solidity name needs to be set - use #[solidity] attribute"));
- }
-
- let mut mutability = Mutability::Pure;
-
- if let Some(FnArg::Receiver(receiver)) = value
- .sig
- .inputs
- .iter()
- .find(|arg| matches!(arg, FnArg::Receiver(_)))
- {
- if receiver.reference.is_none() {
- return Err(syn::Error::new(
- receiver.span(),
- "receiver should be by ref",
- ));
- }
- if receiver.mutability.is_some() {
- mutability = Mutability::Mutable;
- } else {
- mutability = Mutability::View;
- }
- }
- let mut args = Vec::new();
- for typ in value
- .sig
- .inputs
- .iter()
- .filter(|arg| matches!(arg, FnArg::Typed(_)))
- {
- let typ = match typ {
- FnArg::Typed(typ) => typ,
- _ => unreachable!(),
- };
- args.push(MethodArg::try_from(typ)?);
- }
-
- if mutability != Mutability::Mutable && args.iter().any(|arg| arg.is_value()) {
- return Err(syn::Error::new(
- args.iter().find(|arg| arg.is_value()).unwrap().ty.span(),
- "payable function should be mutable",
- ));
- }
-
- let result = match &value.sig.output {
- ReturnType::Type(_, ty) => ty,
- _ => return Err(syn::Error::new(value.sig.output.span(), "interface method should return Result<value>\nif there is no value to return - specify void (which is alias to unit)")),
- };
- let result = parse_result_ok(result)?;
-
- let camel_name = info
- .rename_selector
- .unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));
- let has_normal_args = args.iter().filter(|arg| !arg.is_special()).count() != 0;
- let has_value_args = args.iter().any(|a| a.is_value());
-
- Ok(Self {
- name: ident.clone(),
- camel_name,
- pascal_name: snake_ident_to_pascal(ident),
- screaming_name: snake_ident_to_screaming(ident),
- hide: info.hide,
- args,
- has_normal_args,
- has_value_args,
- mutability,
- result: result.clone(),
- weight,
- docs,
- })
- }
- fn expand_call_def(&self) -> proc_macro2::TokenStream {
- let defs = self
- .args
- .iter()
- .filter(|a| !a.is_special())
- .map(|a| a.expand_call_def());
- let pascal_name = &self.pascal_name;
- let docs = &self.docs;
-
- if self.has_normal_args {
- quote! {
- #(#[doc = #docs])*
- #[allow(missing_docs)]
- #pascal_name {
- #(
- #defs,
- )*
- }
- }
- } else {
- quote! {
- #(#[doc = #docs])*
- #[allow(missing_docs)]
- #pascal_name
- }
- }
- }
-
- fn expand_const(&self) -> proc_macro2::TokenStream {
- let screaming_name = &self.screaming_name;
- let screaming_name_signature = format_ident!("{}_SIGNATURE", &self.screaming_name);
- let custom_signature = self.expand_custom_signature();
- quote! {
- const #screaming_name_signature: ::evm_coder::custom_signature::SignatureUnit = #custom_signature;
- const #screaming_name: ::evm_coder::types::Bytes4 = {
- let mut sum = ::evm_coder::sha3_const::Keccak256::new();
- let mut pos = 0;
- while pos < Self::#screaming_name_signature.len {
- sum = sum.update(&[Self::#screaming_name_signature.data[pos]; 1]);
- pos += 1;
- }
- let a = sum.finalize();
- [a[0], a[1], a[2], a[3]]
- };
- }
- }
-
- fn expand_interface_id(&self) -> proc_macro2::TokenStream {
- let screaming_name = &self.screaming_name;
- quote! {
- interface_id ^= u32::from_be_bytes(Self::#screaming_name);
- }
- }
-
- fn expand_parse(&self) -> proc_macro2::TokenStream {
- let pascal_name = &self.pascal_name;
- let screaming_name = &self.screaming_name;
- if self.has_normal_args {
- let args_iter = self.args.iter().filter(|a| !a.is_special());
- let arg_type = args_iter.clone().map(|a| &a.ty);
- let parsers = args_iter.map(|a| a.expand_parse());
- quote! {
- Self::#screaming_name => {
- let is_dynamic = false #(|| <#arg_type as ::evm_coder::abi::AbiType>::is_dynamic())*;
- return Ok(Some(Self::#pascal_name {
- #(
- #parsers,
- )*
- }))
- }
- }
- } else {
- quote! { Self::#screaming_name => return Ok(Some(Self::#pascal_name)) }
- }
- }
-
- fn expand_variant_call(&self, call_name: &proc_macro2::Ident) -> proc_macro2::TokenStream {
- let pascal_name = &self.pascal_name;
- let name = &self.name;
-
- let matcher = if self.has_normal_args {
- let names = self
- .args
- .iter()
- .filter(|a| !a.is_special())
- .map(|a| &a.name);
-
- quote! {{
- #(
- #names,
- )*
- }}
- } else {
- quote! {}
- };
-
- let receiver = match self.mutability {
- Mutability::Mutable | Mutability::View => quote! {self.},
- Mutability::Pure => quote! {Self::},
- };
- let args = self.args.iter().map(|a| a.expand_call_arg());
-
- quote! {
- #call_name::#pascal_name #matcher => {
- #[allow(deprecated)]
- let result = #receiver #name(
- #(
- #args,
- )*
- )?;
- (&result).to_result()
- }
- }
- }
-
- fn expand_variant_weight(&self) -> proc_macro2::TokenStream {
- let pascal_name = &self.pascal_name;
- if let Some(weight) = &self.weight {
- let matcher = if self.has_normal_args {
- let names = self
- .args
- .iter()
- .filter(|a| !a.is_special())
- .map(|a| &a.name);
-
- quote! {{
- #(
- #names,
- )*
- }}
- } else {
- quote! {}
- };
- quote! {
- Self::#pascal_name #matcher => (#weight).into()
- }
- } else {
- let matcher = if self.has_normal_args {
- quote! {{..}}
- } else {
- quote! {}
- };
- quote! {
- Self::#pascal_name #matcher => ().into()
- }
- }
- }
-
- fn expand_custom_signature(&self) -> proc_macro2::TokenStream {
- let mut args = TokenStream::new();
-
- let mut has_params = false;
- for arg in self.args.iter().filter(|a| !a.is_special()) {
- has_params = true;
- let ty = &arg.ty;
- args.extend(quote! {nameof(<#ty>::SIGNATURE)});
- args.extend(quote! {fixed(",")})
- }
-
- // Remove trailing comma
- if has_params {
- args.extend(quote! {shift_left(1)})
- }
-
- let func_name = self.camel_name.clone();
- quote! { ::evm_coder::make_signature!(new fixed(#func_name) fixed("(") #args fixed(")")) }
- }
-
- fn expand_solidity_function(&self) -> proc_macro2::TokenStream {
- let camel_name = &self.camel_name;
- let mutability = match self.mutability {
- Mutability::Mutable => quote! {SolidityMutability::Mutable},
- Mutability::View => quote! { SolidityMutability::View },
- Mutability::Pure => quote! {SolidityMutability::Pure},
- };
- let result = &self.result;
-
- let args = self
- .args
- .iter()
- .filter(|a| !a.is_special())
- .map(MethodArg::expand_solidity_argument);
- let docs = &self.docs;
- let screaming_name = &self.screaming_name;
- let hide = self.hide;
- let custom_signature = self.expand_custom_signature();
- let is_payable = self.has_value_args;
-
- quote! {
- SolidityFunction {
- docs: &[#(#docs),*],
- hide: #hide,
- selector: u32::from_be_bytes(Self::#screaming_name),
- custom_signature: #custom_signature,
- name: #camel_name,
- mutability: #mutability,
- is_payable: #is_payable,
- args: (
- #(
- #args,
- )*
- ),
- result: <UnnamedArgument<#result>>::default(),
- }
- }
- }
-}
-
-fn generics_list(gen: &Generics) -> proc_macro2::TokenStream {
- if gen.params.is_empty() {
- return quote! {};
- }
- let params = gen.params.iter().map(|p| match p {
- syn::GenericParam::Type(id) => {
- let v = &id.ident;
- quote! {#v}
- }
- syn::GenericParam::Lifetime(lt) => {
- let v = <.lifetime;
- quote! {#v}
- }
- syn::GenericParam::Const(c) => {
- let i = &c.ident;
- quote! {#i}
- }
- });
- quote! { #(#params),* }
-}
-fn generics_reference(gen: &Generics) -> proc_macro2::TokenStream {
- if gen.params.is_empty() {
- return quote! {};
- }
- let list = generics_list(gen);
- quote! { <#list> }
-}
-fn generics_stub(gen: &Generics) -> proc_macro2::TokenStream {
- if gen.params.is_empty() {
- return quote! {};
- }
- let params = (0..gen.params.len()).map(|_| quote! {()});
- quote! {<#(#params,)*>}
-}
-fn generics_data(gen: &Generics) -> proc_macro2::TokenStream {
- let list = generics_list(gen);
- if gen.params.len() == 1 {
- quote! {#list}
- } else {
- quote! { (#list) }
- }
-}
-
-pub struct SolidityInterface {
- generics: Generics,
- name: Box<syn::Type>,
- info: InterfaceInfo,
- methods: Vec<Method>,
- docs: Vec<String>,
-}
-impl SolidityInterface {
- pub fn try_from(info: InterfaceInfo, value: &ItemImpl) -> syn::Result<Self> {
- let mut methods = Vec::new();
-
- for item in &value.items {
- if let ImplItem::Method(method) = item {
- methods.push(Method::try_from(method)?)
- }
- }
- let mut docs = vec![];
- for attr in &value.attrs {
- let ident = parse_ident_from_path(&attr.path, false)?;
- if ident == "doc" {
- let args = attr.parse_meta().unwrap();
- let value = match args {
- Meta::NameValue(MetaNameValue {
- lit: Lit::Str(str), ..
- }) => str.value(),
- _ => unreachable!(),
- };
- docs.push(value);
- }
- }
- Ok(Self {
- generics: value.generics.clone(),
- name: value.self_ty.clone(),
- info,
- methods,
- docs,
- })
- }
- pub fn expand(self) -> proc_macro2::TokenStream {
- let name = self.name;
-
- let solidity_name = self.info.name.to_string();
- let call_name = pascal_ident_to_call(&self.info.name);
- let generics = self.generics;
- let gen_ref = generics_reference(&generics);
- let gen_data = generics_data(&generics);
- let gen_stub = generics_stub(&generics);
- let gen_where = &generics.where_clause;
-
- let call_sub = self
- .info
- .inline_is
- .0
- .iter()
- .chain(self.info.is.0.iter())
- .map(|c| Is::expand_call_def(c, &gen_ref));
- let call_parse = self
- .info
- .inline_is
- .0
- .iter()
- .chain(self.info.is.0.iter())
- .map(|is| Is::expand_parse(is, &gen_ref));
- let call_variants = self
- .info
- .inline_is
- .0
- .iter()
- .chain(self.info.is.0.iter())
- .map(|c| Is::expand_variant_call(c, &call_name, &gen_ref));
- let weight_variants = self
- .info
- .inline_is
- .0
- .iter()
- .chain(self.info.is.0.iter())
- .map(Is::expand_variant_weight);
-
- let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);
- let supports_interface = self
- .info
- .is
- .0
- .iter()
- .map(|is| Is::expand_supports_interface(is, &gen_ref));
-
- let calls = self.methods.iter().map(Method::expand_call_def);
- let consts = self.methods.iter().map(Method::expand_const);
- let interface_id = self.methods.iter().map(Method::expand_interface_id);
- let parsers = self.methods.iter().map(Method::expand_parse);
- let call_variants_this = self
- .methods
- .iter()
- .map(|m| Method::expand_variant_call(m, &call_name));
- let weight_variants_this = self.methods.iter().map(Method::expand_variant_weight);
- let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);
-
- // TODO: Inline inline_is
- let solidity_is = self
- .info
- .is
- .0
- .iter()
- .chain(self.info.inline_is.0.iter())
- .map(|is| is.name.to_string());
- let solidity_events_is = self.info.events.0.iter().map(|is| is.name.to_string());
- let solidity_generators = self
- .info
- .is
- .0
- .iter()
- .chain(self.info.inline_is.0.iter())
- .map(|is| Is::expand_generator(is, &gen_ref));
- let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);
- let solidity_events_idents = self.info.events.0.iter().map(|is| is.name.clone());
- let docs = &self.docs;
-
- let expect_selector = self.info.expect_selector.map(|s| {
- quote! {
- const _: () = assert!(#s == u32::from_be_bytes(<#call_name #gen_stub>::interface_id()), "selector mismatch, review contained function selectors");
- }
- });
-
- quote! {
- #(
- const _: ::core::marker::PhantomData<#solidity_events_idents> = ::core::marker::PhantomData;
- )*
- #[derive(Debug)]
- #(#[doc = #docs])*
- pub enum #call_name #gen_ref {
- /// Inherited method
- ERC165Call(::evm_coder::ERC165Call, ::core::marker::PhantomData<#gen_data>),
- #(
- #calls,
- )*
- #(
- #call_sub,
- )*
- }
-
- #expect_selector
-
- impl #gen_ref #call_name #gen_ref {
- #(
- #consts
- )*
- /// Return this call ERC165 selector
- pub const fn interface_id() -> ::evm_coder::types::Bytes4 {
- let mut interface_id = 0;
- #(#interface_id)*
- #(#inline_interface_id)*
- u32::to_be_bytes(interface_id)
- }
- /// Generate solidity definitions for methods described in this interface
- #[cfg(feature = "stubgen")]
- pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {
- use evm_coder::solidity::*;
- use core::fmt::Write;
- let interface = SolidityInterface {
- docs: &[#(#docs),*],
- name: #solidity_name,
- selector: Self::interface_id(),
- is: &["Dummy", "ERC165", #(
- #solidity_is,
- )* #(
- #solidity_events_is,
- )* ],
- functions: (#(
- #solidity_functions,
- )*),
- };
-
- let mut out = ::evm_coder::types::String::new();
- if #solidity_name.starts_with("Inline") {
- out.push_str("/// @dev inlined interface\n");
- }
- let _ = interface.format(is_impl, &mut out, tc);
- tc.collect(out);
- #(
- #solidity_event_generators
- )*
- #(
- #solidity_generators
- )*
- if is_impl {
- tc.collect("/// @dev common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ncontract ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n".into());
- } else {
- tc.collect("/// @dev common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n".into());
- }
- }
- }
- impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {
- fn parse(method_id: ::evm_coder::types::Bytes4, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {
- use ::evm_coder::abi::AbiRead;
- match method_id {
- ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(
- ::evm_coder::ERC165Call::parse(method_id, reader)?
- .map(|c| Self::ERC165Call(c, ::core::marker::PhantomData))
- ),
- #(
- #parsers,
- )*
- _ => {},
- }
- #(
- #call_parse
- )else*
- return Ok(None);
- }
- }
- impl #generics #call_name #gen_ref
- #gen_where
- {
- /// Is this contract implements specified ERC165 selector
- pub fn supports_interface(this: &#name, interface_id: ::evm_coder::types::Bytes4) -> bool {
- interface_id != u32::to_be_bytes(0xffffff) && (
- interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||
- interface_id == Self::interface_id()
- #(
- || #supports_interface
- )*
- )
- }
- }
- impl #generics ::evm_coder::Weighted for #call_name #gen_ref
- #gen_where
- {
- #[allow(unused_variables)]
- fn weight(&self) -> ::evm_coder::execution::DispatchInfo {
- match self {
- #(
- #weight_variants,
- )*
- // TODO: It should be very cheap, but not free
- Self::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {..}, _) => ::frame_support::weights::Weight::from_ref_time(100).into(),
- #(
- #weight_variants_this,
- )*
- }
- }
- }
- impl #generics ::evm_coder::Callable<#call_name #gen_ref> for #name
- #gen_where
- {
- #[allow(unreachable_code)] // In case of no inner calls
- fn call(&mut self, c: Msg<#call_name #gen_ref>) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> {
- use ::evm_coder::abi::AbiWrite;
- match c.call {
- #(
- #call_variants,
- )*
- #call_name::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}, _) => {
- let mut writer = ::evm_coder::abi::AbiWriter::default();
- writer.bool(&<#call_name #gen_ref>::supports_interface(self, interface_id));
- return Ok(writer.into());
- }
- _ => {},
- }
- let mut writer = ::evm_coder::abi::AbiWriter::default();
- match c.call {
- #(
- #call_variants_this,
- )*
- _ => Err(::evm_coder::execution::Error::from("method is not available").into()),
- }
- }
- }
- }
- }
-}
crates/evm-coder/procedural/src/to_log.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/to_log.rs
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use inflector::cases;
-use syn::{Data, DeriveInput, Field, Fields, Ident, Variant, spanned::Spanned};
-use quote::quote;
-
-use crate::{parse_ident_from_path, parse_ident_from_type, snake_ident_to_screaming};
-
-struct EventField {
- name: Ident,
- camel_name: String,
- ty: Ident,
- indexed: bool,
-}
-
-impl EventField {
- fn try_from(field: &Field) -> syn::Result<Self> {
- let name = field.ident.as_ref().unwrap();
- let ty = parse_ident_from_type(&field.ty, false)?;
- let mut indexed = false;
- for attr in &field.attrs {
- if let Ok(ident) = parse_ident_from_path(&attr.path, false) {
- if ident == "indexed" {
- indexed = true;
- }
- }
- }
- Ok(Self {
- name: name.to_owned(),
- camel_name: cases::camelcase::to_camel_case(&name.to_string()),
- ty: ty.to_owned(),
- indexed,
- })
- }
- fn expand_solidity_argument(&self) -> proc_macro2::TokenStream {
- let camel_name = &self.camel_name;
- let ty = &self.ty;
- let indexed = self.indexed;
- quote! {
- <SolidityEventArgument<#ty>>::new(#indexed, #camel_name)
- }
- }
-}
-
-struct Event {
- name: Ident,
- name_screaming: Ident,
- fields: Vec<EventField>,
- selector: proc_macro2::TokenStream,
-}
-
-impl Event {
- fn try_from(variant: &Variant) -> syn::Result<Self> {
- let name = &variant.ident;
- let name_lit = proc_macro2::Literal::string(name.to_string().as_str());
- let name_screaming = snake_ident_to_screaming(name);
-
- let named = match &variant.fields {
- Fields::Named(named) => named,
- _ => {
- return Err(syn::Error::new(
- variant.fields.span(),
- "expected named fields",
- ))
- }
- };
- let mut fields = Vec::new();
- for field in &named.named {
- fields.push(EventField::try_from(field)?);
- }
- if fields.iter().filter(|f| f.indexed).count() > 3 {
- return Err(syn::Error::new(
- variant.fields.span(),
- "events can have at most 4 indexed fields (1 indexed field is reserved for event signature)"
- ));
- }
-
- let args = fields.iter().map(|f| {
- let ty = &f.ty;
- quote! {nameof(<#ty as ::evm_coder::abi::AbiType>::SIGNATURE) fixed(",")}
- });
- // Remove trailing comma
- let shift = (!fields.is_empty()).then(|| quote! {shift_left(1)});
-
- let signature = quote! { ::evm_coder::make_signature!(new fixed(#name_lit) fixed("(") #(#args)* #shift fixed(")")) };
- let selector = quote! {
- {
- let signature = #signature;
- let mut sum = ::evm_coder::sha3_const::Keccak256::new();
- let mut pos = 0;
- while pos < signature.len {
- sum = sum.update(&[signature.data[pos]; 1]);
- pos += 1;
- }
- let a = sum.finalize();
- let mut selector_bytes = [0; 32];
- let mut i = 0;
- while i != 32 {
- selector_bytes[i] = a[i];
- i += 1;
- }
- selector_bytes
- }
- };
-
- Ok(Self {
- name: name.to_owned(),
- name_screaming,
- fields,
- selector,
- })
- }
-
- fn expand_serializers(&self) -> proc_macro2::TokenStream {
- let name = &self.name;
- let name_screaming = &self.name_screaming;
- let fields = self.fields.iter().map(|f| &f.name);
-
- let indexed = self.fields.iter().filter(|f| f.indexed).map(|f| &f.name);
- let plain = self.fields.iter().filter(|f| !f.indexed).map(|f| &f.name);
-
- quote! {
- Self::#name {#(
- #fields,
- )*} => {
- topics.push(::evm_coder::types::Topic::from(Self::#name_screaming));
- #(
- topics.push(#indexed.to_topic());
- )*
- #(
- #plain.abi_write(&mut writer);
- )*
- }
- }
- }
-
- fn expand_consts(&self) -> proc_macro2::TokenStream {
- let name_screaming = &self.name_screaming;
- let selector = &self.selector;
-
- quote! {
- const #name_screaming: [u8; 32] = #selector;
- }
- }
-
- fn expand_solidity_function(&self) -> proc_macro2::TokenStream {
- let name = self.name.to_string();
- let args = self.fields.iter().map(EventField::expand_solidity_argument);
- quote! {
- SolidityEvent {
- name: #name,
- args: (
- #(
- #args,
- )*
- ),
- }
- }
- }
-}
-
-pub struct Events {
- name: Ident,
- events: Vec<Event>,
-}
-
-impl Events {
- pub fn try_from(data: &DeriveInput) -> syn::Result<Self> {
- let name = &data.ident;
- let en = match &data.data {
- Data::Enum(en) => en,
- _ => return Err(syn::Error::new(data.span(), "expected enum")),
- };
- let mut events = Vec::new();
- for variant in &en.variants {
- events.push(Event::try_from(variant)?);
- }
- Ok(Self {
- name: name.to_owned(),
- events,
- })
- }
- pub fn expand(&self) -> proc_macro2::TokenStream {
- let name = &self.name;
-
- let consts = self.events.iter().map(Event::expand_consts);
- let serializers = self.events.iter().map(Event::expand_serializers);
- let solidity_name = self.name.to_string();
- let solidity_functions = self.events.iter().map(Event::expand_solidity_function);
-
- quote! {
- impl #name {
- #(
- #consts
- )*
-
- /// Generate solidity definitions for methods described in this interface
- #[cfg(feature = "stubgen")]
- pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {
- use evm_coder::solidity::*;
- use core::fmt::Write;
- let interface = SolidityInterface {
- docs: &[],
- selector: [0; 4],
- name: #solidity_name,
- is: &[],
- functions: (#(
- #solidity_functions,
- )*),
- };
- let mut out = ::evm_coder::types::String::new();
- out.push_str("/// @dev inlined interface\n");
- let _ = interface.format(is_impl, &mut out, tc);
- tc.collect(out);
- }
- }
-
- #[automatically_derived]
- impl ::evm_coder::events::ToLog for #name {
- fn to_log(&self, contract: Address) -> ::evm_coder::ethereum::Log {
- use ::evm_coder::events::ToTopic;
- use ::evm_coder::abi::AbiWrite;
- let mut writer = ::evm_coder::abi::AbiWriter::new();
- let mut topics = Vec::new();
- match self {
- #(
- #serializers,
- )*
- }
- ::evm_coder::ethereum::Log {
- address: contract,
- topics,
- data: writer.finish(),
- }
- }
- }
- }
- }
-}
crates/evm-coder/src/abi/impls.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/impls.rs
+++ /dev/null
@@ -1,296 +0,0 @@
-use crate::{
- custom_signature::SignatureUnit,
- execution::{Result, ResultWithPostInfo, WithPostDispatchInfo},
- make_signature, sealed,
- types::*,
-};
-use super::{traits::*, ABI_ALIGNMENT, AbiReader, AbiWriter};
-use primitive_types::{U256, H160};
-
-#[cfg(not(feature = "std"))]
-use alloc::vec::Vec;
-
-macro_rules! impl_abi_type {
- ($ty:ty, $name:ident, $dynamic:literal) => {
- impl sealed::CanBePlacedInVec for $ty {}
-
- impl AbiType for $ty {
- const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($name)));
-
- fn is_dynamic() -> bool {
- $dynamic
- }
-
- fn size() -> usize {
- ABI_ALIGNMENT
- }
- }
- };
-}
-
-macro_rules! impl_abi_readable {
- ($ty:ty, $method:ident) => {
- impl AbiRead for $ty {
- fn abi_read(reader: &mut AbiReader) -> Result<$ty> {
- reader.$method()
- }
- }
- };
-}
-
-macro_rules! impl_abi_writeable {
- ($ty:ty, $method:ident) => {
- impl AbiWrite for $ty {
- fn abi_write(&self, writer: &mut AbiWriter) {
- writer.$method(&self)
- }
- }
- };
-}
-
-macro_rules! impl_abi {
- ($ty:ty, $method:ident, $dynamic:literal) => {
- impl_abi_type!($ty, $method, $dynamic);
- impl_abi_readable!($ty, $method);
- impl_abi_writeable!($ty, $method);
- };
-}
-
-impl_abi!(bool, bool, false);
-impl_abi!(u8, uint8, false);
-impl_abi!(u32, uint32, false);
-impl_abi!(u64, uint64, false);
-impl_abi!(u128, uint128, false);
-impl_abi!(U256, uint256, false);
-impl_abi!(H160, address, false);
-impl_abi!(String, string, true);
-
-impl_abi_writeable!(&str, string);
-
-impl_abi_type!(Bytes, bytes, true);
-
-impl AbiRead for Bytes {
- fn abi_read(reader: &mut AbiReader) -> Result<Bytes> {
- Ok(Bytes(reader.bytes()?))
- }
-}
-
-impl AbiWrite for Bytes {
- fn abi_write(&self, writer: &mut AbiWriter) {
- writer.bytes(self.0.as_slice())
- }
-}
-
-impl_abi_type!(Bytes4, bytes4, false);
-impl AbiRead for Bytes4 {
- fn abi_read(reader: &mut AbiReader) -> Result<Bytes4> {
- reader.bytes4()
- }
-}
-
-impl<T: AbiWrite> AbiWrite for &T {
- fn abi_write(&self, writer: &mut AbiWriter) {
- T::abi_write(self, writer);
- }
-}
-
-impl<T: AbiType> AbiType for &T {
- const SIGNATURE: SignatureUnit = T::SIGNATURE;
-
- fn is_dynamic() -> bool {
- T::is_dynamic()
- }
-
- fn size() -> usize {
- T::size()
- }
-}
-
-impl<T: AbiType + AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<T> {
- fn abi_read(reader: &mut AbiReader) -> Result<Vec<T>> {
- let mut sub = reader.subresult(None)?;
- let size = sub.uint32()? as usize;
- sub.subresult_offset = sub.offset;
- let is_dynamic = <T as AbiType>::is_dynamic();
- let mut out = Vec::with_capacity(size);
- for _ in 0..size {
- out.push(<T as AbiRead>::abi_read(&mut sub)?);
- if !is_dynamic {
- sub.bytes_read(<T as AbiType>::size());
- };
- }
- Ok(out)
- }
-}
-
-impl<T: AbiType> AbiType for Vec<T> {
- const SIGNATURE: SignatureUnit = make_signature!(new nameof(T::SIGNATURE) fixed("[]"));
-
- fn is_dynamic() -> bool {
- true
- }
-
- fn size() -> usize {
- ABI_ALIGNMENT
- }
-}
-
-impl<T: AbiWrite + AbiType> AbiWrite for Vec<T> {
- fn abi_write(&self, writer: &mut AbiWriter) {
- let is_dynamic = T::is_dynamic();
- let mut sub = if is_dynamic {
- AbiWriter::new_dynamic(is_dynamic)
- } else {
- AbiWriter::new()
- };
-
- // Write items count
- (self.len() as u32).abi_write(&mut sub);
-
- for item in self {
- item.abi_write(&mut sub);
- }
- writer.write_subresult(sub);
- }
-}
-
-impl AbiWrite for () {
- fn abi_write(&self, _writer: &mut AbiWriter) {}
-}
-
-/// This particular AbiWrite implementation should be split to another trait,
-/// which only implements `to_result`, but due to lack of specialization feature
-/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,
-/// so here we abusing default trait methods for it
-impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {
- fn abi_write(&self, _writer: &mut AbiWriter) {
- debug_assert!(false, "shouldn't be called, see comment")
- }
- fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
- match self {
- Ok(v) => Ok(WithPostDispatchInfo {
- post_info: v.post_info.clone(),
- data: {
- let mut out = AbiWriter::new();
- v.data.abi_write(&mut out);
- out
- },
- }),
- Err(e) => Err(e.clone()),
- }
- }
-}
-
-macro_rules! impl_tuples {
- ($($ident:ident)+) => {
- impl<$($ident: AbiType,)+> AbiType for ($($ident,)+)
- where
- $(
- $ident: AbiType,
- )+
- {
- const SIGNATURE: SignatureUnit = make_signature!(
- new fixed("(")
- $(nameof(<$ident>::SIGNATURE) fixed(","))+
- shift_left(1)
- fixed(")")
- );
-
- fn is_dynamic() -> bool {
- false
- $(
- || <$ident>::is_dynamic()
- )*
- }
-
- fn size() -> usize {
- 0 $(+ <$ident>::size())+
- }
- }
-
- impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}
-
- impl<$($ident),+> AbiRead for ($($ident,)+)
- where
- Self: AbiType,
- $($ident: AbiRead + AbiType,)+
- {
- fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {
- let is_dynamic = <Self>::is_dynamic();
- let size = if !is_dynamic { Some(<Self>::size()) } else { None };
- let mut subresult = reader.subresult(size)?;
- Ok((
- $({
- let value = <$ident>::abi_read(&mut subresult)?;
- if !is_dynamic {subresult.bytes_read(<$ident as AbiType>::size())};
- value
- },)+
- ))
- }
- }
-
- #[allow(non_snake_case)]
- impl<$($ident),+> AbiWrite for ($($ident,)+)
- where
- $($ident: AbiWrite + AbiType,)+
- {
- fn abi_write(&self, writer: &mut AbiWriter) {
- let ($($ident,)+) = self;
- if <Self as AbiType>::is_dynamic() {
- let mut sub = AbiWriter::new();
- $($ident.abi_write(&mut sub);)+
- writer.write_subresult(sub);
- } else {
- $($ident.abi_write(writer);)+
- }
- }
- }
- };
-}
-
-impl_tuples! {A}
-impl_tuples! {A B}
-impl_tuples! {A B C}
-impl_tuples! {A B C D}
-impl_tuples! {A B C D E}
-impl_tuples! {A B C D E F}
-impl_tuples! {A B C D E F G}
-impl_tuples! {A B C D E F G H}
-impl_tuples! {A B C D E F G H I}
-impl_tuples! {A B C D E F G H I J}
-
-//----- impls for Option -----
-impl<T: AbiType> AbiType for Option<T> {
- const SIGNATURE: SignatureUnit = <(bool, T)>::SIGNATURE;
-
- fn is_dynamic() -> bool {
- <(bool, T)>::is_dynamic()
- }
-
- fn size() -> usize {
- <(bool, T)>::size()
- }
-}
-
-impl<T: AbiWrite + AbiType + Default> AbiWrite for Option<T> {
- fn abi_write(&self, writer: &mut AbiWriter) {
- match self {
- Some(value) => (true, value).abi_write(writer),
- None => (false, T::default()).abi_write(writer),
- }
- }
-}
-
-impl<T> AbiRead for Option<T>
-where
- Self: AbiType,
- T: AbiRead + AbiType,
-{
- fn abi_read(reader: &mut AbiReader) -> Result<Self>
- where
- Self: Sized,
- {
- let (status, value) = <(bool, T)>::abi_read(reader)?;
- Ok(if status { Some(value) } else { None })
- }
-}
crates/evm-coder/src/abi/mod.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/mod.rs
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-//! Implementation of EVM RLP reader/writer
-
-#![allow(dead_code)]
-
-mod traits;
-pub use traits::*;
-mod impls;
-
-#[cfg(test)]
-mod test;
-
-#[cfg(not(feature = "std"))]
-use alloc::vec::Vec;
-use evm_core::ExitError;
-use primitive_types::{H160, U256};
-
-use crate::{
- execution::{Result, Error},
- types::*,
-};
-
-const ABI_ALIGNMENT: usize = 32;
-
-/// View into RLP data, which provides method to read typed items from it
-#[derive(Clone)]
-pub struct AbiReader<'i> {
- buf: &'i [u8],
- subresult_offset: usize,
- offset: usize,
-}
-impl<'i> AbiReader<'i> {
- /// Start reading RLP buffer, assuming there is no padding bytes
- pub fn new(buf: &'i [u8]) -> Self {
- Self {
- buf,
- subresult_offset: 0,
- offset: 0,
- }
- }
- /// Start reading RLP buffer, parsing first 4 bytes as selector
- pub fn new_call(buf: &'i [u8]) -> Result<(Bytes4, Self)> {
- if buf.len() < 4 {
- return Err(Error::Error(ExitError::OutOfOffset));
- }
- let mut method_id = [0; 4];
- method_id.copy_from_slice(&buf[0..4]);
-
- Ok((
- method_id,
- Self {
- buf,
- subresult_offset: 4,
- offset: 4,
- },
- ))
- }
-
- fn read_pad<const S: usize>(
- buf: &[u8],
- offset: usize,
- pad_start: usize,
- pad_end: usize,
- block_start: usize,
- block_end: usize,
- ) -> Result<[u8; S]> {
- if buf.len() - offset < ABI_ALIGNMENT {
- return Err(Error::Error(ExitError::OutOfOffset));
- }
- let mut block = [0; S];
- let is_pad_zeroed = buf[pad_start..pad_end].iter().all(|&v| v == 0);
- if !is_pad_zeroed {
- return Err(Error::Error(ExitError::InvalidRange));
- }
- block.copy_from_slice(&buf[block_start..block_end]);
- Ok(block)
- }
-
- fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {
- let offset = self.offset;
- self.offset += ABI_ALIGNMENT;
- Self::read_pad(
- self.buf,
- offset,
- offset,
- offset + ABI_ALIGNMENT - S,
- offset + ABI_ALIGNMENT - S,
- offset + ABI_ALIGNMENT,
- )
- }
-
- fn read_padright<const S: usize>(&mut self) -> Result<[u8; S]> {
- let offset = self.offset;
- self.offset += ABI_ALIGNMENT;
- Self::read_pad(
- self.buf,
- offset,
- offset + S,
- offset + ABI_ALIGNMENT,
- offset,
- offset + S,
- )
- }
-
- /// Read [`H160`] at current position, then advance
- pub fn address(&mut self) -> Result<H160> {
- Ok(H160(self.read_padleft()?))
- }
-
- /// Read [`bool`] at current position, then advance
- pub fn bool(&mut self) -> Result<bool> {
- let data: [u8; 1] = self.read_padleft()?;
- match data[0] {
- 0 => Ok(false),
- 1 => Ok(true),
- _ => Err(Error::Error(ExitError::InvalidRange)),
- }
- }
-
- /// Read [`[u8; 4]`] at current position, then advance
- pub fn bytes4(&mut self) -> Result<[u8; 4]> {
- self.read_padright()
- }
-
- /// Read [`Vec<u8>`] at current position, then advance
- pub fn bytes(&mut self) -> Result<Vec<u8>> {
- let mut subresult = self.subresult(None)?;
- let length = subresult.uint32()? as usize;
- if subresult.buf.len() < subresult.offset + length {
- return Err(Error::Error(ExitError::OutOfOffset));
- }
- Ok(subresult.buf[subresult.offset..subresult.offset + length].into())
- }
-
- /// Read [`string`] at current position, then advance
- pub fn string(&mut self) -> Result<String> {
- String::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))
- }
-
- /// Read [`u8`] at current position, then advance
- pub fn uint8(&mut self) -> Result<u8> {
- Ok(self.read_padleft::<1>()?[0])
- }
-
- /// Read [`u32`] at current position, then advance
- pub fn uint32(&mut self) -> Result<u32> {
- Ok(u32::from_be_bytes(self.read_padleft()?))
- }
-
- /// Read [`u128`] at current position, then advance
- pub fn uint128(&mut self) -> Result<u128> {
- Ok(u128::from_be_bytes(self.read_padleft()?))
- }
-
- /// Read [`U256`] at current position, then advance
- pub fn uint256(&mut self) -> Result<U256> {
- let buf: [u8; 32] = self.read_padleft()?;
- Ok(U256::from_big_endian(&buf))
- }
-
- /// Read [`u64`] at current position, then advance
- pub fn uint64(&mut self) -> Result<u64> {
- Ok(u64::from_be_bytes(self.read_padleft()?))
- }
-
- /// Read [`usize`] at current position, then advance
- #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]
- pub fn read_usize(&mut self) -> Result<usize> {
- Ok(usize::from_be_bytes(self.read_padleft()?))
- }
-
- /// Slice recursive buffer, advance one word for buffer offset
- /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].
- pub fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {
- let subresult_offset = self.subresult_offset;
- let offset = if let Some(size) = size {
- self.offset += size;
- 0
- } else {
- self.uint32()? as usize
- };
-
- if offset + self.subresult_offset > self.buf.len() {
- return Err(Error::Error(ExitError::InvalidRange));
- }
-
- let new_offset = offset + subresult_offset;
- Ok(AbiReader {
- buf: self.buf,
- subresult_offset: new_offset,
- offset: new_offset,
- })
- }
-
- /// Notify about readed data portion.
- pub fn bytes_read(&mut self, size: usize) {
- self.subresult_offset += size;
- }
-
- /// Is this parser reached end of buffer?
- pub fn is_finished(&self) -> bool {
- self.buf.len() == self.offset
- }
-}
-
-/// Writer for RLP encoded data
-#[derive(Default)]
-pub struct AbiWriter {
- static_part: Vec<u8>,
- dynamic_part: Vec<(usize, AbiWriter)>,
- had_call: bool,
- is_dynamic: bool,
-}
-impl AbiWriter {
- /// Initialize internal buffers for output data, assuming no padding required
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Initialize internal buffers with data size
- pub fn new_dynamic(is_dynamic: bool) -> Self {
- Self {
- is_dynamic,
- ..Default::default()
- }
- }
- /// Initialize internal buffers, inserting method selector at beginning
- pub fn new_call(method_id: u32) -> Self {
- let mut val = Self::new();
- val.static_part.extend(&method_id.to_be_bytes());
- val.had_call = true;
- val
- }
-
- fn write_padleft(&mut self, block: &[u8]) {
- assert!(block.len() <= ABI_ALIGNMENT);
- self.static_part
- .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);
- self.static_part.extend(block);
- }
-
- fn write_padright(&mut self, block: &[u8]) {
- assert!(block.len() <= ABI_ALIGNMENT);
- self.static_part.extend(block);
- self.static_part
- .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);
- }
-
- /// Write [`H160`] to end of buffer
- pub fn address(&mut self, address: &H160) {
- self.write_padleft(&address.0)
- }
-
- /// Write [`bool`] to end of buffer
- pub fn bool(&mut self, value: &bool) {
- self.write_padleft(&[if *value { 1 } else { 0 }])
- }
-
- /// Write [`u8`] to end of buffer
- pub fn uint8(&mut self, value: &u8) {
- self.write_padleft(&[*value])
- }
-
- /// Write [`u32`] to end of buffer
- pub fn uint32(&mut self, value: &u32) {
- self.write_padleft(&u32::to_be_bytes(*value))
- }
-
- /// Write [`u64`] to end of buffer
- pub fn uint64(&mut self, value: &u64) {
- self.write_padleft(&u64::to_be_bytes(*value))
- }
-
- /// Write [`u128`] to end of buffer
- pub fn uint128(&mut self, value: &u128) {
- self.write_padleft(&u128::to_be_bytes(*value))
- }
-
- /// Write [`U256`] to end of buffer
- pub fn uint256(&mut self, value: &U256) {
- let mut out = [0; 32];
- value.to_big_endian(&mut out);
- self.write_padleft(&out)
- }
-
- /// Write [`usize`] to end of buffer
- #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]
- pub fn write_usize(&mut self, value: &usize) {
- self.write_padleft(&usize::to_be_bytes(*value))
- }
-
- /// Append recursive data, writing pending offset at end of buffer
- pub fn write_subresult(&mut self, result: Self) {
- self.dynamic_part.push((self.static_part.len(), result));
- // Empty block, to be filled later
- self.write_padleft(&[]);
- }
-
- fn memory(&mut self, value: &[u8]) {
- let mut sub = Self::new();
- sub.uint32(&(value.len() as u32));
- for chunk in value.chunks(ABI_ALIGNMENT) {
- sub.write_padright(chunk);
- }
- self.write_subresult(sub);
- }
-
- /// Append recursive [`str`] at end of buffer
- pub fn string(&mut self, value: &str) {
- self.memory(value.as_bytes())
- }
-
- /// Append recursive [`[u8]`] at end of buffer
- pub fn bytes(&mut self, value: &[u8]) {
- self.memory(value)
- }
-
- /// Finish writer, concatenating all internal buffers
- pub fn finish(mut self) -> Vec<u8> {
- for (static_offset, part) in self.dynamic_part {
- let part_offset = self.static_part.len()
- - if self.had_call { 4 } else { 0 }
- - if self.is_dynamic { ABI_ALIGNMENT } else { 0 };
-
- let encoded_dynamic_offset = usize::to_be_bytes(part_offset);
- let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();
- let stop = static_offset + ABI_ALIGNMENT;
- self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);
- self.static_part.extend(part.finish())
- }
- self.static_part
- }
-}
crates/evm-coder/src/abi/test.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/test.rs
+++ /dev/null
@@ -1,605 +0,0 @@
-use crate::{
- abi::{AbiRead, AbiWrite},
- types::*,
-};
-
-use super::{AbiReader, AbiWriter};
-use hex_literal::hex;
-use primitive_types::{H160, U256};
-
-fn test_impl<T>(function_identifier: u32, decoded_data: T, encoded_data: &[u8])
-where
- T: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
-{
- let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
- assert_eq!(call, u32::to_be_bytes(function_identifier));
- let data = <T>::abi_read(&mut decoder).unwrap();
- assert_eq!(data, decoded_data);
-
- let mut writer = AbiWriter::new_call(function_identifier);
- decoded_data.abi_write(&mut writer);
- let ed = writer.finish();
- similar_asserts::assert_eq!(encoded_data, ed.as_slice());
-}
-
-macro_rules! test_impl_uint {
- ($type:ident) => {
- test_impl::<$type>(
- 0xdeadbeef,
- 255 as $type,
- &hex!(
- "
- deadbeef
- 00000000000000000000000000000000000000000000000000000000000000ff
- "
- ),
- );
- };
-}
-
-#[test]
-fn encode_decode_uint8() {
- test_impl_uint!(u8);
-}
-
-#[test]
-fn encode_decode_uint32() {
- test_impl_uint!(u32);
-}
-
-#[test]
-fn encode_decode_uint128() {
- test_impl_uint!(u128);
-}
-
-#[test]
-fn encode_decode_uint256() {
- test_impl::<U256>(
- 0xdeadbeef,
- U256([255, 0, 0, 0]),
- &hex!(
- "
- deadbeef
- 00000000000000000000000000000000000000000000000000000000000000ff
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_string() {
- test_impl::<String>(
- 0xdeadbeef,
- "some string".to_string(),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 000000000000000000000000000000000000000000000000000000000000000b
- 736f6d6520737472696e67000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple_string() {
- test_impl::<(String,)>(
- 0xdeadbeef,
- ("some string".to_string(),),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000020
- 000000000000000000000000000000000000000000000000000000000000000b
- 736f6d6520737472696e67000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_vec_tuple_address_uint256() {
- test_impl::<Vec<(Address, U256)>>(
- 0x1ACF2D55,
- vec![
- (
- H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),
- U256([10, 0, 0, 0]),
- ),
- (
- H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),
- U256([20, 0, 0, 0]),
- ),
- (
- H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),
- U256([30, 0, 0, 0]),
- ),
- ],
- &hex!(
- "
- 1ACF2D55
- 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]
- 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]
-
- 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address
- 000000000000000000000000000000000000000000000000000000000000000A // uint256
-
- 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address
- 0000000000000000000000000000000000000000000000000000000000000014 // uint256
-
- 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address
- 000000000000000000000000000000000000000000000000000000000000001E // uint256
- "
- )
- );
-}
-
-#[test]
-fn encode_decode_vec_tuple_uint256_string() {
- test_impl::<Vec<(U256, String)>>(
- 0xdeadbeef,
- vec![
- (1.into(), "Test URI 0".to_string()),
- (11.into(), "Test URI 1".to_string()),
- (12.into(), "Test URI 2".to_string()),
- ],
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]
- 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]
-
- 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem
- 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem
- 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem
-
- 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203000000000000000000000000000000000000000000000 // string
-
- 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203100000000000000000000000000000000000000000000 // string
-
- 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203200000000000000000000000000000000000000000000 // string
- "
- )
- );
-}
-
-#[test]
-fn dynamic_after_static() {
- let mut encoder = AbiWriter::new();
- encoder.bool(&true);
- encoder.string("test");
- let encoded = encoder.finish();
-
- let mut encoder = AbiWriter::new();
- encoder.bool(&true);
- // Offset to subresult
- encoder.uint32(&(32 * 2));
- // Len of "test"
- encoder.uint32(&4);
- encoder.write_padright(&[b't', b'e', b's', b't']);
- let alternative_encoded = encoder.finish();
-
- assert_eq!(encoded, alternative_encoded);
-
- let mut decoder = AbiReader::new(&encoded);
- assert!(decoder.bool().unwrap());
- assert_eq!(decoder.string().unwrap(), "test");
-}
-
-#[test]
-fn mint_sample() {
- let (call, mut decoder) = AbiReader::new_call(&hex!(
- "
- 50bb4e7f
- 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374
- 0000000000000000000000000000000000000000000000000000000000000001
- 0000000000000000000000000000000000000000000000000000000000000060
- 0000000000000000000000000000000000000000000000000000000000000008
- 5465737420555249000000000000000000000000000000000000000000000000
- "
- ))
- .unwrap();
- assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));
- assert_eq!(
- format!("{:?}", decoder.address().unwrap()),
- "0xad2c0954693c2b5404b7e50967d3481bea432374"
- );
- assert_eq!(decoder.uint32().unwrap(), 1);
- assert_eq!(decoder.string().unwrap(), "Test URI");
-}
-
-#[test]
-fn parse_vec_with_dynamic_type() {
- let decoded_data = (
- 0x36543006,
- vec![
- (1.into(), "Test URI 0".to_string()),
- (11.into(), "Test URI 1".to_string()),
- (12.into(), "Test URI 2".to_string()),
- ],
- );
-
- let encoded_data = &hex!(
- "
- 36543006
- 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]
- 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]
-
- 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem
- 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem
- 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem
-
- 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203000000000000000000000000000000000000000000000 // string
-
- 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203100000000000000000000000000000000000000000000 // string
-
- 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203200000000000000000000000000000000000000000000 // string
- "
- );
-
- let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
- assert_eq!(call, u32::to_be_bytes(decoded_data.0));
- let address = decoder.address().unwrap();
- let data = <Vec<(U256, String)>>::abi_read(&mut decoder).unwrap();
- assert_eq!(data, decoded_data.1);
-
- let mut writer = AbiWriter::new_call(decoded_data.0);
- address.abi_write(&mut writer);
- decoded_data.1.abi_write(&mut writer);
- let ed = writer.finish();
- similar_asserts::assert_eq!(encoded_data, ed.as_slice());
-}
-
-#[test]
-fn encode_decode_vec_tuple_string_bytes() {
- test_impl::<Vec<(String, Bytes)>>(
- 0xdeadbeef,
- vec![
- (
- "Test URI 0".to_string(),
- Bytes(vec![
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- ]),
- ),
- (
- "Test URI 1".to_string(),
- Bytes(vec![
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- ]),
- ),
- ("Test URI 2".to_string(), Bytes(vec![0x33, 0x33])),
- ],
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000003
-
- 0000000000000000000000000000000000000000000000000000000000000060
- 0000000000000000000000000000000000000000000000000000000000000140
- 0000000000000000000000000000000000000000000000000000000000000220
-
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000080
- 000000000000000000000000000000000000000000000000000000000000000a
- 5465737420555249203000000000000000000000000000000000000000000000
- 0000000000000000000000000000000000000000000000000000000000000030
- 1111111111111111111111111111111111111111111111111111111111111111
- 1111111111111111111111111111111100000000000000000000000000000000
-
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000080
- 000000000000000000000000000000000000000000000000000000000000000a
- 5465737420555249203100000000000000000000000000000000000000000000
- 000000000000000000000000000000000000000000000000000000000000002f
- 2222222222222222222222222222222222222222222222222222222222222222
- 2222222222222222222222222222220000000000000000000000000000000000
-
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000080
- 000000000000000000000000000000000000000000000000000000000000000a
- 5465737420555249203200000000000000000000000000000000000000000000
- 0000000000000000000000000000000000000000000000000000000000000002
- 3333000000000000000000000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-// #[ignore = "reason"]
-fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() {
- let int = 0xff;
- let by = Bytes(vec![0x11, 0x22, 0x33]);
- let string = "some string".to_string();
-
- test_impl::<((u8,), (String, Bytes), (u8, Bytes))>(
- 0xdeadbeef,
- ((int,), (string.clone(), by.clone()), (int, by)),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 00000000000000000000000000000000000000000000000000000000000000ff
- 0000000000000000000000000000000000000000000000000000000000000060
- 0000000000000000000000000000000000000000000000000000000000000120
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000080
- 000000000000000000000000000000000000000000000000000000000000000b
- 736f6d6520737472696e67000000000000000000000000000000000000000000
- 0000000000000000000000000000000000000000000000000000000000000003
- 1122330000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000ff
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000003
- 1122330000000000000000000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8_uint8_tuple1_uint8_uint8() {
- test_impl::<((u8,), (u8, u8), (u8, u8))>(
- 0xdeadbeef,
- ((43,), (44, 45), (46, 47)),
- &hex!(
- "
- deadbeef
- 000000000000000000000000000000000000000000000000000000000000002b
- 000000000000000000000000000000000000000000000000000000000000002c
- 000000000000000000000000000000000000000000000000000000000000002d
- 000000000000000000000000000000000000000000000000000000000000002e
- 000000000000000000000000000000000000000000000000000000000000002f
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8() {
- test_impl::<((u8,), (u8,))>(
- 0xdeadbeef,
- ((43,), (44,)),
- &hex!(
- "
- deadbeef
- 000000000000000000000000000000000000000000000000000000000000002b
- 000000000000000000000000000000000000000000000000000000000000002c
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple0_tuple1_uint8_uint8() {
- test_impl::<((u8, u8),)>(
- 0xdeadbeef,
- ((43, 44),),
- &hex!(
- "
- deadbeef
- 000000000000000000000000000000000000000000000000000000000000002b
- 000000000000000000000000000000000000000000000000000000000000002c
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple_uint8_uint8() {
- test_impl::<(u8, u8)>(
- 0xdeadbeef,
- (43, 44),
- &hex!(
- "
- deadbeef
- 000000000000000000000000000000000000000000000000000000000000002b
- 000000000000000000000000000000000000000000000000000000000000002c
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple0_tuple1_uint8_uint8_tuple1_uint8_uint8_and_uint8() {
- test_impl::<((u8, u8), (u8, u8), u8)>(
- 0xdeadbeef,
- ((10, 11), (12, 13), 14),
- &hex!(
- "
- deadbeef
- 000000000000000000000000000000000000000000000000000000000000000a
- 000000000000000000000000000000000000000000000000000000000000000b
- 000000000000000000000000000000000000000000000000000000000000000c
- 000000000000000000000000000000000000000000000000000000000000000d
- 000000000000000000000000000000000000000000000000000000000000000e
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple0_tuple1_string() {
- test_impl::<((String,),)>(
- 0xdeadbeef,
- (("some string".to_string(),),),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000020
- 000000000000000000000000000000000000000000000000000000000000000b
- 736f6d6520737472696e67000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple0_tuple1_uint8_string() {
- test_impl::<((u8, String),)>(
- 0xdeadbeef,
- ((0xff, "some string".to_string()),),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000020
- 00000000000000000000000000000000000000000000000000000000000000ff
- 0000000000000000000000000000000000000000000000000000000000000040
- 000000000000000000000000000000000000000000000000000000000000000b
- 736f6d6520737472696e67000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple0_tuple1_string_bytes() {
- test_impl::<((String, Bytes),)>(
- 0xdeadbeef,
- (("some string".to_string(), Bytes(vec![1, 2, 3])),),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000080
- 000000000000000000000000000000000000000000000000000000000000000b
- 736f6d6520737472696e67000000000000000000000000000000000000000000
- 0000000000000000000000000000000000000000000000000000000000000003
- 0102030000000000000000000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_tuple0_tuple1_uint8_tuple1_string() {
- test_impl::<((u8,), (String,))>(
- 0xdeadbeef,
- ((0xff,), ("some string".to_string(),)),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 00000000000000000000000000000000000000000000000000000000000000ff
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000020
- 000000000000000000000000000000000000000000000000000000000000000b
- 736f6d6520737472696e67000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn parse_multiple_params() {
- let encoded_data = hex!(
- "
- deadbeef
- 000000000000000000000000000000000000000000000000000000000000000a
- 000000000000000000000000000000000000000000000000000000000000000b
- "
- );
- let (_, mut decoder) = AbiReader::new_call(&encoded_data).unwrap();
- let p1 = <u8>::abi_read(&mut decoder).unwrap();
- let p2 = <u8>::abi_read(&mut decoder).unwrap();
- assert_eq!(p1, 0x0a);
- assert_eq!(p2, 0x0b);
-}
-
-#[test]
-fn encode_decode_option_uint8_some() {
- test_impl::<Option<u8>>(
- 0xdeadbeef,
- Some(44),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000001
- 000000000000000000000000000000000000000000000000000000000000002c
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_option_uint8_none() {
- test_impl::<Option<u8>>(
- 0xdeadbeef,
- None,
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000000
- 0000000000000000000000000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_option_string_some() {
- test_impl::<Option<String>>(
- 0xdeadbeef,
- Some("some string".to_string()),
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000001
- 0000000000000000000000000000000000000000000000000000000000000040
- 000000000000000000000000000000000000000000000000000000000000000b
- 736f6d6520737472696e67000000000000000000000000000000000000000000
- "
- ),
- );
-}
-
-#[test]
-fn encode_decode_option_string_none() {
- test_impl::<Option<String>>(
- 0xdeadbeef,
- None,
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000000
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000000
- "
- ),
- );
-}
crates/evm-coder/src/abi/traits.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/traits.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use super::{AbiReader, AbiWriter};
-use crate::{
- custom_signature::*,
- execution::{Result, ResultWithPostInfo},
-};
-use core::str::from_utf8;
-
-/// Helper for type.
-pub trait AbiType {
- /// Signature for Etherium ABI.
- const SIGNATURE: SignatureUnit;
-
- /// Signature as str.
- fn as_str() -> &'static str {
- from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
- }
-
- /// Is type dynamic sized.
- fn is_dynamic() -> bool;
-
- /// Size for type aligned to [`ABI_ALIGNMENT`].
- fn size() -> usize;
-}
-
-/// [`AbiReader`] implements reading of many types.
-pub trait AbiRead {
- /// Read item from current position, advanding decoder
- fn abi_read(reader: &mut AbiReader) -> Result<Self>
- where
- Self: Sized;
-}
-
-/// For questions about inability to provide custom implementations,
-/// see [`AbiRead`]
-pub trait AbiWrite {
- /// Write value to end of specified encoder
- fn abi_write(&self, writer: &mut AbiWriter);
- /// Specialization for [`crate::solidity_interface`] implementation,
- /// see comment in `impl AbiWrite for ResultWithPostInfo`
- fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
- let mut writer = AbiWriter::new();
- self.abi_write(&mut writer);
- Ok(writer.into())
- }
-}
crates/evm-coder/src/custom_signature.rsdiffbeforeafterboth--- a/crates/evm-coder/src/custom_signature.rs
+++ /dev/null
@@ -1,326 +0,0 @@
-//! # A module for custom signature support.
-//!
-//! ## Overview
-//! This module allows you to create arbitrary signatures for types and functions in compile time.
-//!
-//! ### Type signatures
-//! To create the desired type signature, you need to create your own trait with the `SIGNATURE` constant.
-//! Then in the implementation, for the required type, use the macro [`make_signature`]
-//! #### Example
-//! ```
-//! use std::str::from_utf8;
-//! use evm_coder::{custom_signature::SignatureUnit, make_signature};
-//!
-//! // Create trait for our signature
-//! trait SoliditySignature {
-//! const SIGNATURE: SignatureUnit;
-//!
-//! fn name() -> &'static str {
-//! from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
-//! }
-//! }
-//!
-//! // Make signatures for some types
-//! impl SoliditySignature for u8 {
-//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8"));
-//! }
-//! impl SoliditySignature for u32 {
-//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint32"));
-//! }
-//! impl<T: SoliditySignature> SoliditySignature for Vec<T> {
-//! const SIGNATURE: SignatureUnit = make_signature!(new nameof(T::SIGNATURE) fixed("[]"));
-//! }
-//! impl<A: SoliditySignature, B: SoliditySignature> SoliditySignature for (A, B) {
-//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("(") nameof(A::SIGNATURE) fixed(",") nameof(B::SIGNATURE) fixed(")"));
-//! }
-//! impl<A: SoliditySignature> SoliditySignature for (A,) {
-//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("(") nameof(A::SIGNATURE) fixed(",") shift_left(1) fixed(")"));
-//! }
-//!
-//! assert_eq!(u8::name(), "uint8");
-//! assert_eq!(<Vec<u8>>::name(), "uint8[]");
-//! assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)");
-//! ```
-//!
-//! ### Function signatures
-//! To create a function signature, the macro [`make_signature`] is also used, which accepts
-//! settings for the function format [`SignaturePreferences`] and function parameters [`SignatureUnit`]
-//! #### Example
-//! ```
-//! use core::str::from_utf8;
-//! use evm_coder::{custom_signature::SignatureUnit, make_signature};
-//! // Trait for our signature
-//! trait SoliditySignature {
-//! const SIGNATURE: SignatureUnit;
-//!
-//! fn name() -> &'static str {
-//! from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
-//! }
-//! }
-//!
-//! // Make signatures for some types
-//! impl SoliditySignature for u8 {
-//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8"));
-//! }
-//! impl<T: SoliditySignature> SoliditySignature for Vec<T> {
-//! const SIGNATURE: SignatureUnit = make_signature!(new nameof(T::SIGNATURE) fixed("[]"));
-//! }
-//! ```
-
-/// The maximum length of the signature.
-pub const SIGNATURE_SIZE_LIMIT: usize = 256;
-
-/// Storage for the signature or its elements.
-#[derive(Debug)]
-pub struct SignatureUnit {
- /// Signature data.
- pub data: [u8; SIGNATURE_SIZE_LIMIT],
- /// The actual size of the data.
- pub len: usize,
-}
-
-impl SignatureUnit {
- /// Create a signature from `&str'.
- pub const fn new(name: &'static str) -> SignatureUnit {
- let mut signature = [0_u8; SIGNATURE_SIZE_LIMIT];
- let name = name.as_bytes();
- let name_len = name.len();
- let mut dst_offset = 0;
- crate::make_signature!(@copy(name, signature, name_len, dst_offset));
- SignatureUnit {
- data: signature,
- len: name_len,
- }
- }
- /// String conversion
- pub fn as_str(&self) -> Option<&str> {
- core::str::from_utf8(&self.data[0..self.len]).ok()
- }
-}
-
-/// ### Macro to create signatures of types and functions.
-///
-/// Format for creating a type of signature:
-/// ```ignore
-/// make_signature!(new fixed("uint8")); // Simple type
-/// make_signature!(new fixed("(") nameof(u8) fixed(",") nameof(u8) fixed(")")); // Composite type
-/// ```
-#[macro_export]
-macro_rules! make_signature {
- (new $($tt:tt)*) => {
- ($crate::custom_signature::SignatureUnit {
- data: {
- let mut out = [0u8; $crate::custom_signature::SIGNATURE_SIZE_LIMIT];
- let mut dst_offset = 0;
- $crate::make_signature!(@data(out, dst_offset); $($tt)*);
- out
- },
- len: {0 + $crate::make_signature!(@size; $($tt)*)},
- })
- };
-
- (@size;) => {
- 0
- };
- (@size; fixed($expr:expr) $($tt:tt)*) => {
- $expr.len() + $crate::make_signature!(@size; $($tt)*)
- };
- (@size; nameof($expr:expr) $($tt:tt)*) => {
- $expr.len + $crate::make_signature!(@size; $($tt)*)
- };
- (@size; numof($expr:expr) $($tt:tt)*) => {
- {
- let mut out = 0;
- let mut v = $expr;
- if v == 0 {
- out = 1;
- } else {
- while v > 0 {
- out += 1;
- v /= 10;
- }
- }
- out
- } + $crate::make_signature!(@size; $($tt)*)
- };
- (@size; shift_left($expr:expr) $($tt:tt)*) => {
- $crate::make_signature!(@size; $($tt)*) - $expr
- };
-
- (@data($dst:ident, $dst_offset:ident);) => {};
- (@data($dst:ident, $dst_offset:ident); fixed($expr:expr) $($tt:tt)*) => {
- {
- let data = $expr.as_bytes();
- let data_len = data.len();
- $crate::make_signature!(@copy(data, $dst, data_len, $dst_offset));
- }
- $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)
- };
- (@data($dst:ident, $dst_offset:ident); nameof($expr:expr) $($tt:tt)*) => {
- {
- $crate::make_signature!(@copy(&$expr.data, $dst, $expr.len, $dst_offset));
- }
- $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)
- };
- (@data($dst:ident, $dst_offset:ident); numof($expr:expr) $($tt:tt)*) => {
- {
- let mut v = $expr;
- let mut need_to_swap = 0;
- if v == 0 {
- $dst[$dst_offset] = b'0';
- $dst_offset += 1;
- } else {
- while v > 0 {
- let n = (v % 10) as u8;
- $dst[$dst_offset] = b'0' + n;
- v /= 10;
- need_to_swap += 1;
- $dst_offset += 1;
- }
- }
- let mut i = 0;
- #[allow(clippy::manual_swap)]
- while i < need_to_swap / 2 {
- let a = $dst_offset - i - 1;
- let b = $dst_offset - need_to_swap + i;
- let v = $dst[a];
- $dst[a] = $dst[b];
- $dst[b] = v;
- i += 1;
- }
- }
- $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)
- };
- (@data($dst:ident, $dst_offset:ident); shift_left($expr:expr) $($tt:tt)*) => {
- $dst_offset -= $expr;
- $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)
- };
-
- (@copy($src:expr, $dst:expr, $src_len:expr, $dst_offset:ident)) => {
- {
- let mut src_offset = 0;
- let src_len: usize = $src_len;
- while src_offset < src_len {
- $dst[$dst_offset] = $src[src_offset];
- $dst_offset += 1;
- src_offset += 1;
- }
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use core::str::from_utf8;
-
- use super::{SIGNATURE_SIZE_LIMIT, SignatureUnit};
-
- trait Name {
- const NAME: SignatureUnit;
-
- fn name() -> &'static str {
- from_utf8(&Self::NAME.data[..Self::NAME.len]).expect("bad utf-8")
- }
- }
-
- impl Name for u8 {
- const NAME: SignatureUnit = make_signature!(new fixed("uint8"));
- }
- impl Name for u32 {
- const NAME: SignatureUnit = make_signature!(new fixed("uint32"));
- }
- impl<T: Name> Name for Vec<T> {
- const NAME: SignatureUnit = make_signature!(new nameof(T::NAME) fixed("[]"));
- }
- impl<A: Name, B: Name> Name for (A, B) {
- const NAME: SignatureUnit =
- make_signature!(new fixed("(") nameof(A::NAME) fixed(",") nameof(B::NAME) fixed(")"));
- }
- impl<A: Name> Name for (A,) {
- const NAME: SignatureUnit =
- make_signature!(new fixed("(") nameof(A::NAME) fixed(",") shift_left(1) fixed(")"));
- }
- impl<A: Name, const SIZE: usize> Name for [A; SIZE] {
- const NAME: SignatureUnit =
- make_signature!(new nameof(A::NAME) fixed("[") numof(SIZE) fixed("]"));
- }
-
- struct MaxSize();
- impl Name for MaxSize {
- const NAME: SignatureUnit = SignatureUnit {
- data: [b'!'; SIGNATURE_SIZE_LIMIT],
- len: SIGNATURE_SIZE_LIMIT,
- };
- }
-
- #[test]
- fn simple() {
- assert_eq!(u8::name(), "uint8");
- assert_eq!(u32::name(), "uint32");
- }
-
- #[test]
- fn vector_of_simple() {
- assert_eq!(<Vec<u8>>::name(), "uint8[]");
- assert_eq!(<Vec<u32>>::name(), "uint32[]");
- }
-
- #[test]
- fn vector_of_vector() {
- assert_eq!(<Vec<Vec<u8>>>::name(), "uint8[][]");
- }
-
- #[test]
- fn tuple_of_simple() {
- assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)");
- }
-
- #[test]
- fn tuple_of_tuple() {
- assert_eq!(
- <((u32, u8), (u8, u32))>::name(),
- "((uint32,uint8),(uint8,uint32))"
- );
- }
-
- #[test]
- fn vector_of_tuple() {
- assert_eq!(<Vec<(u32, u8)>>::name(), "(uint32,uint8)[]");
- }
-
- #[test]
- fn tuple_of_vector() {
- assert_eq!(<(Vec<u32>, u8)>::name(), "(uint32[],uint8)");
- }
-
- #[test]
- fn complex() {
- assert_eq!(
- <(Vec<u32>, (u32, Vec<u8>))>::name(),
- "(uint32[],(uint32,uint8[]))"
- );
- }
-
- #[test]
- fn max_size() {
- assert_eq!(<MaxSize>::name(), "!".repeat(SIGNATURE_SIZE_LIMIT));
- }
-
- #[test]
- fn shift() {
- assert_eq!(<(u32,)>::name(), "(uint32)");
- }
-
- #[test]
- fn num() {
- assert_eq!(<[u8; 0]>::name(), "uint8[0]");
- assert_eq!(<[u8; 1234]>::name(), "uint8[1234]");
- assert_eq!(<[u8; 12345]>::name(), "uint8[12345]");
- }
-
- #[test]
- fn over_max_size() {
- let t = trybuild::TestCases::new();
- t.compile_fail("tests/build_failed/custom_signature_over_max_size.rs");
- }
-}
crates/evm-coder/src/events.rsdiffbeforeafterboth--- a/crates/evm-coder/src/events.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use ethereum::Log;
-use primitive_types::{H160, H256, U256};
-
-use crate::types::*;
-
-/// Implementation of this trait should not be written manually,
-/// instead use [`crate::ToLog`] proc macros.
-///
-/// See also [`evm_coder_procedural::ToLog`], [solidity docs on events](https://docs.soliditylang.org/en/develop/contracts.html#events)
-pub trait ToLog {
- /// Convert event to [`ethereum::Log`].
- /// Because event by itself doesn't contains current contract
- /// address, it should be specified manually.
- fn to_log(&self, contract: H160) -> Log;
-}
-
-/// Only items implementing `ToTopic` may be used as `#[indexed]` field
-/// in [`crate::ToLog`] macro usage.
-///
-/// See also (solidity docs on events)[<https://docs.soliditylang.org/en/develop/contracts.html#events>]
-pub trait ToTopic {
- /// Convert value to topic to be used in [`ethereum::Log`]
- fn to_topic(&self) -> H256;
-}
-
-impl ToTopic for H256 {
- fn to_topic(&self) -> H256 {
- *self
- }
-}
-
-impl ToTopic for U256 {
- fn to_topic(&self) -> H256 {
- let mut out = [0u8; 32];
- self.to_big_endian(&mut out);
- H256(out)
- }
-}
-
-impl ToTopic for Address {
- fn to_topic(&self) -> H256 {
- let mut out = [0u8; 32];
- out[12..32].copy_from_slice(&self.0);
- H256(out)
- }
-}
-
-impl ToTopic for u32 {
- fn to_topic(&self) -> H256 {
- let mut out = [0u8; 32];
- out[28..32].copy_from_slice(&self.to_be_bytes());
- H256(out)
- }
-}
crates/evm-coder/src/execution.rsdiffbeforeafterboth--- a/crates/evm-coder/src/execution.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-//! Contract execution related types
-
-#[cfg(not(feature = "std"))]
-use alloc::string::{String, ToString};
-use evm_core::{ExitError, ExitFatal};
-#[cfg(feature = "std")]
-use std::string::{String, ToString};
-
-use crate::Weight;
-
-/// Execution error, should be convertible between EVM and Substrate.
-#[derive(Debug, Clone)]
-pub enum Error {
- /// Non-fatal contract error occured
- Revert(String),
- /// EVM fatal error
- Fatal(ExitFatal),
- /// EVM normal error
- Error(ExitError),
-}
-
-impl<E> From<E> for Error
-where
- E: ToString,
-{
- fn from(e: E) -> Self {
- Self::Revert(e.to_string())
- }
-}
-
-/// To be used in [`crate::solidity_interface`] implementation.
-pub type Result<T> = core::result::Result<T, Error>;
-
-/// Static information collected from [`crate::weight`].
-pub struct DispatchInfo {
- /// Statically predicted call weight
- pub weight: Weight,
-}
-
-impl From<Weight> for DispatchInfo {
- fn from(weight: Weight) -> Self {
- Self { weight }
- }
-}
-impl From<u64> for DispatchInfo {
- fn from(weight: u64) -> Self {
- Self {
- weight: Weight::from_ref_time(weight),
- }
- }
-}
-impl From<()> for DispatchInfo {
- fn from(_: ()) -> Self {
- Self {
- weight: Weight::zero(),
- }
- }
-}
-
-/// Weight information that is only available post dispatch.
-/// Note: This can only be used to reduce the weight or fee, not increase it.
-#[derive(Default, Clone)]
-pub struct PostDispatchInfo {
- /// Actual weight consumed by call
- actual_weight: Option<Weight>,
-}
-
-impl PostDispatchInfo {
- /// Calculate amount to be returned back to user
- pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
- info.weight - self.calc_actual_weight(info)
- }
-
- /// Calculate actual consumed weight, saturating to weight reported
- /// pre-dispatch
- pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
- if let Some(actual_weight) = self.actual_weight {
- actual_weight.min(info.weight)
- } else {
- info.weight
- }
- }
-}
-
-/// Wrapper for PostDispatchInfo and any user-provided data
-#[derive(Clone)]
-pub struct WithPostDispatchInfo<T> {
- /// User provided data
- pub data: T,
- /// Info known after dispatch
- pub post_info: PostDispatchInfo,
-}
-
-impl<T> From<T> for WithPostDispatchInfo<T> {
- fn from(data: T) -> Self {
- Self {
- data,
- post_info: Default::default(),
- }
- }
-}
-
-/// Return type of items in [`crate::solidity_interface`] definition
-pub type ResultWithPostInfo<T> =
- core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;
crates/evm-coder/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/src/lib.rs
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#![doc = include_str!("../README.md")]
-#![deny(missing_docs)]
-#![macro_use]
-#![cfg_attr(not(feature = "std"), no_std)]
-#[cfg(not(feature = "std"))]
-extern crate alloc;
-
-use abi::{AbiRead, AbiReader, AbiWriter};
-pub use evm_coder_procedural::{event_topic, fn_selector};
-pub mod abi;
-pub use events::{ToLog, ToTopic};
-use execution::DispatchInfo;
-pub mod execution;
-#[macro_use]
-pub mod custom_signature;
-
-/// Derives call enum implementing [`crate::Callable`], [`crate::Weighted`]
-/// and [`crate::Call`] from impl block.
-///
-/// ## Macro syntax
-///
-/// `#[solidity_interface(name, is, inline_is, events)]`
-/// - *name* - used in generated code, and for Call enum name
-/// - *is* - used to provide inheritance in Solidity
-/// - *inline_is* - same as `is`, but ERC165::SupportsInterface will work differently: For `is` SupportsInterface(A) will return true
-/// if A is one of the interfaces the contract is inherited from (e.g. B is created as `is(A)`). If B is created as `inline_is(A)`
-/// SupportsInterface(A) will internally create a new interface that combines all methods of A and B, so SupportsInterface(A) will return
-/// false.
-///
-/// `#[weight(value)]`
-/// Can be added to every method of impl block, used for deriving [`crate::Weighted`], which
-/// is used by substrate bridge.
-/// - *value*: expression, which evaluates to weight required to call this method.
-/// This expression can use call arguments to calculate non-constant execution time.
-/// This expression should evaluate faster than actual execution does, and may provide worse case
-/// than one is called.
-///
-/// `#[solidity_interface(rename_selector)]`
-/// - *rename_selector* - by default, selector name will be generated by transforming method name
-/// from snake_case to camelCase. Use this option, if other naming convention is required.
-/// I.e: method `token_uri` will be automatically renamed to `tokenUri` in selector, but name
-/// required by ERC721 standard is `tokenURI`, thus we need to specify `rename_selector = "tokenURI"`
-/// explicitly.
-///
-/// Both contract and contract methods may have doccomments, which will end up in a generated
-/// solidity interface file, thus you should use [solidity syntax](https://docs.soliditylang.org/en/latest/natspec-format.html) for writing documentation in this macro
-///
-/// ## Example
-///
-/// ```ignore
-/// struct SuperContract;
-/// struct InlineContract;
-/// struct Contract;
-///
-/// #[derive(ToLog)]
-/// enum ContractEvents {
-/// Event(#[indexed] uint32),
-/// }
-///
-/// /// @dev This contract provides function to multiply two numbers
-/// #[solidity_interface(name = MyContract, is(SuperContract), inline_is(InlineContract))]
-/// impl Contract {
-/// /// Multiply two numbers
-/// /// @param a First number
-/// /// @param b Second number
-/// /// @return uint32 Product of two passed numbers
-/// /// @dev This function returns error in case of overflow
-/// #[weight(200 + a + b)]
-/// #[solidity_interface(rename_selector = "mul")]
-/// fn mul(&mut self, a: uint32, b: uint32) -> Result<uint32> {
-/// Ok(a.checked_mul(b).ok_or("overflow")?)
-/// }
-/// }
-/// ```
-pub use evm_coder_procedural::solidity_interface;
-/// See [`solidity_interface`]
-pub use evm_coder_procedural::solidity;
-/// See [`solidity_interface`]
-pub use evm_coder_procedural::weight;
-pub use evm_coder_procedural::AbiCoder;
-pub use sha3_const;
-
-/// macro reexports
-pub use ethereum;
-
-/// Derives [`ToLog`] for enum
-///
-/// Selectors will be derived from variant names, there is currently no way to have custom naming
-/// for them
-///
-/// `#[indexed]`
-/// Marks this field as indexed, so it will appear in [`ethereum::Log`] topics instead of data
-pub use evm_coder_procedural::ToLog;
-
-// Api of those modules shouldn't be consumed directly, it is only exported for usage in proc macros
-#[doc(hidden)]
-pub mod events;
-#[doc(hidden)]
-#[cfg(feature = "stubgen")]
-pub mod solidity;
-
-/// Sealed traits.
-pub mod sealed {
- /// Not every type should be directly placed in vec.
- /// Vec encoding is not memory efficient, as every item will be padded
- /// to 32 bytes.
- /// Instead you should use specialized types (`bytes` in case of `Vec<u8>`)
- pub trait CanBePlacedInVec {}
-}
-
-/// Solidity type definitions (aliases from solidity name to rust type)
-/// To be used in [`solidity_interface`] definitions, to make sure there is no
-/// type conflict between Rust code and generated definitions
-pub mod types {
- #![allow(non_camel_case_types, missing_docs)]
-
- #[cfg(not(feature = "std"))]
- use alloc::{vec::Vec};
- use primitive_types::{U256, H160, H256};
-
- pub type Address = H160;
- pub type Bytes4 = [u8; 4];
- pub type Topic = H256;
-
- #[cfg(not(feature = "std"))]
- pub type String = ::alloc::string::String;
- #[cfg(feature = "std")]
- pub type String = ::std::string::String;
-
- #[derive(Default, Debug, PartialEq, Eq, Clone)]
- pub struct Bytes(pub Vec<u8>);
-
- //#region Special types
- /// Makes function payable
- pub type Value = U256;
- /// Makes function caller-sensitive
- pub type Caller = Address;
- //#endregion
-
- /// Ethereum typed call message, similar to solidity
- /// `msg` object.
- pub struct Msg<C> {
- pub call: C,
- /// Address of user, which called this contract.
- pub caller: H160,
- /// Payment amount to contract.
- /// Contract should reject payment, if target call is not payable,
- /// and there is no `receiver()` function defined.
- pub value: U256,
- }
-
- impl From<Vec<u8>> for Bytes {
- fn from(src: Vec<u8>) -> Self {
- Self(src)
- }
- }
-
- #[allow(clippy::from_over_into)]
- impl Into<Vec<u8>> for Bytes {
- fn into(self) -> Vec<u8> {
- self.0
- }
- }
-
- impl Bytes {
- #[must_use]
- pub fn len(&self) -> usize {
- self.0.len()
- }
-
- #[must_use]
- pub fn is_empty(&self) -> bool {
- self.len() == 0
- }
- }
-}
-
-/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro
-pub trait Call: Sized {
- /// Parse call buffer into typed call enum
- fn parse(selector: types::Bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;
-}
-
-/// Intended to be used as `#[weight]` output type
-/// Should be same between evm-coder and substrate to avoid confusion
-///
-/// Isn't same thing as gas, some mapping is required between those types
-pub type Weight = frame_support::pallet_prelude::Weight;
-
-/// In substrate, we have benchmarking, which allows
-/// us to not rely on gas metering, but instead predict amount of gas to execute call
-pub trait Weighted: Call {
- /// Predict weight of this call
- fn weight(&self) -> DispatchInfo;
-}
-
-/// Type callable with ethereum message, may be implemented by [`solidity_interface`] macro
-/// on interface implementation, or for externally-owned real EVM contract
-pub trait Callable<C: Call> {
- /// Call contract using specified call data
- fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;
-}
-
-/// Implementation of ERC165 is implicitly generated for all interfaces in [`solidity_interface`],
-/// this structure holds parsed data for ERC165Call subvariant
-///
-/// Note: no [`Callable`] implementation is provided, call implementation is inlined into every
-/// implementing contract
-///
-/// See <https://eips.ethereum.org/EIPS/eip-165>
-#[derive(Debug)]
-pub enum ERC165Call {
- /// ERC165 provides single method, which returns true, if contract
- /// implements specified interface
- SupportsInterface {
- /// Requested interface
- interface_id: types::Bytes4,
- },
-}
-
-impl ERC165Call {
- /// ERC165 selector is provided by standard
- pub const INTERFACE_ID: types::Bytes4 = u32::to_be_bytes(0x01ffc9a7);
-}
-
-impl Call for ERC165Call {
- fn parse(selector: types::Bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>> {
- if selector != Self::INTERFACE_ID {
- return Ok(None);
- }
- Ok(Some(Self::SupportsInterface {
- interface_id: types::Bytes4::abi_read(input)?,
- }))
- }
-}
-
-/// Generate "tests", which will generate solidity code on execution and print it to stdout
-/// Script at .maintain/scripts/generate_api.sh can split this output from test runtime
-///
-/// This macro receives type usage as second argument, but you can use anything as generics,
-/// because no bounds are implied
-#[macro_export]
-macro_rules! generate_stubgen {
- ($name:ident, $decl:ty, $is_impl:literal) => {
- #[cfg(feature = "stubgen")]
- #[test]
- #[ignore]
- fn $name() {
- use evm_coder::solidity::TypeCollector;
- let mut out = TypeCollector::new();
- <$decl>::generate_solidity_interface(&mut out, $is_impl);
- println!("=== SNIP START ===");
- println!("// SPDX-License-Identifier: OTHER");
- println!("// This code is automatically generated");
- println!();
- println!("pragma solidity >=0.8.0 <0.9.0;");
- println!();
- for b in out.finish() {
- println!("{}", b);
- }
- println!("=== SNIP END ===");
- }
- };
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn function_selector_generation() {
- assert_eq!(fn_selector!(transfer(address, uint256)), 0xa9059cbb);
- }
-
- #[test]
- fn event_topic_generation() {
- assert_eq!(
- hex::encode(&event_topic!(Transfer(address, address, uint256))[..]),
- "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
- );
- }
-}
crates/evm-coder/src/solidity/impls.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity/impls.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-use super::{TypeCollector, SolidityTypeName, SolidityTupleTy};
-use crate::{sealed, types::*};
-use core::fmt;
-use primitive_types::{U256, H160};
-
-macro_rules! solidity_type_name {
- ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => {
- $(
- impl SolidityTypeName for $ty {
- fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {
- write!(writer, $name)
- }
- fn is_simple() -> bool {
- $simple
- }
- fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {
- write!(writer, $default)
- }
- }
- )*
- };
-}
-
-solidity_type_name! {
- u8 => "uint8" true = "0",
- u32 => "uint32" true = "0",
- u64 => "uint64" true = "0",
- u128 => "uint128" true = "0",
- U256 => "uint256" true = "0",
- Bytes4 => "bytes4" true = "bytes4(0)",
- H160 => "address" true = "0x0000000000000000000000000000000000000000",
- String => "string" false = "\"\"",
- Bytes => "bytes" false = "hex\"\"",
- bool => "bool" true = "false",
-}
-
-impl SolidityTypeName for () {
- fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
- Ok(())
- }
- fn is_simple() -> bool {
- true
- }
- fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
- Ok(())
- }
- fn is_void() -> bool {
- true
- }
-}
-
-impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {
- fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- T::solidity_name(writer, tc)?;
- write!(writer, "[]")
- }
- fn is_simple() -> bool {
- false
- }
- fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- write!(writer, "new ")?;
- T::solidity_name(writer, tc)?;
- write!(writer, "[](0)")
- }
-}
-
-macro_rules! count {
- () => (0usize);
- ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
-}
-
-macro_rules! impl_tuples {
- ($($ident:ident)+) => {
- impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleTy for ($($ident,)+) {
- fn fields(tc: &TypeCollector) -> Vec<String> {
- let mut collected = Vec::with_capacity(Self::len());
- $({
- let mut out = String::new();
- $ident::solidity_name(&mut out, tc).expect("no fmt error");
- collected.push(out);
- })*;
- collected
- }
-
- fn len() -> usize {
- count!($($ident)*)
- }
- }
- impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) {
- fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- write!(writer, "{}", tc.collect_tuple::<Self>())
- }
- fn is_simple() -> bool {
- false
- }
- #[allow(unused_assignments)]
- fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- write!(writer, "{}(", tc.collect_tuple::<Self>())?;
- let mut first = true;
- $(
- if !first {
- write!(writer, ",")?;
- } else {
- first = false;
- }
- <$ident>::solidity_default(writer, tc)?;
- )*
- write!(writer, ")")
- }
- }
- };
-}
-
-impl_tuples! {A}
-impl_tuples! {A B}
-impl_tuples! {A B C}
-impl_tuples! {A B C D}
-impl_tuples! {A B C D E}
-impl_tuples! {A B C D E F}
-impl_tuples! {A B C D E F G}
-impl_tuples! {A B C D E F G H}
-impl_tuples! {A B C D E F G H I}
-impl_tuples! {A B C D E F G H I J}
-
-//----- impls for Option -----
-impl<T: SolidityTypeName + 'static> SolidityTypeName for Option<T> {
- fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- write!(writer, "{}", tc.collect_struct::<Self>())
- }
- fn is_simple() -> bool {
- false
- }
- fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- write!(writer, "{}(", tc.collect_struct::<Self>())?;
- bool::solidity_default(writer, tc)?;
- write!(writer, ", ");
- T::solidity_default(writer, tc)?;
- write!(writer, ")")
- }
-}
-
-impl<T: SolidityTypeName> super::SolidityStructTy for Option<T> {
- fn generate_solidity_interface(tc: &TypeCollector) -> String {
- let mut solidity_name = "Option".to_string();
- let mut generic_name = String::new();
- T::solidity_name(&mut generic_name, tc);
- solidity_name.push(
- generic_name
- .chars()
- .next()
- .expect("Generic name is empty")
- .to_ascii_uppercase(),
- );
- solidity_name.push_str(&generic_name[1..]);
-
- let interface = super::SolidityStruct {
- docs: &[" Optional value"],
- name: solidity_name.as_str(),
- fields: (
- super::SolidityStructField::<bool> {
- docs: &[" Shows the status of accessibility of value"],
- name: "status",
- ty: ::core::marker::PhantomData,
- },
- super::SolidityStructField::<T> {
- docs: &[" Actual value if `status` is true"],
- name: "value",
- ty: ::core::marker::PhantomData,
- },
- ),
- };
-
- let mut out = String::new();
- let _ = interface.format(&mut out, tc);
- tc.collect(out);
-
- solidity_name.to_string()
- }
-}
crates/evm-coder/src/solidity/mod.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity/mod.rs
+++ /dev/null
@@ -1,515 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-//! Implementation detail of [`crate::solidity_interface`] macro code-generation.
-//! You should not rely on any public item from this module, as it is only intended to be used
-//! by procedural macro, API and output format may be changed at any time.
-//!
-//! Purpose of this module is to receive solidity contract definition in module-specified
-//! format, and then output string, representing interface of this contract in solidity language
-
-mod traits;
-pub use traits::*;
-mod impls;
-
-#[cfg(not(feature = "std"))]
-use alloc::{vec::Vec, collections::BTreeMap, format};
-#[cfg(feature = "std")]
-use std::collections::BTreeMap;
-use core::{
- fmt::{self, Write},
- marker::PhantomData,
- cell::{Cell, RefCell},
- cmp::Reverse,
-};
-use impl_trait_for_tuples::impl_for_tuples;
-use crate::{types::*, custom_signature::SignatureUnit};
-
-#[derive(Default)]
-pub struct TypeCollector {
- /// Code => id
- /// id ordering is required to perform topo-sort on the resulting data
- structs: RefCell<BTreeMap<String, usize>>,
- anonymous: RefCell<BTreeMap<Vec<String>, usize>>,
- // generic: RefCell<BTreeMap<String, usize>>,
- id: Cell<usize>,
-}
-impl TypeCollector {
- pub fn new() -> Self {
- Self::default()
- }
- pub fn collect(&self, item: String) {
- let id = self.next_id();
- self.structs.borrow_mut().insert(item, id);
- }
- pub fn next_id(&self) -> usize {
- let v = self.id.get();
- self.id.set(v + 1);
- v
- }
- /// Collect typle, deduplicating it by type, and returning generated name
- pub fn collect_tuple<T: SolidityTupleTy>(&self) -> String {
- let names = T::fields(self);
- if let Some(id) = self.anonymous.borrow().get(&names).cloned() {
- return format!("Tuple{}", id);
- }
- let id = self.next_id();
- let mut str = String::new();
- writeln!(str, "/// @dev anonymous struct").unwrap();
- writeln!(str, "struct Tuple{} {{", id).unwrap();
- for (i, name) in names.iter().enumerate() {
- writeln!(str, "\t{} field_{};", name, i).unwrap();
- }
- writeln!(str, "}}").unwrap();
- self.collect(str);
- self.anonymous.borrow_mut().insert(names, id);
- format!("Tuple{}", id)
- }
- pub fn collect_struct<T: SolidityStructTy>(&self) -> String {
- T::generate_solidity_interface(self)
- }
- pub fn collect_enum<T: SolidityEnumTy>(&self) -> String {
- T::generate_solidity_interface(self)
- }
- pub fn finish(self) -> Vec<String> {
- let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();
- data.sort_by_key(|(_, id)| Reverse(*id));
- data.into_iter().map(|(code, _)| code).collect()
- }
-}
-#[derive(Default)]
-pub struct UnnamedArgument<T>(PhantomData<*const T>);
-
-impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {
- fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- if !T::is_void() {
- T::solidity_name(writer, tc)?;
- if !T::is_simple() {
- write!(writer, " memory")?;
- }
- Ok(())
- } else {
- Ok(())
- }
- }
- fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {
- Ok(())
- }
- fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- T::solidity_default(writer, tc)
- }
- fn len(&self) -> usize {
- if T::is_void() {
- 0
- } else {
- 1
- }
- }
-}
-
-pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);
-
-impl<T> NamedArgument<T> {
- pub fn new(name: &'static str) -> Self {
- Self(name, Default::default())
- }
-}
-
-impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {
- fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- if !T::is_void() {
- T::solidity_name(writer, tc)?;
- if !T::is_simple() {
- write!(writer, " memory")?;
- }
- write!(writer, " {}", self.0)
- } else {
- Ok(())
- }
- }
- fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
- writeln!(writer, "\t{prefix}\t{};", self.0)
- }
- fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- T::solidity_default(writer, tc)
- }
- fn len(&self) -> usize {
- if T::is_void() {
- 0
- } else {
- 1
- }
- }
-}
-
-pub struct SolidityEventArgument<T>(pub bool, &'static str, PhantomData<*const T>);
-
-impl<T> SolidityEventArgument<T> {
- pub fn new(indexed: bool, name: &'static str) -> Self {
- Self(indexed, name, Default::default())
- }
-}
-
-impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {
- fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- if !T::is_void() {
- T::solidity_name(writer, tc)?;
- if self.0 {
- write!(writer, " indexed")?;
- }
- write!(writer, " {}", self.1)
- } else {
- Ok(())
- }
- }
- fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
- writeln!(writer, "\t{prefix}\t{};", self.1)
- }
- fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- T::solidity_default(writer, tc)
- }
- fn len(&self) -> usize {
- if T::is_void() {
- 0
- } else {
- 1
- }
- }
-}
-
-impl SolidityArguments for () {
- fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
- Ok(())
- }
- fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {
- Ok(())
- }
- fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
- Ok(())
- }
- fn len(&self) -> usize {
- 0
- }
-}
-
-#[impl_for_tuples(1, 12)]
-impl SolidityArguments for Tuple {
- for_tuples!( where #( Tuple: SolidityArguments ),* );
-
- fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- let mut first = true;
- for_tuples!( #(
- if !Tuple.is_empty() {
- if !first {
- write!(writer, ", ")?;
- }
- first = false;
- Tuple.solidity_name(writer, tc)?;
- }
- )* );
- Ok(())
- }
- fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
- for_tuples!( #(
- Tuple.solidity_get(prefix, writer)?;
- )* );
- Ok(())
- }
- fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- if self.is_empty() {
- Ok(())
- } else if self.len() == 1 {
- for_tuples!( #(
- Tuple.solidity_default(writer, tc)?;
- )* );
- Ok(())
- } else {
- write!(writer, "(")?;
- let mut first = true;
- for_tuples!( #(
- if !Tuple.is_empty() {
- if !first {
- write!(writer, ", ")?;
- }
- first = false;
- Tuple.solidity_default(writer, tc)?;
- }
- )* );
- write!(writer, ")")?;
- Ok(())
- }
- }
- fn len(&self) -> usize {
- for_tuples!( #( Tuple.len() )+* )
- }
-}
-
-pub enum SolidityMutability {
- Pure,
- View,
- Mutable,
-}
-pub struct SolidityFunction<A, R> {
- pub docs: &'static [&'static str],
- pub selector: u32,
- pub hide: bool,
- pub custom_signature: SignatureUnit,
- pub name: &'static str,
- pub args: A,
- pub result: R,
- pub mutability: SolidityMutability,
- pub is_payable: bool,
-}
-impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {
- fn solidity_name(
- &self,
- is_impl: bool,
- writer: &mut impl fmt::Write,
- tc: &TypeCollector,
- ) -> fmt::Result {
- let hide_comment = self.hide.then_some("// ").unwrap_or("");
- for doc in self.docs {
- writeln!(writer, "\t{hide_comment}///{}", doc)?;
- }
- writeln!(
- writer,
- "\t{hide_comment}/// @dev EVM selector for this function is: 0x{:0>8x},",
- self.selector
- )?;
- writeln!(
- writer,
- "\t{hide_comment}/// or in textual repr: {}",
- self.custom_signature.as_str().expect("bad utf-8")
- )?;
- write!(writer, "\t{hide_comment}function {}(", self.name)?;
- self.args.solidity_name(writer, tc)?;
- write!(writer, ")")?;
- if is_impl {
- write!(writer, " public")?;
- } else {
- write!(writer, " external")?;
- }
- match &self.mutability {
- SolidityMutability::Pure => write!(writer, " pure")?,
- SolidityMutability::View => write!(writer, " view")?,
- SolidityMutability::Mutable => {}
- }
- if self.is_payable {
- write!(writer, " payable")?;
- }
- if !self.result.is_empty() {
- write!(writer, " returns (")?;
- self.result.solidity_name(writer, tc)?;
- write!(writer, ")")?;
- }
- if is_impl {
- writeln!(writer, " {{")?;
- writeln!(writer, "\t{hide_comment}\trequire(false, stub_error);")?;
- self.args.solidity_get(hide_comment, writer)?;
- match &self.mutability {
- SolidityMutability::Pure => {}
- SolidityMutability::View => writeln!(writer, "\t{hide_comment}\tdummy;")?,
- SolidityMutability::Mutable => writeln!(writer, "\t{hide_comment}\tdummy = 0;")?,
- }
- if !self.result.is_empty() {
- write!(writer, "\t{hide_comment}\treturn ")?;
- self.result.solidity_default(writer, tc)?;
- writeln!(writer, ";")?;
- }
- writeln!(writer, "\t{hide_comment}}}")?;
- } else {
- writeln!(writer, ";")?;
- }
- if self.hide {
- writeln!(writer, "// FORMATTING: FORCE NEWLINE")?;
- }
- Ok(())
- }
-}
-
-#[impl_for_tuples(0, 48)]
-impl SolidityFunctions for Tuple {
- for_tuples!( where #( Tuple: SolidityFunctions ),* );
-
- fn solidity_name(
- &self,
- is_impl: bool,
- writer: &mut impl fmt::Write,
- tc: &TypeCollector,
- ) -> fmt::Result {
- let mut first = false;
- for_tuples!( #(
- Tuple.solidity_name(is_impl, writer, tc)?;
- )* );
- Ok(())
- }
-}
-
-pub struct SolidityInterface<F: SolidityFunctions> {
- pub docs: &'static [&'static str],
- pub selector: Bytes4,
- pub name: &'static str,
- pub is: &'static [&'static str],
- pub functions: F,
-}
-
-impl<F: SolidityFunctions> SolidityInterface<F> {
- pub fn format(
- &self,
- is_impl: bool,
- out: &mut impl fmt::Write,
- tc: &TypeCollector,
- ) -> fmt::Result {
- const ZERO_BYTES: [u8; 4] = [0; 4];
- for doc in self.docs {
- writeln!(out, "///{}", doc)?;
- }
- if self.selector != ZERO_BYTES {
- writeln!(
- out,
- "/// @dev the ERC-165 identifier for this interface is 0x{:0>8x}",
- u32::from_be_bytes(self.selector)
- )?;
- }
- if is_impl {
- write!(out, "contract ")?;
- } else {
- write!(out, "interface ")?;
- }
- write!(out, "{}", self.name)?;
- if !self.is.is_empty() {
- write!(out, " is")?;
- for (i, n) in self.is.iter().enumerate() {
- if i != 0 {
- write!(out, ",")?;
- }
- write!(out, " {}", n)?;
- }
- }
- writeln!(out, " {{")?;
- self.functions.solidity_name(is_impl, out, tc)?;
- writeln!(out, "}}")?;
- Ok(())
- }
-}
-
-pub struct SolidityEvent<A> {
- pub name: &'static str,
- pub args: A,
-}
-
-impl<A: SolidityArguments> SolidityFunctions for SolidityEvent<A> {
- fn solidity_name(
- &self,
- _is_impl: bool,
- writer: &mut impl fmt::Write,
- tc: &TypeCollector,
- ) -> fmt::Result {
- write!(writer, "\tevent {}(", self.name)?;
- self.args.solidity_name(writer, tc)?;
- writeln!(writer, ");")
- }
-}
-
-#[impl_for_tuples(0, 48)]
-impl SolidityItems for Tuple {
- for_tuples!( where #( Tuple: SolidityItems ),* );
-
- fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- for_tuples!( #(
- Tuple.solidity_name(writer, tc)?;
- )* );
- Ok(())
- }
-}
-
-pub struct SolidityStructField<T> {
- pub docs: &'static [&'static str],
- pub name: &'static str,
- pub ty: PhantomData<*const T>,
-}
-
-impl<T> SolidityItems for SolidityStructField<T>
-where
- T: SolidityTypeName,
-{
- fn solidity_name(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- for doc in self.docs {
- writeln!(out, "///{}", doc)?;
- }
- write!(out, "\t")?;
- T::solidity_name(out, tc)?;
- writeln!(out, " {};", self.name)?;
- Ok(())
- }
-}
-pub struct SolidityStruct<'a, F> {
- pub docs: &'a [&'a str],
- // pub generics:
- pub name: &'a str,
- pub fields: F,
-}
-impl<F> SolidityStruct<'_, F>
-where
- F: SolidityItems,
-{
- pub fn format(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- for doc in self.docs {
- writeln!(out, "///{}", doc)?;
- }
- writeln!(out, "struct {} {{", self.name)?;
- self.fields.solidity_name(out, tc)?;
- writeln!(out, "}}")?;
- Ok(())
- }
-}
-
-pub struct SolidityEnumVariant {
- pub docs: &'static [&'static str],
- pub name: &'static str,
-}
-impl SolidityItems for SolidityEnumVariant {
- fn solidity_name(&self, out: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
- for doc in self.docs {
- writeln!(out, "///{}", doc)?;
- }
- write!(out, "\t{}", self.name)?;
- Ok(())
- }
-}
-pub struct SolidityEnum {
- pub docs: &'static [&'static str],
- pub name: &'static str,
- pub fields: &'static [SolidityEnumVariant],
-}
-impl SolidityEnum {
- pub fn format(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- for doc in self.docs {
- writeln!(out, "///{}", doc)?;
- }
- write!(out, "enum {} {{", self.name)?;
- for (i, field) in self.fields.iter().enumerate() {
- if i != 0 {
- write!(out, ",")?;
- }
- writeln!(out)?;
- field.solidity_name(out, tc)?;
- }
- writeln!(out)?;
- writeln!(out, "}}")?;
- Ok(())
- }
-}
crates/evm-coder/src/solidity/traits.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity/traits.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use super::TypeCollector;
-use core::fmt;
-
-pub trait SolidityTypeName: 'static {
- fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
- /// "simple" types are stored inline, no `memory` modifier should be used in solidity
- fn is_simple() -> bool;
- fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
- /// Specialization
- fn is_void() -> bool {
- false
- }
-}
-
-pub trait SolidityTupleTy: 'static {
- fn fields(tc: &TypeCollector) -> Vec<String>;
- fn len() -> usize;
-}
-pub trait SolidityStructTy: 'static {
- fn generate_solidity_interface(tc: &TypeCollector) -> String;
-}
-pub trait SolidityEnumTy: 'static {
- fn generate_solidity_interface(tc: &TypeCollector) -> String;
- fn solidity_option(&self) -> &str;
-}
-
-pub trait SolidityArguments {
- fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
- fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result;
- fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
- fn is_empty(&self) -> bool {
- self.len() == 0
- }
- fn len(&self) -> usize;
-}
-
-pub trait SolidityFunctions {
- fn solidity_name(
- &self,
- is_impl: bool,
- writer: &mut impl fmt::Write,
- tc: &TypeCollector,
- ) -> fmt::Result;
-}
-
-pub trait SolidityItems {
- fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
- // For PhantomData fields
- // fn is_void()
-}
crates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/abi_derive_generation.rs
+++ /dev/null
@@ -1,765 +0,0 @@
-mod test_struct {
- use evm_coder_procedural::AbiCoder;
- use evm_coder::types::Bytes;
-
- #[test]
- fn empty_struct() {
- let t = trybuild::TestCases::new();
- t.compile_fail("tests/build_failed/abi_derive_struct_generation.rs");
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct1SimpleParam {
- _a: u8,
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct1DynamicParam {
- _a: String,
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct2SimpleParam {
- _a: u8,
- _b: u32,
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct2DynamicParam {
- _a: String,
- _b: Bytes,
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct2MixedParam {
- _a: u8,
- _b: Bytes,
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct1DerivedSimpleParam {
- _a: TypeStruct1SimpleParam,
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct2DerivedSimpleParam {
- _a: TypeStruct1SimpleParam,
- _b: TypeStruct2SimpleParam,
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct1DerivedDynamicParam {
- _a: TypeStruct1DynamicParam,
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct2DerivedDynamicParam {
- _a: TypeStruct1DynamicParam,
- _b: TypeStruct2DynamicParam,
- }
-
- /// Some docs
- /// At multi
- /// line
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct3DerivedMixedParam {
- /// Docs for A
- /// multi
- /// line
- _a: TypeStruct1SimpleParam,
- /// Docs for B
- _b: TypeStruct2DynamicParam,
- /// Docs for C
- _c: TypeStruct2MixedParam,
- }
-
- #[test]
- fn impl_abi_type_signature() {
- assert_eq!(
- <TypeStruct1SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "(uint8)"
- );
- assert_eq!(
- <TypeStruct1DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "(string)"
- );
- assert_eq!(
- <TypeStruct2SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "(uint8,uint32)"
- );
- assert_eq!(
- <TypeStruct2DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "(string,bytes)"
- );
- assert_eq!(
- <TypeStruct2MixedParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "(uint8,bytes)"
- );
- assert_eq!(
- <TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "((uint8))"
- );
- assert_eq!(
- <TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "((uint8),(uint8,uint32))"
- );
- assert_eq!(
- <TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "((string))"
- );
- assert_eq!(
- <TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "((string),(string,bytes))"
- );
- assert_eq!(
- <TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- "((uint8),(string,bytes),(uint8,bytes))"
- );
- }
-
- #[test]
- fn impl_abi_type_is_dynamic() {
- assert_eq!(
- <TypeStruct1SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
- false
- );
- assert_eq!(
- <TypeStruct1DynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
- true
- );
- assert_eq!(
- <TypeStruct2SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
- false
- );
- assert_eq!(
- <TypeStruct2DynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
- true
- );
- assert_eq!(
- <TypeStruct2MixedParam as evm_coder::abi::AbiType>::is_dynamic(),
- true
- );
- assert_eq!(
- <TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
- false
- );
- assert_eq!(
- <TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
- false
- );
- assert_eq!(
- <TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
- true
- );
- assert_eq!(
- <TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
- true
- );
- assert_eq!(
- <TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::is_dynamic(),
- true
- );
- }
-
- #[test]
- fn impl_abi_type_size() {
- const ABI_ALIGNMENT: usize = 32;
- assert_eq!(
- <TypeStruct1SimpleParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT
- );
- assert_eq!(
- <TypeStruct1DynamicParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT
- );
- assert_eq!(
- <TypeStruct2SimpleParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT * 2
- );
- assert_eq!(
- <TypeStruct2DynamicParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT * 2
- );
- assert_eq!(
- <TypeStruct2MixedParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT * 2
- );
- assert_eq!(
- <TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT
- );
- assert_eq!(
- <TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT * 3
- );
- assert_eq!(
- <TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT
- );
- assert_eq!(
- <TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT * 3
- );
- assert_eq!(
- <TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::size(),
- ABI_ALIGNMENT * 5
- );
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct1SimpleParam(u8);
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct1DynamicParam(String);
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct2SimpleParam(u8, u32);
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct2DynamicParam(String, Bytes);
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct2MixedParam(u8, Bytes);
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam);
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct2DerivedSimpleParam(TupleStruct1SimpleParam, TupleStruct2SimpleParam);
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam);
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct2DerivedDynamicParam(TupleStruct1DynamicParam, TupleStruct2DynamicParam);
-
- /// Some docs
- /// At multi
- /// line
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct3DerivedMixedParam(
- /// Docs for A
- /// multi
- /// line
- TupleStruct1SimpleParam,
- TupleStruct2DynamicParam,
- /// Docs for C
- TupleStruct2MixedParam,
- );
-
- #[test]
- fn impl_abi_type_signature_same_for_structs() {
- assert_eq!(
- <TypeStruct1SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct1SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap()
- );
- assert_eq!(
- <TypeStruct1DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct1DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap()
- );
- assert_eq!(
- <TypeStruct2SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct2SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap()
- );
- assert_eq!(
- <TypeStruct2DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct2DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap()
- );
- assert_eq!(
- <TypeStruct2MixedParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct2MixedParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- );
- assert_eq!(
- <TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- );
- assert_eq!(
- <TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- );
- assert_eq!(
- <TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- );
- assert_eq!(
- <TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- );
- assert_eq!(
- <TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <TupleStruct3DerivedMixedParam as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- );
- }
-
- #[test]
- fn impl_abi_type_is_dynamic_same_for_structs() {
- assert_eq!(
- <TypeStruct1SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct1SimpleParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct1DynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct1DynamicParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct2SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct2SimpleParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct2DynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct2DynamicParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct2MixedParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct2MixedParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- assert_eq!(
- <TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::is_dynamic(),
- <TupleStruct3DerivedMixedParam as evm_coder::abi::AbiType>::is_dynamic()
- );
- }
-
- #[test]
- fn impl_abi_type_size_same_for_structs() {
- assert_eq!(
- <TypeStruct1SimpleParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct1SimpleParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct1DynamicParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct1DynamicParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct2SimpleParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct2SimpleParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct2DynamicParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct2DynamicParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct2MixedParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct2MixedParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::size()
- );
- assert_eq!(
- <TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::size(),
- <TupleStruct3DerivedMixedParam as evm_coder::abi::AbiType>::size()
- );
- }
-
- const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef;
-
- fn test_impl<Tuple, TupleStruct, TypeStruct>(
- tuple_data: Tuple,
- tuple_struct_data: TupleStruct,
- type_struct_data: TypeStruct,
- ) where
- TypeStruct: evm_coder::abi::AbiWrite
- + evm_coder::abi::AbiRead
- + std::cmp::PartialEq
- + std::fmt::Debug,
- TupleStruct: evm_coder::abi::AbiWrite
- + evm_coder::abi::AbiRead
- + std::cmp::PartialEq
- + std::fmt::Debug,
- Tuple: evm_coder::abi::AbiWrite
- + evm_coder::abi::AbiRead
- + std::cmp::PartialEq
- + std::fmt::Debug,
- {
- let encoded_type_struct = test_abi_write_impl(&type_struct_data);
- let encoded_tuple_struct = test_abi_write_impl(&tuple_struct_data);
- let encoded_tuple = test_abi_write_impl(&tuple_data);
-
- similar_asserts::assert_eq!(encoded_tuple, encoded_type_struct);
- similar_asserts::assert_eq!(encoded_tuple, encoded_tuple_struct);
-
- {
- let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_tuple).unwrap();
- let restored_struct_data = <TypeStruct>::abi_read(&mut decoder).unwrap();
- assert_eq!(restored_struct_data, type_struct_data);
- }
- {
- let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_tuple).unwrap();
- let restored_struct_data = <TupleStruct>::abi_read(&mut decoder).unwrap();
- assert_eq!(restored_struct_data, tuple_struct_data);
- }
-
- {
- let (_, mut decoder) =
- evm_coder::abi::AbiReader::new_call(&encoded_type_struct).unwrap();
- let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
- assert_eq!(restored_tuple_data, tuple_data);
- }
- {
- let (_, mut decoder) =
- evm_coder::abi::AbiReader::new_call(&encoded_tuple_struct).unwrap();
- let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
- assert_eq!(restored_tuple_data, tuple_data);
- }
- }
-
- fn test_abi_write_impl<A>(data: &A) -> Vec<u8>
- where
- A: evm_coder::abi::AbiWrite
- + evm_coder::abi::AbiRead
- + std::cmp::PartialEq
- + std::fmt::Debug,
- {
- let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER);
- data.abi_write(&mut writer);
- let encoded_tuple = writer.finish();
- encoded_tuple
- }
-
- #[test]
- fn codec_struct_1_simple() {
- let _a = 0xff;
- test_impl::<(u8,), TupleStruct1SimpleParam, TypeStruct1SimpleParam>(
- (_a,),
- TupleStruct1SimpleParam(_a),
- TypeStruct1SimpleParam { _a },
- );
- }
-
- #[test]
- fn codec_struct_1_dynamic() {
- let _a: String = "some string".into();
- test_impl::<(String,), TupleStruct1DynamicParam, TypeStruct1DynamicParam>(
- (_a.clone(),),
- TupleStruct1DynamicParam(_a.clone()),
- TypeStruct1DynamicParam { _a },
- );
- }
-
- #[test]
- fn codec_struct_1_derived_simple() {
- let _a: u8 = 0xff;
- test_impl::<((u8,),), TupleStruct1DerivedSimpleParam, TypeStruct1DerivedSimpleParam>(
- ((_a,),),
- TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam(_a)),
- TypeStruct1DerivedSimpleParam {
- _a: TypeStruct1SimpleParam { _a },
- },
- );
- }
-
- #[test]
- fn codec_struct_1_derived_dynamic() {
- let _a: String = "some string".into();
- test_impl::<((String,),), TupleStruct1DerivedDynamicParam, TypeStruct1DerivedDynamicParam>(
- ((_a.clone(),),),
- TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam(_a.clone())),
- TypeStruct1DerivedDynamicParam {
- _a: TypeStruct1DynamicParam { _a },
- },
- );
- }
-
- #[test]
- fn codec_struct_2_simple() {
- let _a = 0xff;
- let _b = 0xbeefbaba;
- test_impl::<(u8, u32), TupleStruct2SimpleParam, TypeStruct2SimpleParam>(
- (_a, _b),
- TupleStruct2SimpleParam(_a, _b),
- TypeStruct2SimpleParam { _a, _b },
- );
- }
-
- #[test]
- fn codec_struct_2_dynamic() {
- let _a: String = "some string".into();
- let _b: Bytes = Bytes(vec![0x11, 0x22, 0x33]);
- test_impl::<(String, Bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>(
- (_a.clone(), _b.clone()),
- TupleStruct2DynamicParam(_a.clone(), _b.clone()),
- TypeStruct2DynamicParam { _a, _b },
- );
- }
-
- #[test]
- fn codec_struct_2_mixed() {
- let _a: u8 = 0xff;
- let _b: Bytes = Bytes(vec![0x11, 0x22, 0x33]);
- test_impl::<(u8, Bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>(
- (_a.clone(), _b.clone()),
- TupleStruct2MixedParam(_a.clone(), _b.clone()),
- TypeStruct2MixedParam { _a, _b },
- );
- }
-
- #[test]
- fn codec_struct_2_derived_simple() {
- let _a = 0xff;
- let _b = 0xbeefbaba;
- test_impl::<
- ((u8,), (u8, u32)),
- TupleStruct2DerivedSimpleParam,
- TypeStruct2DerivedSimpleParam,
- >(
- ((_a,), (_a, _b)),
- TupleStruct2DerivedSimpleParam(
- TupleStruct1SimpleParam(_a),
- TupleStruct2SimpleParam(_a, _b),
- ),
- TypeStruct2DerivedSimpleParam {
- _a: TypeStruct1SimpleParam { _a },
- _b: TypeStruct2SimpleParam { _a, _b },
- },
- );
- }
-
- #[test]
- fn codec_struct_2_derived_dynamic() {
- let _a = "some string".to_string();
- let _b = Bytes(vec![0x11, 0x22, 0x33]);
- test_impl::<
- ((String,), (String, Bytes)),
- TupleStruct2DerivedDynamicParam,
- TypeStruct2DerivedDynamicParam,
- >(
- ((_a.clone(),), (_a.clone(), _b.clone())),
- TupleStruct2DerivedDynamicParam(
- TupleStruct1DynamicParam(_a.clone()),
- TupleStruct2DynamicParam(_a.clone(), _b.clone()),
- ),
- TypeStruct2DerivedDynamicParam {
- _a: TypeStruct1DynamicParam { _a: _a.clone() },
- _b: TypeStruct2DynamicParam { _a, _b },
- },
- );
- }
-
- #[test]
- fn codec_struct_3_derived_mixed() {
- let int = 0xff;
- let by = Bytes(vec![0x11, 0x22, 0x33]);
- let string = "some string".to_string();
- test_impl::<
- ((u8,), (String, Bytes), (u8, Bytes)),
- TupleStruct3DerivedMixedParam,
- TypeStruct3DerivedMixedParam,
- >(
- ((int,), (string.clone(), by.clone()), (int, by.clone())),
- TupleStruct3DerivedMixedParam(
- TupleStruct1SimpleParam(int),
- TupleStruct2DynamicParam(string.clone(), by.clone()),
- TupleStruct2MixedParam(int, by.clone()),
- ),
- TypeStruct3DerivedMixedParam {
- _a: TypeStruct1SimpleParam { _a: int },
- _b: TypeStruct2DynamicParam {
- _a: string.clone(),
- _b: by.clone(),
- },
- _c: TypeStruct2MixedParam { _a: int, _b: by },
- },
- );
- }
-
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TypeStruct2SimpleStruct1Simple {
- _a: TypeStruct2SimpleParam,
- _b: TypeStruct2SimpleParam,
- _c: u8,
- }
- #[derive(AbiCoder, PartialEq, Debug)]
- struct TupleStruct2SimpleStruct1Simple(TupleStruct2SimpleParam, TupleStruct2SimpleParam, u8);
-
- #[test]
- fn codec_struct_2_struct_simple_1_simple() {
- let _a = 0xff;
- let _b = 0xbeefbaba;
- test_impl::<
- ((u8, u32), (u8, u32), u8),
- TupleStruct2SimpleStruct1Simple,
- TypeStruct2SimpleStruct1Simple,
- >(
- ((_a, _b), (_a, _b), _a),
- TupleStruct2SimpleStruct1Simple(
- TupleStruct2SimpleParam(_a, _b),
- TupleStruct2SimpleParam(_a, _b),
- _a,
- ),
- TypeStruct2SimpleStruct1Simple {
- _a: TypeStruct2SimpleParam { _a, _b },
- _b: TypeStruct2SimpleParam { _a, _b },
- _c: _a,
- },
- );
- }
-}
-
-mod test_enum {
- use evm_coder::AbiCoder;
-
- /// Some docs
- /// At multi
- /// line
- #[derive(AbiCoder, Debug, PartialEq, Default, Clone, Copy)]
- #[repr(u8)]
- enum Color {
- /// Docs for Red
- /// multi
- /// line
- Red,
- Green,
- /// Docs for Blue
- #[default]
- Blue,
- }
-
- #[test]
- fn empty() {}
-
- #[test]
- fn bad_enums() {
- let t = trybuild::TestCases::new();
- t.compile_fail("tests/build_failed/abi_derive_enum_generation.rs");
- }
-
- #[test]
- fn impl_abi_type_signature_same_for_structs() {
- assert_eq!(
- <Color as evm_coder::abi::AbiType>::SIGNATURE
- .as_str()
- .unwrap(),
- <u8 as evm_coder::abi::AbiType>::SIGNATURE.as_str().unwrap()
- );
- }
-
- #[test]
- fn impl_abi_type_is_dynamic_same_for_structs() {
- assert_eq!(
- <Color as evm_coder::abi::AbiType>::is_dynamic(),
- <u8 as evm_coder::abi::AbiType>::is_dynamic()
- );
- }
-
- #[test]
- fn impl_abi_type_size_same_for_structs() {
- assert_eq!(
- <Color as evm_coder::abi::AbiType>::size(),
- <u8 as evm_coder::abi::AbiType>::size()
- );
- }
-
- #[test]
- fn test_coder() {
- const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef;
-
- let encoded_enum = {
- let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER);
- <Color as evm_coder::abi::AbiWrite>::abi_write(&Color::Green, &mut writer);
- writer.finish()
- };
-
- let encoded_u8 = {
- let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER);
- <u8 as evm_coder::abi::AbiWrite>::abi_write(&(Color::Green as u8), &mut writer);
- writer.finish()
- };
-
- similar_asserts::assert_eq!(encoded_enum, encoded_u8);
-
- {
- let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_enum).unwrap();
- let restored_enum_data =
- <Color as evm_coder::abi::AbiRead>::abi_read(&mut decoder).unwrap();
- assert_eq!(restored_enum_data, Color::Green);
- }
- }
-}
crates/evm-coder/tests/build_failed/abi_derive_enum_generation.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use evm_coder_procedural::AbiCoder;
-
-#[derive(AbiCoder)]
-enum NonRepr {
- A,
- B,
- C,
-}
-
-#[derive(AbiCoder)]
-#[repr(u32)]
-enum NonReprU8 {
- A,
- B,
- C,
-}
-
-#[derive(AbiCoder)]
-#[repr(u8)]
-enum RustEnum {
- A(u128),
- B,
- C,
-}
-
-#[derive(AbiCoder)]
-#[repr(u8)]
-enum WithExplicit {
- A = 128,
- B,
- C,
-}
-
-fn main() {
- assert!(false);
-}
crates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderrdiffbeforeafterboth--- a/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: Enum is not "repr(u8)"
- --> tests/build_failed/abi_derive_enum_generation.rs:4:6
- |
-4 | enum NonRepr {
- | ^^^^^^^
-
-error: Enum is not "repr(u8)"
- --> tests/build_failed/abi_derive_enum_generation.rs:11:8
- |
-11 | #[repr(u32)]
- | ^^^
-
-error: Enumeration parameters should not have fields
- --> tests/build_failed/abi_derive_enum_generation.rs:21:2
- |
-21 | A(u128),
- | ^
-
-error: Enumeration options should not have an explicit specified value
- --> tests/build_failed/abi_derive_enum_generation.rs:29:2
- |
-29 | A = 128,
- | ^
crates/evm-coder/tests/build_failed/abi_derive_struct_generation.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use evm_coder_procedural::AbiCoder;
-
-#[derive(AbiCoder, PartialEq, Debug)]
-struct EmptyStruct {}
-
-#[derive(AbiCoder, PartialEq, Debug)]
-struct EmptyTupleStruct();
-
-fn main() {
- assert!(false);
-}
crates/evm-coder/tests/build_failed/abi_derive_struct_generation.stderrdiffbeforeafterboth--- a/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: Empty structs not supported
- --> tests/build_failed/abi_derive_struct_generation.rs:4:8
- |
-4 | struct EmptyStruct {}
- | ^^^^^^^^^^^
-
-error: Empty structs not supported
- --> tests/build_failed/abi_derive_struct_generation.rs:7:8
- |
-7 | struct EmptyTupleStruct();
- | ^^^^^^^^^^^^^^^^
crates/evm-coder/tests/build_failed/custom_signature_over_max_size.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-#![allow(dead_code)]
-use std::str::from_utf8;
-
-use evm_coder::{
- make_signature,
- custom_signature::{SignatureUnit, SIGNATURE_SIZE_LIMIT},
-};
-
-trait Name {
- const SIGNATURE: SignatureUnit;
-
- fn name() -> &'static str {
- from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
- }
-}
-
-impl<T: Name> Name for Vec<T> {
- const SIGNATURE: SignatureUnit =
- evm_coder::make_signature!(new nameof(T::SIGNATURE) fixed("[]"));
-}
-
-struct MaxSize();
-impl Name for MaxSize {
- const SIGNATURE: SignatureUnit = SignatureUnit {
- data: [b'!'; SIGNATURE_SIZE_LIMIT],
- len: SIGNATURE_SIZE_LIMIT,
- };
-}
-
-const NAME: SignatureUnit = <Vec<MaxSize>>::SIGNATURE;
-
-fn main() {
- assert!(false);
-}
crates/evm-coder/tests/build_failed/custom_signature_over_max_size.stderrdiffbeforeafterboth--- a/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-warning: unused import: `make_signature`
- --> tests/build_failed/custom_signature_over_max_size.rs:5:2
- |
-5 | make_signature,
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(unused_imports)]` on by default
-
-error[E0080]: evaluation of `<std::vec::Vec<MaxSize> as Name>::SIGNATURE` failed
- --> tests/build_failed/custom_signature_over_max_size.rs:19:3
- |
-19 | evm_coder::make_signature!(new nameof(T::SIGNATURE) fixed("[]"));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 256 but the index is 256
- |
- = note: this error originates in the macro `$crate::make_signature` which comes from the expansion of the macro `evm_coder::make_signature` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: evaluation of constant value failed
- --> tests/build_failed/custom_signature_over_max_size.rs:30:29
- |
-30 | const NAME: SignatureUnit = <Vec<MaxSize>>::SIGNATURE;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
crates/evm-coder/tests/conditional_is.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/conditional_is.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-use evm_coder::{types::*, solidity_interface, execution::Result};
-
-pub struct Contract(bool);
-
-#[solidity_interface(name = A)]
-impl Contract {
- fn method_a() -> Result<()> {
- Ok(())
- }
-}
-
-#[solidity_interface(name = B)]
-impl Contract {
- fn method_b() -> Result<()> {
- Ok(())
- }
-}
-
-#[solidity_interface(name = Contract, is(
- A(if(this.0)),
- B(if(!this.0)),
-))]
-impl Contract {}
-
-#[test]
-fn conditional_erc165() {
- assert!(ContractCall::supports_interface(
- &Contract(true),
- ACall::METHOD_A
- ));
- assert!(!ContractCall::supports_interface(
- &Contract(false),
- ACall::METHOD_A
- ));
-
- assert!(ContractCall::supports_interface(
- &Contract(false),
- BCall::METHOD_B
- ));
- assert!(!ContractCall::supports_interface(
- &Contract(true),
- BCall::METHOD_B
- ));
-}
crates/evm-coder/tests/generics.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/generics.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use std::marker::PhantomData;
-use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};
-use primitive_types::U256;
-
-pub struct Generic<T>(PhantomData<T>);
-
-#[solidity_interface(name = GenericIs)]
-impl<T> Generic<T> {
- fn test_1(&self) -> Result<U256> {
- unreachable!()
- }
-}
-
-#[solidity_interface(name = Generic, is(GenericIs))]
-impl<T: Into<u32>> Generic<T> {
- fn test_2(&self) -> Result<U256> {
- unreachable!()
- }
-}
-
-generate_stubgen!(gen_iface, GenericCall<()>, false);
-
-#[solidity_interface(name = GenericWhere)]
-impl<T> Generic<T>
-where
- T: core::fmt::Debug,
-{
- fn test_3(&self) -> Result<U256> {
- unreachable!()
- }
-}
-
-generate_stubgen!(gen_where_iface, GenericWhereCall<()>, false);
crates/evm-coder/tests/log.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/log.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#![allow(dead_code)]
-
-use evm_coder::{ToLog, types::*};
-use primitive_types::U256;
-
-#[derive(ToLog)]
-enum ERC721Log {
- Transfer {
- #[indexed]
- from: Address,
- #[indexed]
- to: Address,
- value: U256,
- },
- Eee {
- #[indexed]
- aaa: Address,
- bbb: U256,
- },
-}
crates/evm-coder/tests/random.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/random.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#![allow(dead_code)] // This test only checks that macros is not panicking
-
-use evm_coder::{
- abi::AbiType, ToLog, execution::Result, solidity_interface, types::*, solidity, weight,
-};
-use primitive_types::U256;
-
-pub struct Impls;
-
-#[solidity_interface(name = OurInterface)]
-impl Impls {
- fn fn_a(&self, _input: U256) -> Result<bool> {
- unreachable!()
- }
-}
-
-#[solidity_interface(name = OurInterface1)]
-impl Impls {
- fn fn_b(&self, _input: u128) -> Result<u32> {
- unreachable!()
- }
-}
-
-#[derive(ToLog)]
-enum OurEvents {
- Event1 {
- field1: u32,
- },
- Event2 {
- field1: u32,
- #[indexed]
- field2: u32,
- },
-}
-
-#[solidity_interface(
- name = OurInterface2,
- is(OurInterface),
- inline_is(OurInterface1),
- events(OurEvents)
-)]
-impl Impls {
- #[solidity(rename_selector = "fnK")]
- fn fn_c(&self, _input: u32) -> Result<u8> {
- unreachable!()
- }
- fn fn_d(&self, _value: u32) -> Result<u32> {
- unreachable!()
- }
-
- fn caller_sensitive(&self, _caller: Caller) -> Result<u8> {
- unreachable!()
- }
- fn payable(&mut self, _value: Value) -> Result<u8> {
- unreachable!()
- }
-
- #[weight(*_weight)]
- fn with_weight(&self, _weight: u64) -> Result<()> {
- unreachable!()
- }
-
- /// Doccoment example
- fn with_doc(&self) -> Result<()> {
- unreachable!()
- }
-}
-
-#[solidity_interface(
- name = ValidSelector,
- expect_selector = 0x00000000,
-)]
-impl Impls {}
crates/evm-coder/tests/solidity_generation.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/solidity_generation.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use evm_coder::{abi::AbiType, execution::Result, generate_stubgen, solidity_interface, types::*};
-use primitive_types::U256;
-
-pub struct ERC20;
-
-#[solidity_interface(name = ERC20)]
-impl ERC20 {
- fn decimals(&self) -> Result<u8> {
- unreachable!()
- }
- /// Get balance of specified owner
- fn balance_of(&self, _owner: Address) -> Result<U256> {
- unreachable!()
- }
- fn transfer(&mut self, _caller: Caller, _to: Address, _value: U256) -> Result<bool> {
- unreachable!()
- }
- fn transfer_from(
- &mut self,
- _caller: Caller,
- _from: Address,
- _to: Address,
- _value: U256,
- ) -> Result<bool> {
- unreachable!()
- }
- fn approve(&mut self, _caller: Caller, _spender: Address, _value: U256) -> Result<bool> {
- unreachable!()
- }
- fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {
- unreachable!()
- }
-}
-
-generate_stubgen!(gen_impl, ERC20Call, true);
-generate_stubgen!(gen_iface, ERC20Call, false);
crates/struct-versioning/src/lib.rsdiffbeforeafterboth--- a/crates/struct-versioning/src/lib.rs
+++ b/crates/struct-versioning/src/lib.rs
@@ -223,7 +223,7 @@
};
let current_fields = fields
.iter()
- .filter_map(|(ver, field)| ver.exists_on(version).then(|| field));
+ .filter_map(|(ver, field)| ver.exists_on(version).then_some(field));
let mut doc = Vec::new();
if version > attr.first_version {
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -17,12 +17,12 @@
//! This module contains the implementation of pallet methods for evm.
pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};
-use evm_coder::{
+use pallet_evm_coder_substrate::{
abi::AbiType,
- solidity_interface, solidity, ToLog,
+ solidity_interface, ToLog,
types::*,
- execution::{Result, Error},
- weight,
+ execution::{Result, Error, PreDispatch},
+ frontier_contract,
};
use pallet_evm_coder_substrate::dispatch_to_evm;
use sp_std::{vec, vec::Vec};
@@ -36,6 +36,11 @@
Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf, eth, weights::WeightInfo,
};
+frontier_contract! {
+ macro_rules! CollectionHandle_result {...}
+ impl<T: Config> Contract for CollectionHandle<T> {...}
+}
+
/// Events for ethereum collection helper.
#[derive(ToLog)]
pub enum CollectionHelpersEvents {
@@ -83,7 +88,7 @@
}
/// @title A contract that allows you to work with collections.
-#[solidity_interface(name = Collection)]
+#[solidity_interface(name = Collection, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> CollectionHandle<T>
where
T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
@@ -272,7 +277,7 @@
None => return Ok(Default::default()),
};
- Ok(eth::CrossAddress::from_sub::<T>(&sponsor))
+ Ok(eth::CrossAddress::from_sub::<T>(sponsor))
}
/// Get current collection limits.
@@ -280,11 +285,6 @@
/// @return Array of collection limits
fn collection_limits(&self) -> Result<Vec<eth::CollectionLimit>> {
let limits = &self.collection.limits;
-
- let convert_value_from_bool = |ob: Option<bool>| match ob {
- Some(b) => Some(b as u32),
- None => None,
- };
Ok(vec![
eth::CollectionLimit::new(
@@ -307,10 +307,12 @@
None
}
})
- .unwrap_or(eth::CollectionLimit::new(
- eth::CollectionLimitField::SponsoredDataRateLimit,
- Default::default(),
- )),
+ .unwrap_or_else(|| {
+ eth::CollectionLimit::new(
+ eth::CollectionLimitField::SponsoredDataRateLimit,
+ Default::default(),
+ )
+ }),
eth::CollectionLimit::new(eth::CollectionLimitField::TokenLimit, limits.token_limit),
eth::CollectionLimit::new(
eth::CollectionLimitField::SponsorTransferTimeout,
@@ -322,15 +324,15 @@
),
eth::CollectionLimit::new(
eth::CollectionLimitField::OwnerCanTransfer,
- convert_value_from_bool(limits.owner_can_transfer),
+ limits.owner_can_transfer.map(u32::from),
),
eth::CollectionLimit::new(
eth::CollectionLimitField::OwnerCanDestroy,
- convert_value_from_bool(limits.owner_can_destroy),
+ limits.owner_can_destroy.map(u32::from),
),
eth::CollectionLimit::new(
eth::CollectionLimitField::TransferEnabled,
- convert_value_from_bool(limits.transfers_enabled),
+ limits.transfers_enabled.map(u32::from),
),
])
}
@@ -680,7 +682,7 @@
/// Contains static property keys and values.
pub mod static_property {
- use evm_coder::{
+ use pallet_evm_coder_substrate::{
execution::{Result, Error},
};
use alloc::format;
pallets/common/src/eth.rsdiffbeforeafterboth--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -105,7 +105,9 @@
}
}
/// Converts [`CrossAddress`] to `CrossAccountId`.
- pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>
+ pub fn into_sub_cross_account<T>(
+ &self,
+ ) -> pallet_evm_coder_substrate::execution::Result<T::CrossAccountId>
where
T: pallet_evm::Config,
T::AccountId: From<[u8; 32]>,
@@ -130,7 +132,7 @@
}
impl TryFrom<up_data_structs::Property> for Property {
- type Error = evm_coder::execution::Error;
+ type Error = pallet_evm_coder_substrate::execution::Error;
fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {
let key = evm_coder::types::String::from_utf8(from.key.into())
@@ -141,7 +143,7 @@
}
impl TryInto<up_data_structs::Property> for Property {
- type Error = evm_coder::execution::Error;
+ type Error = pallet_evm_coder_substrate::execution::Error;
fn try_into(self) -> Result<up_data_structs::Property, Self::Error> {
let key = <Vec<u8>>::from(self.key)
@@ -212,7 +214,7 @@
}
impl TryInto<up_data_structs::CollectionLimits> for CollectionLimit {
- type Error = evm_coder::execution::Error;
+ type Error = pallet_evm_coder_substrate::execution::Error;
fn try_into(self) -> Result<up_data_structs::CollectionLimits, Self::Error> {
let value = self
@@ -378,7 +380,8 @@
/// Convert vector of [`TokenPropertyPermission`] into vector of [`up_data_structs::PropertyKeyPermission`].
pub fn into_property_key_permissions(
permissions: Vec<TokenPropertyPermission>,
- ) -> evm_coder::execution::Result<Vec<up_data_structs::PropertyKeyPermission>> {
+ ) -> pallet_evm_coder_substrate::execution::Result<Vec<up_data_structs::PropertyKeyPermission>>
+ {
let mut perms = Vec::new();
for TokenPropertyPermission { key, permissions } in permissions {
pallets/common/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::{57 ops::{Deref, DerefMut},58 slice::from_ref,59};60use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};61use sp_std::vec::Vec;62use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};63use evm_coder::ToLog;64use frame_support::{65 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},66 ensure,67 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},68 dispatch::Pays,69 transactional, fail,70};71use pallet_evm::GasWeightMapping;72use up_data_structs::{73 AccessMode,74 COLLECTION_NUMBER_LIMIT,75 Collection,76 RpcCollection,77 CollectionFlags,78 RpcCollectionFlags,79 CollectionId,80 CreateItemData,81 MAX_TOKEN_PREFIX_LENGTH,82 COLLECTION_ADMINS_LIMIT,83 TokenId,84 TokenChild,85 CollectionStats,86 MAX_TOKEN_OWNERSHIP,87 CollectionMode,88 NFT_SPONSOR_TRANSFER_TIMEOUT,89 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,90 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,91 MAX_SPONSOR_TIMEOUT,92 CUSTOM_DATA_LIMIT,93 CollectionLimits,94 CreateCollectionData,95 SponsorshipState,96 CreateItemExData,97 SponsoringRateLimit,98 budget::Budget,99 PhantomType,100 Property,101 Properties,102 PropertiesPermissionMap,103 PropertyKey,104 PropertyValue,105 PropertyPermission,106 PropertiesError,107 TokenOwnerError,108 PropertyKeyPermission,109 TokenData,110 TrySetProperty,111 PropertyScope,112 // RMRK113 RmrkCollectionInfo,114 RmrkInstanceInfo,115 RmrkResourceInfo,116 RmrkPropertyInfo,117 RmrkBaseInfo,118 RmrkPartType,119 RmrkBoundedTheme,120 RmrkNftChild,121 CollectionPermissions,122};123use up_pov_estimate_rpc::PovInfo;124125pub use pallet::*;126use sp_core::H160;127use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};128129use crate::erc::CollectionHelpersEvents;130#[cfg(feature = "runtime-benchmarks")]131pub mod benchmarking;132pub mod dispatch;133pub mod erc;134pub mod eth;135pub mod weights;136137/// Weight info.138pub type SelfWeightOf<T> = <T as Config>::WeightInfo;139140/// Collection handle contains information about collection data and id.141/// Also provides functionality to count consumed gas.142///143/// CollectionHandle is used as a generic wrapper for collections of all types.144/// It allows to perform common operations and queries on any collection type,145/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].146#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]147pub struct CollectionHandle<T: Config> {148 /// Collection id149 pub id: CollectionId,150 collection: Collection<T::AccountId>,151 /// Substrate recorder for counting consumed gas152 pub recorder: SubstrateRecorder<T>,153}154155impl<T: Config> WithRecorder<T> for CollectionHandle<T> {156 fn recorder(&self) -> &SubstrateRecorder<T> {157 &self.recorder158 }159 fn into_recorder(self) -> SubstrateRecorder<T> {160 self.recorder161 }162}163164impl<T: Config> CollectionHandle<T> {165 /// Same as [CollectionHandle::new] but with an explicit gas limit.166 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {167 <CollectionById<T>>::get(id).map(|collection| Self {168 id,169 collection,170 recorder: SubstrateRecorder::new(gas_limit),171 })172 }173174 /// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].175 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {176 <CollectionById<T>>::get(id).map(|collection| Self {177 id,178 collection,179 recorder,180 })181 }182183 /// Retrives collection data from storage and creates collection handle with default parameters.184 /// If collection not found return `None`185 pub fn new(id: CollectionId) -> Option<Self> {186 Self::new_with_gas_limit(id, u64::MAX)187 }188189 /// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.190 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {191 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)192 }193194 /// Consume gas for reading.195 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {196 self.recorder197 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(198 <T as frame_system::Config>::DbWeight::get()199 .read200 .saturating_mul(reads),201 )))202 }203204 /// Consume gas for writing.205 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {206 self.recorder207 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(208 <T as frame_system::Config>::DbWeight::get()209 .write210 .saturating_mul(writes),211 )))212 }213214 /// Consume gas for reading and writing.215 pub fn consume_store_reads_and_writes(216 &self,217 reads: u64,218 writes: u64,219 ) -> evm_coder::execution::Result<()> {220 let weight = <T as frame_system::Config>::DbWeight::get();221 let reads = weight.read.saturating_mul(reads);222 let writes = weight.read.saturating_mul(writes);223 self.recorder224 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(225 reads.saturating_add(writes),226 )))227 }228229 /// Save collection to storage.230 pub fn save(&self) -> DispatchResult {231 <CollectionById<T>>::insert(self.id, &self.collection);232 Ok(())233 }234235 /// Set collection sponsor.236 ///237 /// Unique collections allows sponsoring for certain actions.238 /// This method allows you to set the sponsor of the collection.239 /// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].240 pub fn set_sponsor(241 &mut self,242 sender: &T::CrossAccountId,243 sponsor: T::AccountId,244 ) -> DispatchResult {245 self.check_is_internal()?;246 self.check_is_owner_or_admin(sender)?;247248 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor.clone());249250 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor));251 <PalletEvm<T>>::deposit_log(252 erc::CollectionHelpersEvents::CollectionChanged {253 collection_id: eth::collection_id_to_address(self.id),254 }255 .to_log(T::ContractAddress::get()),256 );257258 self.save()259 }260261 /// Force set `sponsor`.262 ///263 /// Differs from [`set_sponsor`][`Self::set_sponsor`] in that confirmation264 /// from the `sponsor` is not required.265 ///266 /// # Arguments267 ///268 /// * `sender`: Caller's account.269 /// * `sponsor`: ID of the account of the sponsor-to-be.270 pub fn force_set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {271 self.check_is_internal()?;272273 self.collection.sponsorship = SponsorshipState::Confirmed(sponsor.clone());274275 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor.clone()));276 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sponsor));277 <PalletEvm<T>>::deposit_log(278 erc::CollectionHelpersEvents::CollectionChanged {279 collection_id: eth::collection_id_to_address(self.id),280 }281 .to_log(T::ContractAddress::get()),282 );283284 self.save()285 }286287 /// Confirm sponsorship288 ///289 /// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.290 /// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].291 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> DispatchResult {292 self.check_is_internal()?;293 ensure!(294 self.collection.sponsorship.pending_sponsor() == Some(sender),295 Error::<T>::ConfirmSponsorshipFail296 );297298 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());299300 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sender.clone()));301 <PalletEvm<T>>::deposit_log(302 erc::CollectionHelpersEvents::CollectionChanged {303 collection_id: eth::collection_id_to_address(self.id),304 }305 .to_log(T::ContractAddress::get()),306 );307308 self.save()309 }310311 /// Remove collection sponsor.312 pub fn remove_sponsor(&mut self, sender: &T::CrossAccountId) -> DispatchResult {313 self.check_is_internal()?;314 self.check_is_owner_or_admin(sender)?;315316 self.collection.sponsorship = SponsorshipState::Disabled;317318 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));319 <PalletEvm<T>>::deposit_log(320 erc::CollectionHelpersEvents::CollectionChanged {321 collection_id: eth::collection_id_to_address(self.id),322 }323 .to_log(T::ContractAddress::get()),324 );325 self.save()326 }327328 /// Force remove `sponsor`.329 ///330 /// Differs from `remove_sponsor` in that331 /// it doesn't require consent from the `owner` of the collection.332 pub fn force_remove_sponsor(&mut self) -> DispatchResult {333 self.check_is_internal()?;334335 self.collection.sponsorship = SponsorshipState::Disabled;336337 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));338 <PalletEvm<T>>::deposit_log(339 erc::CollectionHelpersEvents::CollectionChanged {340 collection_id: eth::collection_id_to_address(self.id),341 }342 .to_log(T::ContractAddress::get()),343 );344 self.save()345 }346347 /// Checks that the collection was created with, and must be operated upon through **Unique API**.348 /// Now check only the `external` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.349 pub fn check_is_internal(&self) -> DispatchResult {350 if self.flags.external {351 return Err(<Error<T>>::CollectionIsExternal)?;352 }353354 Ok(())355 }356357 /// Checks that the collection was created with, and must be operated upon through an **assimilated API**.358 /// Now check only the `external` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.359 pub fn check_is_external(&self) -> DispatchResult {360 if !self.flags.external {361 return Err(<Error<T>>::CollectionIsInternal)?;362 }363364 Ok(())365 }366}367368impl<T: Config> Deref for CollectionHandle<T> {369 type Target = Collection<T::AccountId>;370371 fn deref(&self) -> &Self::Target {372 &self.collection373 }374}375376impl<T: Config> DerefMut for CollectionHandle<T> {377 fn deref_mut(&mut self) -> &mut Self::Target {378 &mut self.collection379 }380}381382impl<T: Config> CollectionHandle<T> {383 /// Checks if the `user` is the owner of the collection.384 pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {385 ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);386 Ok(())387 }388389 /// Returns **true** if the `user` is the owner or administrator of the collection.390 pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {391 *user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))392 }393394 /// Checks if the `user` is the owner or administrator of the collection.395 pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {396 ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);397 Ok(())398 }399400 /// Returns **true** if401 /// * the `user`is a collection owner or admin402 /// * the collection limits allow the owner/admins to transfer/burn any collection token403 pub fn ignores_token_restrictions(&self, user: &T::CrossAccountId) -> bool {404 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)405 }406407 /// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.408 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {409 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)410 }411412 /// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.413 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {414 ensure!(415 <Allowlist<T>>::get((self.id, user)),416 <Error<T>>::AddressNotInAllowlist417 );418 Ok(())419 }420421 /// Changes collection owner to another account422 /// #### Store read/writes423 /// 1 writes424 pub fn change_owner(425 &mut self,426 caller: T::CrossAccountId,427 new_owner: T::CrossAccountId,428 ) -> DispatchResult {429 self.check_is_internal()?;430 self.check_is_owner(&caller)?;431 self.collection.owner = new_owner.as_sub().clone();432433 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnerChanged(434 self.id,435 new_owner.as_sub().clone(),436 ));437 <PalletEvm<T>>::deposit_log(438 erc::CollectionHelpersEvents::CollectionChanged {439 collection_id: eth::collection_id_to_address(self.id),440 }441 .to_log(T::ContractAddress::get()),442 );443444 self.save()445 }446}447448#[frame_support::pallet]449pub mod pallet {450 use super::*;451 use dispatch::CollectionDispatch;452 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};453 use frame_system::pallet_prelude::*;454 use frame_support::traits::Currency;455 use up_data_structs::{TokenId, mapping::TokenAddressMapping};456 use scale_info::TypeInfo;457 use weights::WeightInfo;458459 #[pallet::config]460 pub trait Config:461 frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config + TypeInfo462 {463 /// Weight information for functions of this pallet.464 type WeightInfo: WeightInfo;465466 /// Events compatible with [`frame_system::Config::Event`].467 type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;468469 /// Handler of accounts and payment.470 type Currency: Currency<Self::AccountId>;471472 /// Set price to create a collection.473 #[pallet::constant]474 type CollectionCreationPrice: Get<475 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,476 >;477478 /// Dispatcher of operations on collections.479 type CollectionDispatch: CollectionDispatch<Self>;480481 /// Account which holds the chain's treasury.482 type TreasuryAccountId: Get<Self::AccountId>;483484 /// Address under which the CollectionHelper contract would be available.485 #[pallet::constant]486 type ContractAddress: Get<H160>;487488 /// Mapper for token addresses to Ethereum addresses.489 type EvmTokenAddressMapping: TokenAddressMapping<H160>;490491 /// Mapper for token addresses to [`CrossAccountId`].492 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;493 }494495 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);496497 #[pallet::pallet]498 #[pallet::storage_version(STORAGE_VERSION)]499 #[pallet::generate_store(pub(super) trait Store)]500 pub struct Pallet<T>(_);501502 #[pallet::extra_constants]503 impl<T: Config> Pallet<T> {504 /// Maximum admins per collection.505 pub fn collection_admins_limit() -> u32 {506 COLLECTION_ADMINS_LIMIT507 }508 }509510 impl<T: Config> Pallet<T> {511 /// Helper function that handles deposit events512 pub fn deposit_event(event: Event<T>) {513 let event = <T as Config>::RuntimeEvent::from(event);514 let event = event.into();515 <frame_system::Pallet<T>>::deposit_event(event)516 }517 }518519 #[pallet::event]520 pub enum Event<T: Config> {521 /// New collection was created522 CollectionCreated(523 /// Globally unique identifier of newly created collection.524 CollectionId,525 /// [`CollectionMode`] converted into _u8_.526 u8,527 /// Collection owner.528 T::AccountId,529 ),530531 /// New collection was destroyed532 CollectionDestroyed(533 /// Globally unique identifier of collection.534 CollectionId,535 ),536537 /// New item was created.538 ItemCreated(539 /// Id of the collection where item was created.540 CollectionId,541 /// Id of an item. Unique within the collection.542 TokenId,543 /// Owner of newly created item544 T::CrossAccountId,545 /// Always 1 for NFT546 u128,547 ),548549 /// Collection item was burned.550 ItemDestroyed(551 /// Id of the collection where item was destroyed.552 CollectionId,553 /// Identifier of burned NFT.554 TokenId,555 /// Which user has destroyed its tokens.556 T::CrossAccountId,557 /// Amount of token pieces destroed. Always 1 for NFT.558 u128,559 ),560561 /// Item was transferred562 Transfer(563 /// Id of collection to which item is belong.564 CollectionId,565 /// Id of an item.566 TokenId,567 /// Original owner of item.568 T::CrossAccountId,569 /// New owner of item.570 T::CrossAccountId,571 /// Amount of token pieces transfered. Always 1 for NFT.572 u128,573 ),574575 /// Amount pieces of token owned by `sender` was approved for `spender`.576 Approved(577 /// Id of collection to which item is belong.578 CollectionId,579 /// Id of an item.580 TokenId,581 /// Original owner of item.582 T::CrossAccountId,583 /// Id for which the approval was granted.584 T::CrossAccountId,585 /// Amount of token pieces transfered. Always 1 for NFT.586 u128,587 ),588589 /// A `sender` approves operations on all owned tokens for `spender`.590 ApprovedForAll(591 /// Id of collection to which item is belong.592 CollectionId,593 /// Owner of a wallet.594 T::CrossAccountId,595 /// Id for which operator status was granted or rewoked.596 T::CrossAccountId,597 /// Is operator status granted or revoked?598 bool,599 ),600601 /// The colletion property has been added or edited.602 CollectionPropertySet(603 /// Id of collection to which property has been set.604 CollectionId,605 /// The property that was set.606 PropertyKey,607 ),608609 /// The property has been deleted.610 CollectionPropertyDeleted(611 /// Id of collection to which property has been deleted.612 CollectionId,613 /// The property that was deleted.614 PropertyKey,615 ),616617 /// The token property has been added or edited.618 TokenPropertySet(619 /// Identifier of the collection whose token has the property set.620 CollectionId,621 /// The token for which the property was set.622 TokenId,623 /// The property that was set.624 PropertyKey,625 ),626627 /// The token property has been deleted.628 TokenPropertyDeleted(629 /// Identifier of the collection whose token has the property deleted.630 CollectionId,631 /// The token for which the property was deleted.632 TokenId,633 /// The property that was deleted.634 PropertyKey,635 ),636637 /// The token property permission of a collection has been set.638 PropertyPermissionSet(639 /// ID of collection to which property permission has been set.640 CollectionId,641 /// The property permission that was set.642 PropertyKey,643 ),644645 /// Address was added to the allow list.646 AllowListAddressAdded(647 /// ID of the affected collection.648 CollectionId,649 /// Address of the added account.650 T::CrossAccountId,651 ),652653 /// Address was removed from the allow list.654 AllowListAddressRemoved(655 /// ID of the affected collection.656 CollectionId,657 /// Address of the removed account.658 T::CrossAccountId,659 ),660661 /// Collection admin was added.662 CollectionAdminAdded(663 /// ID of the affected collection.664 CollectionId,665 /// Admin address.666 T::CrossAccountId,667 ),668669 /// Collection admin was removed.670 CollectionAdminRemoved(671 /// ID of the affected collection.672 CollectionId,673 /// Removed admin address.674 T::CrossAccountId,675 ),676677 /// Collection limits were set.678 CollectionLimitSet(679 /// ID of the affected collection.680 CollectionId,681 ),682683 /// Collection owned was changed.684 CollectionOwnerChanged(685 /// ID of the affected collection.686 CollectionId,687 /// New owner address.688 T::AccountId,689 ),690691 /// Collection permissions were set.692 CollectionPermissionSet(693 /// ID of the affected collection.694 CollectionId,695 ),696697 /// Collection sponsor was set.698 CollectionSponsorSet(699 /// ID of the affected collection.700 CollectionId,701 /// New sponsor address.702 T::AccountId,703 ),704705 /// New sponsor was confirm.706 SponsorshipConfirmed(707 /// ID of the affected collection.708 CollectionId,709 /// New sponsor address.710 T::AccountId,711 ),712713 /// Collection sponsor was removed.714 CollectionSponsorRemoved(715 /// ID of the affected collection.716 CollectionId,717 ),718 }719720 #[pallet::error]721 pub enum Error<T> {722 /// This collection does not exist.723 CollectionNotFound,724 /// Sender parameter and item owner must be equal.725 MustBeTokenOwner,726 /// No permission to perform action727 NoPermission,728 /// Destroying only empty collections is allowed729 CantDestroyNotEmptyCollection,730 /// Collection is not in mint mode.731 PublicMintingNotAllowed,732 /// Address is not in allow list.733 AddressNotInAllowlist,734735 /// Collection name can not be longer than 63 char.736 CollectionNameLimitExceeded,737 /// Collection description can not be longer than 255 char.738 CollectionDescriptionLimitExceeded,739 /// Token prefix can not be longer than 15 char.740 CollectionTokenPrefixLimitExceeded,741 /// Total collections bound exceeded.742 TotalCollectionsLimitExceeded,743 /// Exceeded max admin count744 CollectionAdminCountExceeded,745 /// Collection limit bounds per collection exceeded746 CollectionLimitBoundsExceeded,747 /// Tried to enable permissions which are only permitted to be disabled748 OwnerPermissionsCantBeReverted,749 /// Collection settings not allowing items transferring750 TransferNotAllowed,751 /// Account token limit exceeded per collection752 AccountTokenLimitExceeded,753 /// Collection token limit exceeded754 CollectionTokenLimitExceeded,755 /// Metadata flag frozen756 MetadataFlagFrozen,757758 /// Item does not exist759 TokenNotFound,760 /// Item is balance not enough761 TokenValueTooLow,762 /// Requested value is more than the approved763 ApprovedValueTooLow,764 /// Tried to approve more than owned765 CantApproveMoreThanOwned,766 /// Only spending from eth mirror could be approved767 AddressIsNotEthMirror,768769 /// Can't transfer tokens to ethereum zero address770 AddressIsZero,771772 /// The operation is not supported773 UnsupportedOperation,774775 /// Insufficient funds to perform an action776 NotSufficientFounds,777778 /// User does not satisfy the nesting rule779 UserIsNotAllowedToNest,780 /// Only tokens from specific collections may nest tokens under this one781 SourceCollectionIsNotAllowedToNest,782783 /// Tried to store more data than allowed in collection field784 CollectionFieldSizeExceeded,785786 /// Tried to store more property data than allowed787 NoSpaceForProperty,788789 /// Tried to store more property keys than allowed790 PropertyLimitReached,791792 /// Property key is too long793 PropertyKeyIsTooLong,794795 /// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed796 InvalidCharacterInPropertyKey,797798 /// Empty property keys are forbidden799 EmptyPropertyKey,800801 /// Tried to access an external collection with an internal API802 CollectionIsExternal,803804 /// Tried to access an internal collection with an external API805 CollectionIsInternal,806807 /// This address is not set as sponsor, use setCollectionSponsor first.808 ConfirmSponsorshipFail,809810 /// The user is not an administrator.811 UserIsNotCollectionAdmin,812 }813814 /// Storage of the count of created collections. Essentially contains the last collection ID.815 #[pallet::storage]816 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;817818 /// Storage of the count of deleted collections.819 #[pallet::storage]820 pub type DestroyedCollectionCount<T> =821 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;822823 /// Storage of collection info.824 #[pallet::storage]825 pub type CollectionById<T> = StorageMap<826 Hasher = Blake2_128Concat,827 Key = CollectionId,828 Value = Collection<<T as frame_system::Config>::AccountId>,829 QueryKind = OptionQuery,830 >;831832 /// Storage of collection properties.833 #[pallet::storage]834 #[pallet::getter(fn collection_properties)]835 pub type CollectionProperties<T> = StorageMap<836 Hasher = Blake2_128Concat,837 Key = CollectionId,838 Value = Properties,839 QueryKind = ValueQuery,840 OnEmpty = up_data_structs::CollectionProperties,841 >;842843 /// Storage of token property permissions of a collection.844 #[pallet::storage]845 #[pallet::getter(fn property_permissions)]846 pub type CollectionPropertyPermissions<T> = StorageMap<847 Hasher = Blake2_128Concat,848 Key = CollectionId,849 Value = PropertiesPermissionMap,850 QueryKind = ValueQuery,851 >;852853 /// Storage of the amount of collection admins.854 #[pallet::storage]855 pub type AdminAmount<T> = StorageMap<856 Hasher = Blake2_128Concat,857 Key = CollectionId,858 Value = u32,859 QueryKind = ValueQuery,860 >;861862 /// List of collection admins.863 #[pallet::storage]864 pub type IsAdmin<T: Config> = StorageNMap<865 Key = (866 Key<Blake2_128Concat, CollectionId>,867 Key<Blake2_128Concat, T::CrossAccountId>,868 ),869 Value = bool,870 QueryKind = ValueQuery,871 >;872873 /// Allowlisted collection users.874 #[pallet::storage]875 pub type Allowlist<T: Config> = StorageNMap<876 Key = (877 Key<Blake2_128Concat, CollectionId>,878 Key<Blake2_128Concat, T::CrossAccountId>,879 ),880 Value = bool,881 QueryKind = ValueQuery,882 >;883884 /// Not used by code, exists only to provide some types to metadata.885 #[pallet::storage]886 pub type DummyStorageValue<T: Config> = StorageValue<887 Value = (888 CollectionStats,889 CollectionId,890 TokenId,891 TokenChild,892 PhantomType<(893 TokenData<T::CrossAccountId>,894 RpcCollection<T::AccountId>,895 // RMRK896 RmrkCollectionInfo<T::AccountId>,897 RmrkInstanceInfo<T::AccountId>,898 RmrkResourceInfo,899 RmrkPropertyInfo,900 RmrkBaseInfo<T::AccountId>,901 RmrkPartType,902 RmrkBoundedTheme,903 RmrkNftChild,904 // PoV Estimate Info905 PovInfo,906 )>,907 ),908 QueryKind = OptionQuery,909 >;910911 #[pallet::hooks]912 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {913 fn on_runtime_upgrade() -> Weight {914 StorageVersion::new(1).put::<Pallet<T>>();915916 Weight::zero()917 }918 }919}920921impl<T: Config> Pallet<T> {922 /// Enshure that receiver address is correct.923 ///924 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.925 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {926 ensure!(927 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,928 <Error<T>>::AddressIsZero929 );930 Ok(())931 }932933 /// Get a vector of collection admins.934 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {935 <IsAdmin<T>>::iter_prefix((collection,))936 .map(|(a, _)| a)937 .collect()938 }939940 /// Get a vector of users allowed to mint tokens.941 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {942 <Allowlist<T>>::iter_prefix((collection,))943 .map(|(a, _)| a)944 .collect()945 }946947 /// Is `user` allowed to mint token in `collection`.948 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {949 <Allowlist<T>>::get((collection, user))950 }951952 /// Get statistics of collections.953 pub fn collection_stats() -> CollectionStats {954 let created = <CreatedCollectionCount<T>>::get();955 let destroyed = <DestroyedCollectionCount<T>>::get();956 CollectionStats {957 created: created.0,958 destroyed: destroyed.0,959 alive: created.0 - destroyed.0,960 }961 }962963 /// Get the effective limits for the collection.964 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {965 let collection = <CollectionById<T>>::get(collection)?;966 let limits = collection.limits;967 let effective_limits = CollectionLimits {968 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),969 sponsored_data_size: Some(limits.sponsored_data_size()),970 sponsored_data_rate_limit: Some(971 limits972 .sponsored_data_rate_limit973 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),974 ),975 token_limit: Some(limits.token_limit()),976 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(977 match collection.mode {978 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,979 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,980 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,981 },982 )),983 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),984 owner_can_transfer: Some(limits.owner_can_transfer()),985 owner_can_destroy: Some(limits.owner_can_destroy()),986 transfers_enabled: Some(limits.transfers_enabled()),987 };988989 Some(effective_limits)990 }991992 /// Returns information about the `collection` adapted for rpc.993 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {994 let Collection {995 name,996 description,997 owner,998 mode,999 token_prefix,1000 sponsorship,1001 limits,1002 permissions,1003 flags,1004 } = <CollectionById<T>>::get(collection)?;10051006 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)1007 .into_iter()1008 .map(|(key, permission)| PropertyKeyPermission { key, permission })1009 .collect();10101011 let properties = <CollectionProperties<T>>::get(collection)1012 .into_iter()1013 .map(|(key, value)| Property { key, value })1014 .collect();10151016 let permissions = CollectionPermissions {1017 access: Some(permissions.access()),1018 mint_mode: Some(permissions.mint_mode()),1019 nesting: Some(permissions.nesting().clone()),1020 };10211022 Some(RpcCollection {1023 name: name.into_inner(),1024 description: description.into_inner(),1025 owner,1026 mode,1027 token_prefix: token_prefix.into_inner(),1028 sponsorship,1029 limits,1030 permissions,1031 token_property_permissions,1032 properties,1033 read_only: flags.external,10341035 flags: RpcCollectionFlags {1036 foreign: flags.foreign,1037 erc721metadata: flags.erc721metadata,1038 },1039 })1040 }1041}10421043macro_rules! limit_default {1044 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1045 $(1046 if let Some($new) = $new.$field {1047 let $old = $old.$field($($arg)?);1048 let _ = $new;1049 let _ = $old;1050 $check1051 } else {1052 $new.$field = $old.$field1053 }1054 )*1055 }};1056}1057macro_rules! limit_default_clone {1058 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1059 $(1060 if let Some($new) = $new.$field.clone() {1061 let $old = $old.$field($($arg)?);1062 let _ = $new;1063 let _ = $old;1064 $check1065 } else {1066 $new.$field = $old.$field.clone()1067 }1068 )*1069 }};1070}10711072impl<T: Config> Pallet<T> {1073 /// Create new collection.1074 ///1075 /// * `owner` - The owner of the collection.1076 /// * `data` - Description of the created collection.1077 /// * `flags` - Extra flags to store.1078 pub fn init_collection(1079 owner: T::CrossAccountId,1080 payer: T::CrossAccountId,1081 data: CreateCollectionData<T::AccountId>,1082 flags: CollectionFlags,1083 ) -> Result<CollectionId, DispatchError> {1084 {1085 ensure!(1086 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,1087 Error::<T>::CollectionTokenPrefixLimitExceeded1088 );1089 }10901091 let created_count = <CreatedCollectionCount<T>>::get()1092 .01093 .checked_add(1)1094 .ok_or(ArithmeticError::Overflow)?;1095 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;1096 let id = CollectionId(created_count);10971098 // bound Total number of collections1099 ensure!(1100 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,1101 <Error<T>>::TotalCollectionsLimitExceeded1102 );11031104 // =========11051106 let collection = Collection {1107 owner: owner.as_sub().clone(),1108 name: data.name,1109 mode: data.mode.clone(),1110 description: data.description,1111 token_prefix: data.token_prefix,1112 sponsorship: data1113 .pending_sponsor1114 .map(SponsorshipState::Unconfirmed)1115 .unwrap_or_default(),1116 limits: data1117 .limits1118 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))1119 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,1120 permissions: data1121 .permissions1122 .map(|permissions| {1123 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)1124 })1125 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,1126 flags,1127 };11281129 let mut collection_properties = up_data_structs::CollectionProperties::get();1130 collection_properties1131 .try_set_from_iter(data.properties.into_iter())1132 .map_err(<Error<T>>::from)?;11331134 CollectionProperties::<T>::insert(id, collection_properties);11351136 let mut token_props_permissions = PropertiesPermissionMap::new();1137 token_props_permissions1138 .try_set_from_iter(data.token_property_permissions.into_iter())1139 .map_err(<Error<T>>::from)?;11401141 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);11421143 // Take a (non-refundable) deposit of collection creation1144 {1145 let mut imbalance =1146 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();1147 imbalance.subsume(1148 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(1149 &T::TreasuryAccountId::get(),1150 T::CollectionCreationPrice::get(),1151 ),1152 );1153 <T as Config>::Currency::settle(1154 payer.as_sub(),1155 imbalance,1156 WithdrawReasons::TRANSFER,1157 ExistenceRequirement::KeepAlive,1158 )1159 .map_err(|_| Error::<T>::NotSufficientFounds)?;1160 }11611162 <CreatedCollectionCount<T>>::put(created_count);1163 <Pallet<T>>::deposit_event(Event::CollectionCreated(1164 id,1165 data.mode.id(),1166 owner.as_sub().clone(),1167 ));1168 <PalletEvm<T>>::deposit_log(1169 erc::CollectionHelpersEvents::CollectionCreated {1170 owner: *owner.as_eth(),1171 collection_id: eth::collection_id_to_address(id),1172 }1173 .to_log(T::ContractAddress::get()),1174 );1175 <CollectionById<T>>::insert(id, collection);1176 Ok(id)1177 }11781179 /// Destroy collection.1180 ///1181 /// * `collection` - Collection handler.1182 /// * `sender` - The owner or administrator of the collection.1183 pub fn destroy_collection(1184 collection: CollectionHandle<T>,1185 sender: &T::CrossAccountId,1186 ) -> DispatchResult {1187 ensure!(1188 collection.limits.owner_can_destroy(),1189 <Error<T>>::NoPermission,1190 );1191 collection.check_is_owner(sender)?;11921193 let destroyed_collections = <DestroyedCollectionCount<T>>::get()1194 .01195 .checked_add(1)1196 .ok_or(ArithmeticError::Overflow)?;11971198 // =========11991200 <DestroyedCollectionCount<T>>::put(destroyed_collections);1201 <CollectionById<T>>::remove(collection.id);1202 <AdminAmount<T>>::remove(collection.id);1203 let _ = <IsAdmin<T>>::clear_prefix((collection.id,), u32::MAX, None);1204 let _ = <Allowlist<T>>::clear_prefix((collection.id,), u32::MAX, None);1205 <CollectionProperties<T>>::remove(collection.id);12061207 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));12081209 <PalletEvm<T>>::deposit_log(1210 erc::CollectionHelpersEvents::CollectionDestroyed {1211 collection_id: eth::collection_id_to_address(collection.id),1212 }1213 .to_log(T::ContractAddress::get()),1214 );1215 Ok(())1216 }12171218 /// This function sets or removes a collection properties according to1219 /// `properties_updates` contents:1220 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1221 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.1222 ///1223 /// This function fires an event for each property change.1224 /// In case of an error, all the changes (including the events) will be reverted1225 /// since the function is transactional.1226 #[transactional]1227 fn modify_collection_properties(1228 collection: &CollectionHandle<T>,1229 sender: &T::CrossAccountId,1230 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1231 ) -> DispatchResult {1232 collection.check_is_owner_or_admin(sender)?;12331234 let mut stored_properties = <CollectionProperties<T>>::get(collection.id);12351236 for (key, value) in properties_updates {1237 match value {1238 Some(value) => {1239 stored_properties1240 .try_set(key.clone(), value)1241 .map_err(<Error<T>>::from)?;12421243 Self::deposit_event(Event::CollectionPropertySet(collection.id, key));1244 <PalletEvm<T>>::deposit_log(1245 erc::CollectionHelpersEvents::CollectionChanged {1246 collection_id: eth::collection_id_to_address(collection.id),1247 }1248 .to_log(T::ContractAddress::get()),1249 );1250 }1251 None => {1252 stored_properties.remove(&key).map_err(<Error<T>>::from)?;12531254 Self::deposit_event(Event::CollectionPropertyDeleted(collection.id, key));1255 <PalletEvm<T>>::deposit_log(1256 erc::CollectionHelpersEvents::CollectionChanged {1257 collection_id: eth::collection_id_to_address(collection.id),1258 }1259 .to_log(T::ContractAddress::get()),1260 );1261 }1262 }1263 }12641265 <CollectionProperties<T>>::set(collection.id, stored_properties);12661267 Ok(())1268 }12691270 /// A batch operation to add, edit or remove properties for a token.1271 /// It sets or removes a token's properties according to1272 /// `properties_updates` contents:1273 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1274 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.1275 ///1276 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.1277 /// - `is_token_create`: Indicates that method is called during token initialization.1278 /// Allows to bypass ownership check.1279 ///1280 /// All affected properties should have `mutable` permission1281 /// to be **deleted** or to be **set more than once**,1282 /// and the sender should have permission to edit those properties.1283 ///1284 /// This function fires an event for each property change.1285 /// In case of an error, all the changes (including the events) will be reverted1286 /// since the function is transactional.1287 pub fn modify_token_properties(1288 collection: &CollectionHandle<T>,1289 sender: &T::CrossAccountId,1290 token_id: TokenId,1291 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1292 is_token_create: bool,1293 mut stored_properties: Properties,1294 is_token_owner: impl Fn() -> Result<bool, DispatchError>,1295 set_token_properties: impl FnOnce(Properties),1296 ) -> DispatchResult {1297 let is_collection_admin = collection.is_owner_or_admin(sender);1298 let permissions = Self::property_permissions(collection.id);12991300 let mut token_owner_result = None;1301 let mut is_token_owner = || -> Result<bool, DispatchError> {1302 *token_owner_result.get_or_insert_with(&is_token_owner)1303 };13041305 for (key, value) in properties_updates {1306 let permission = permissions1307 .get(&key)1308 .cloned()1309 .unwrap_or_else(PropertyPermission::none);13101311 let is_property_exists = stored_properties.get(&key).is_some();13121313 match permission {1314 PropertyPermission { mutable: false, .. } if is_property_exists => {1315 return Err(<Error<T>>::NoPermission.into());1316 }13171318 PropertyPermission {1319 collection_admin,1320 token_owner,1321 ..1322 } => {1323 //TODO: investigate threats during public minting.1324 let is_token_create =1325 is_token_create && (collection_admin || token_owner) && value.is_some();1326 if !(is_token_create1327 || (collection_admin && is_collection_admin)1328 || (token_owner && is_token_owner()?))1329 {1330 fail!(<Error<T>>::NoPermission);1331 }1332 }1333 }13341335 match value {1336 Some(value) => {1337 stored_properties1338 .try_set(key.clone(), value)1339 .map_err(<Error<T>>::from)?;13401341 Self::deposit_event(Event::TokenPropertySet(collection.id, token_id, key));1342 }1343 None => {1344 stored_properties.remove(&key).map_err(<Error<T>>::from)?;13451346 Self::deposit_event(Event::TokenPropertyDeleted(collection.id, token_id, key));1347 }1348 }13491350 <PalletEvm<T>>::deposit_log(1351 CollectionHelpersEvents::TokenChanged {1352 collection_id: eth::collection_id_to_address(collection.id),1353 token_id: token_id.into(),1354 }1355 .to_log(T::ContractAddress::get()),1356 );1357 }13581359 set_token_properties(stored_properties);13601361 Ok(())1362 }13631364 /// Sets or unsets the approval of a given operator.1365 ///1366 /// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.1367 /// - `owner`: Token owner1368 /// - `operator`: Operator1369 /// - `approve`: Should operator status be granted or revoked?1370 pub fn set_allowance_for_all(1371 collection: &CollectionHandle<T>,1372 owner: &T::CrossAccountId,1373 operator: &T::CrossAccountId,1374 approve: bool,1375 set_allowance: impl FnOnce(),1376 log: evm_coder::ethereum::Log,1377 ) -> DispatchResult {1378 if collection.permissions.access() == AccessMode::AllowList {1379 collection.check_allowlist(owner)?;1380 collection.check_allowlist(operator)?;1381 }13821383 Self::ensure_correct_receiver(operator)?;13841385 set_allowance();13861387 <PalletEvm<T>>::deposit_log(log);1388 Self::deposit_event(Event::ApprovedForAll(1389 collection.id,1390 owner.clone(),1391 operator.clone(),1392 approve,1393 ));1394 Ok(())1395 }13961397 /// Set collection property.1398 ///1399 /// * `collection` - Collection handler.1400 /// * `sender` - The owner or administrator of the collection.1401 /// * `property` - The property to set.1402 pub fn set_collection_property(1403 collection: &CollectionHandle<T>,1404 sender: &T::CrossAccountId,1405 property: Property,1406 ) -> DispatchResult {1407 Self::set_collection_properties(collection, sender, [property].into_iter())1408 }14091410 /// Set a scoped collection property, where the scope is a special prefix1411 /// prohibiting a user access to change the property directly.1412 ///1413 /// * `collection_id` - ID of the collection for which the property is being set.1414 /// * `scope` - Property scope.1415 /// * `property` - The property to set.1416 pub fn set_scoped_collection_property(1417 collection_id: CollectionId,1418 scope: PropertyScope,1419 property: Property,1420 ) -> DispatchResult {1421 CollectionProperties::<T>::try_mutate(collection_id, |properties| {1422 properties.try_scoped_set(scope, property.key, property.value)1423 })1424 .map_err(<Error<T>>::from)?;14251426 Ok(())1427 }14281429 /// Set scoped collection properties, where the scope is a special prefix1430 /// prohibiting a user access to change the properties directly.1431 ///1432 /// * `collection_id` - ID of the collection for which the properties is being set.1433 /// * `scope` - Property scope.1434 /// * `properties` - The properties to set.1435 pub fn set_scoped_collection_properties(1436 collection_id: CollectionId,1437 scope: PropertyScope,1438 properties: impl Iterator<Item = Property>,1439 ) -> DispatchResult {1440 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1441 stored_properties.try_scoped_set_from_iter(scope, properties)1442 })1443 .map_err(<Error<T>>::from)?;14441445 Ok(())1446 }14471448 /// Set collection properties.1449 ///1450 /// * `collection` - Collection handler.1451 /// * `sender` - The owner or administrator of the collection.1452 /// * `properties` - The properties to set.1453 pub fn set_collection_properties(1454 collection: &CollectionHandle<T>,1455 sender: &T::CrossAccountId,1456 properties: impl Iterator<Item = Property>,1457 ) -> DispatchResult {1458 Self::modify_collection_properties(1459 collection,1460 sender,1461 properties.map(|property| (property.key, Some(property.value))),1462 )1463 }14641465 /// Delete collection property.1466 ///1467 /// * `collection` - Collection handler.1468 /// * `sender` - The owner or administrator of the collection.1469 /// * `property` - The property to delete.1470 pub fn delete_collection_property(1471 collection: &CollectionHandle<T>,1472 sender: &T::CrossAccountId,1473 property_key: PropertyKey,1474 ) -> DispatchResult {1475 Self::delete_collection_properties(collection, sender, [property_key].into_iter())1476 }14771478 /// Delete collection properties.1479 ///1480 /// * `collection` - Collection handler.1481 /// * `sender` - The owner or administrator of the collection.1482 /// * `properties` - The properties to delete.1483 pub fn delete_collection_properties(1484 collection: &CollectionHandle<T>,1485 sender: &T::CrossAccountId,1486 property_keys: impl Iterator<Item = PropertyKey>,1487 ) -> DispatchResult {1488 Self::modify_collection_properties(collection, sender, property_keys.map(|key| (key, None)))1489 }14901491 /// Set collection propetry permission without any checks.1492 ///1493 /// Used for migrations.1494 ///1495 /// * `collection` - Collection handler.1496 /// * `property_permissions` - Property permissions.1497 pub fn set_property_permission_unchecked(1498 collection: CollectionId,1499 property_permission: PropertyKeyPermission,1500 ) -> DispatchResult {1501 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1502 permissions.try_set(property_permission.key, property_permission.permission)1503 })1504 .map_err(<Error<T>>::from)?;1505 Ok(())1506 }15071508 /// Set collection property permission.1509 ///1510 /// * `collection` - Collection handler.1511 /// * `sender` - The owner or administrator of the collection.1512 /// * `property_permission` - Property permission.1513 pub fn set_property_permission(1514 collection: &CollectionHandle<T>,1515 sender: &T::CrossAccountId,1516 property_permission: PropertyKeyPermission,1517 ) -> DispatchResult {1518 Self::set_scoped_property_permission(1519 collection,1520 sender,1521 PropertyScope::None,1522 property_permission,1523 )1524 }15251526 /// Set collection property permission with scope.1527 ///1528 /// * `collection` - Collection handler.1529 /// * `sender` - The owner or administrator of the collection.1530 /// * `scope` - Property scope.1531 /// * `property_permission` - Property permission.1532 pub fn set_scoped_property_permission(1533 collection: &CollectionHandle<T>,1534 sender: &T::CrossAccountId,1535 scope: PropertyScope,1536 property_permission: PropertyKeyPermission,1537 ) -> DispatchResult {1538 collection.check_is_owner_or_admin(sender)?;15391540 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1541 let current_permission = all_permissions.get(&property_permission.key);1542 if matches![1543 current_permission,1544 Some(PropertyPermission { mutable: false, .. })1545 ] {1546 return Err(<Error<T>>::NoPermission.into());1547 }15481549 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1550 let property_permission = property_permission.clone();1551 permissions.try_scoped_set(1552 scope,1553 property_permission.key,1554 property_permission.permission,1555 )1556 })1557 .map_err(<Error<T>>::from)?;15581559 Self::deposit_event(Event::PropertyPermissionSet(1560 collection.id,1561 property_permission.key,1562 ));1563 <PalletEvm<T>>::deposit_log(1564 erc::CollectionHelpersEvents::CollectionChanged {1565 collection_id: eth::collection_id_to_address(collection.id),1566 }1567 .to_log(T::ContractAddress::get()),1568 );15691570 Ok(())1571 }15721573 /// Set token property permission.1574 ///1575 /// * `collection` - Collection handler.1576 /// * `sender` - The owner or administrator of the collection.1577 /// * `property_permissions` - Property permissions.1578 #[transactional]1579 pub fn set_token_property_permissions(1580 collection: &CollectionHandle<T>,1581 sender: &T::CrossAccountId,1582 property_permissions: Vec<PropertyKeyPermission>,1583 ) -> DispatchResult {1584 Self::set_scoped_token_property_permissions(1585 collection,1586 sender,1587 PropertyScope::None,1588 property_permissions,1589 )1590 }15911592 /// Set token property permission with scope.1593 ///1594 /// * `collection` - Collection handler.1595 /// * `sender` - The owner or administrator of the collection.1596 /// * `scope` - Property scope.1597 /// * `property_permissions` - Property permissions.1598 #[transactional]1599 pub fn set_scoped_token_property_permissions(1600 collection: &CollectionHandle<T>,1601 sender: &T::CrossAccountId,1602 scope: PropertyScope,1603 property_permissions: Vec<PropertyKeyPermission>,1604 ) -> DispatchResult {1605 for prop_pemission in property_permissions {1606 Self::set_scoped_property_permission(collection, sender, scope, prop_pemission)?;1607 }16081609 Ok(())1610 }16111612 /// Get collection property.1613 pub fn get_collection_property(1614 collection_id: CollectionId,1615 key: &PropertyKey,1616 ) -> Option<PropertyValue> {1617 Self::collection_properties(collection_id).get(key).cloned()1618 }16191620 /// Convert byte vector to property key vector.1621 pub fn bytes_keys_to_property_keys(1622 keys: Vec<Vec<u8>>,1623 ) -> Result<Vec<PropertyKey>, DispatchError> {1624 keys.into_iter()1625 .map(|key| -> Result<PropertyKey, DispatchError> {1626 key.try_into()1627 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1628 })1629 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1630 }16311632 /// Get properties according to given keys.1633 pub fn filter_collection_properties(1634 collection_id: CollectionId,1635 keys: Option<Vec<PropertyKey>>,1636 ) -> Result<Vec<Property>, DispatchError> {1637 let properties = Self::collection_properties(collection_id);16381639 let properties = keys1640 .map(|keys| {1641 keys.into_iter()1642 .filter_map(|key| {1643 properties.get(&key).map(|value| Property {1644 key,1645 value: value.clone(),1646 })1647 })1648 .collect()1649 })1650 .unwrap_or_else(|| {1651 properties1652 .into_iter()1653 .map(|(key, value)| Property { key, value })1654 .collect()1655 });16561657 Ok(properties)1658 }16591660 /// Get property permissions according to given keys.1661 pub fn filter_property_permissions(1662 collection_id: CollectionId,1663 keys: Option<Vec<PropertyKey>>,1664 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1665 let permissions = Self::property_permissions(collection_id);16661667 let key_permissions = keys1668 .map(|keys| {1669 keys.into_iter()1670 .filter_map(|key| {1671 permissions1672 .get(&key)1673 .map(|permission| PropertyKeyPermission {1674 key,1675 permission: permission.clone(),1676 })1677 })1678 .collect()1679 })1680 .unwrap_or_else(|| {1681 permissions1682 .into_iter()1683 .map(|(key, permission)| PropertyKeyPermission { key, permission })1684 .collect()1685 });16861687 Ok(key_permissions)1688 }16891690 /// Toggle `user` participation in the `collection`'s allow list.1691 /// #### Store read/writes1692 /// 1 writes1693 pub fn toggle_allowlist(1694 collection: &CollectionHandle<T>,1695 sender: &T::CrossAccountId,1696 user: &T::CrossAccountId,1697 allowed: bool,1698 ) -> DispatchResult {1699 collection.check_is_owner_or_admin(sender)?;17001701 // =========17021703 if allowed {1704 <Allowlist<T>>::insert((collection.id, user), true);1705 Self::deposit_event(Event::<T>::AllowListAddressAdded(1706 collection.id,1707 user.clone(),1708 ));1709 } else {1710 <Allowlist<T>>::remove((collection.id, user));1711 Self::deposit_event(Event::<T>::AllowListAddressRemoved(1712 collection.id,1713 user.clone(),1714 ));1715 }17161717 <PalletEvm<T>>::deposit_log(1718 erc::CollectionHelpersEvents::CollectionChanged {1719 collection_id: eth::collection_id_to_address(collection.id),1720 }1721 .to_log(T::ContractAddress::get()),1722 );17231724 Ok(())1725 }17261727 /// Toggle `user` participation in the `collection`'s admin list.1728 /// #### Store read/writes1729 /// 2 reads, 2 writes1730 pub fn toggle_admin(1731 collection: &CollectionHandle<T>,1732 sender: &T::CrossAccountId,1733 user: &T::CrossAccountId,1734 admin: bool,1735 ) -> DispatchResult {1736 collection.check_is_internal()?;1737 collection.check_is_owner(sender)?;17381739 let is_admin = <IsAdmin<T>>::get((collection.id, user));1740 if is_admin == admin {1741 if admin {1742 return Ok(());1743 } else {1744 return Err(Error::<T>::UserIsNotCollectionAdmin.into());1745 }1746 }1747 let amount = <AdminAmount<T>>::get(collection.id);17481749 // =========17501751 if admin {1752 let amount = amount1753 .checked_add(1)1754 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1755 ensure!(1756 amount <= Self::collection_admins_limit(),1757 <Error<T>>::CollectionAdminCountExceeded,1758 );17591760 <AdminAmount<T>>::insert(collection.id, amount);1761 <IsAdmin<T>>::insert((collection.id, user), true);17621763 Self::deposit_event(Event::<T>::CollectionAdminAdded(1764 collection.id,1765 user.clone(),1766 ));1767 } else {1768 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1769 <IsAdmin<T>>::remove((collection.id, user));17701771 Self::deposit_event(Event::<T>::CollectionAdminRemoved(1772 collection.id,1773 user.clone(),1774 ));1775 }17761777 <PalletEvm<T>>::deposit_log(1778 erc::CollectionHelpersEvents::CollectionChanged {1779 collection_id: eth::collection_id_to_address(collection.id),1780 }1781 .to_log(T::ContractAddress::get()),1782 );17831784 Ok(())1785 }17861787 /// Update collection limits.1788 pub fn update_limits(1789 user: &T::CrossAccountId,1790 collection: &mut CollectionHandle<T>,1791 new_limit: CollectionLimits,1792 ) -> DispatchResult {1793 collection.check_is_internal()?;1794 collection.check_is_owner_or_admin(user)?;17951796 collection.limits =1797 Self::clamp_limits(collection.mode.clone(), &collection.limits, new_limit)?;17981799 Self::deposit_event(Event::<T>::CollectionLimitSet(collection.id));1800 <PalletEvm<T>>::deposit_log(1801 erc::CollectionHelpersEvents::CollectionChanged {1802 collection_id: eth::collection_id_to_address(collection.id),1803 }1804 .to_log(T::ContractAddress::get()),1805 );18061807 collection.save()1808 }18091810 /// Merge set fields from `new_limit` to `old_limit`.1811 fn clamp_limits(1812 mode: CollectionMode,1813 old_limit: &CollectionLimits,1814 mut new_limit: CollectionLimits,1815 ) -> Result<CollectionLimits, DispatchError> {1816 let limits = old_limit;1817 limit_default!(old_limit, new_limit,1818 account_token_ownership_limit => ensure!(1819 new_limit <= MAX_TOKEN_OWNERSHIP,1820 <Error<T>>::CollectionLimitBoundsExceeded,1821 ),1822 sponsored_data_size => ensure!(1823 new_limit <= CUSTOM_DATA_LIMIT,1824 <Error<T>>::CollectionLimitBoundsExceeded,1825 ),18261827 sponsored_data_rate_limit => {},1828 token_limit => ensure!(1829 old_limit >= new_limit && new_limit > 0,1830 <Error<T>>::CollectionTokenLimitExceeded1831 ),18321833 sponsor_transfer_timeout(match mode {1834 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1835 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1836 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1837 }) => ensure!(1838 new_limit <= MAX_SPONSOR_TIMEOUT,1839 <Error<T>>::CollectionLimitBoundsExceeded,1840 ),1841 sponsor_approve_timeout => {},1842 owner_can_transfer => ensure!(1843 !limits.owner_can_transfer_instaled() ||1844 old_limit || !new_limit,1845 <Error<T>>::OwnerPermissionsCantBeReverted,1846 ),1847 owner_can_destroy => ensure!(1848 old_limit || !new_limit,1849 <Error<T>>::OwnerPermissionsCantBeReverted,1850 ),1851 transfers_enabled => {},1852 );1853 Ok(new_limit)1854 }18551856 /// Update collection permissions.1857 pub fn update_permissions(1858 user: &T::CrossAccountId,1859 collection: &mut CollectionHandle<T>,1860 new_permission: CollectionPermissions,1861 ) -> DispatchResult {1862 collection.check_is_internal()?;1863 collection.check_is_owner_or_admin(user)?;1864 collection.permissions = Self::clamp_permissions(1865 collection.mode.clone(),1866 &collection.permissions,1867 new_permission,1868 )?;18691870 Self::deposit_event(Event::<T>::CollectionPermissionSet(collection.id));1871 <PalletEvm<T>>::deposit_log(1872 erc::CollectionHelpersEvents::CollectionChanged {1873 collection_id: eth::collection_id_to_address(collection.id),1874 }1875 .to_log(T::ContractAddress::get()),1876 );18771878 collection.save()1879 }18801881 /// Merge set fields from `new_permission` to `old_permission`.1882 fn clamp_permissions(1883 _mode: CollectionMode,1884 old_permission: &CollectionPermissions,1885 mut new_permission: CollectionPermissions,1886 ) -> Result<CollectionPermissions, DispatchError> {1887 limit_default_clone!(old_permission, new_permission,1888 access => {},1889 mint_mode => {},1890 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1891 );1892 Ok(new_permission)1893 }18941895 /// Repair possibly broken properties of a collection.1896 pub fn repair_collection(collection_id: CollectionId) -> DispatchResult {1897 CollectionProperties::<T>::mutate(collection_id, |properties| {1898 properties.recompute_consumed_space();1899 });19001901 Ok(())1902 }1903}19041905/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1906#[macro_export]1907macro_rules! unsupported {1908 ($runtime:path) => {1909 Err($crate::Error::<$runtime>::UnsupportedOperation.into())1910 };1911}19121913/// Return weights for various worst-case operations.1914pub trait CommonWeightInfo<CrossAccountId> {1915 /// Weight of item creation.1916 fn create_item(data: &CreateItemData) -> Weight {1917 Self::create_multiple_items(from_ref(data))1918 }19191920 /// Weight of items creation.1921 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;19221923 /// Weight of items creation.1924 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;19251926 /// The weight of the burning item.1927 fn burn_item() -> Weight;19281929 /// Property setting weight.1930 ///1931 /// * `amount`- The number of properties to set.1932 fn set_collection_properties(amount: u32) -> Weight;19331934 /// Collection property deletion weight.1935 ///1936 /// * `amount`- The number of properties to set.1937 fn delete_collection_properties(amount: u32) -> Weight;19381939 /// Token property setting weight.1940 ///1941 /// * `amount`- The number of properties to set.1942 fn set_token_properties(amount: u32) -> Weight;19431944 /// Token property deletion weight.1945 ///1946 /// * `amount`- The number of properties to delete.1947 fn delete_token_properties(amount: u32) -> Weight;19481949 /// Token property permissions set weight.1950 ///1951 /// * `amount`- The number of property permissions to set.1952 fn set_token_property_permissions(amount: u32) -> Weight;19531954 /// Transfer price of the token or its parts.1955 fn transfer() -> Weight;19561957 /// The price of setting the permission of the operation from another user.1958 fn approve() -> Weight;19591960 /// The price of setting the permission of the operation from another user for eth mirror.1961 fn approve_from() -> Weight;19621963 /// Transfer price from another user.1964 fn transfer_from() -> Weight;19651966 /// The price of burning a token from another user.1967 fn burn_from() -> Weight;19681969 /// Differs from burn_item in case of Fungible and Refungible, as it should burn1970 /// whole users's balance.1971 ///1972 /// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1973 fn burn_recursively_self_raw() -> Weight;19741975 /// Cost of iterating over `amount` children while burning, without counting child burning itself.1976 ///1977 /// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1978 fn burn_recursively_breadth_raw(amount: u32) -> Weight;19791980 /// The price of recursive burning a token.1981 ///1982 /// `max_selfs` - The maximum burning weight of the token itself.1983 /// `max_breadth` - The maximum number of nested tokens to burn.1984 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1985 Self::burn_recursively_self_raw()1986 .saturating_mul(max_selfs.max(1) as u64)1987 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1988 }19891990 /// The price of retrieving token owner1991 fn token_owner() -> Weight;19921993 /// The price of setting approval for all1994 fn set_allowance_for_all() -> Weight;19951996 /// The price of repairing an item.1997 fn force_repair_item() -> Weight;1998}19992000/// Weight info extension trait for refungible pallet.2001pub trait RefungibleExtensionsWeightInfo {2002 /// Weight of token repartition.2003 fn repartition() -> Weight;2004}20052006/// Common collection operations.2007///2008/// It wraps methods in Fungible, Nonfungible and Refungible pallets2009/// and adds weight info.2010pub trait CommonCollectionOperations<T: Config> {2011 /// Create token.2012 ///2013 /// * `sender` - The user who mint the token and pays for the transaction.2014 /// * `to` - The user who will own the token.2015 /// * `data` - Token data.2016 /// * `nesting_budget` - A budget that can be spent on nesting tokens.2017 fn create_item(2018 &self,2019 sender: T::CrossAccountId,2020 to: T::CrossAccountId,2021 data: CreateItemData,2022 nesting_budget: &dyn Budget,2023 ) -> DispatchResultWithPostInfo;20242025 /// Create multiple tokens.2026 ///2027 /// * `sender` - The user who mint the token and pays for the transaction.2028 /// * `to` - The user who will own the token.2029 /// * `data` - Token data.2030 /// * `nesting_budget` - A budget that can be spent on nesting tokens.2031 fn create_multiple_items(2032 &self,2033 sender: T::CrossAccountId,2034 to: T::CrossAccountId,2035 data: Vec<CreateItemData>,2036 nesting_budget: &dyn Budget,2037 ) -> DispatchResultWithPostInfo;20382039 /// Create multiple tokens.2040 ///2041 /// * `sender` - The user who mint the token and pays for the transaction.2042 /// * `to` - The user who will own the token.2043 /// * `data` - Token data.2044 /// * `nesting_budget` - A budget that can be spent on nesting tokens.2045 fn create_multiple_items_ex(2046 &self,2047 sender: T::CrossAccountId,2048 data: CreateItemExData<T::CrossAccountId>,2049 nesting_budget: &dyn Budget,2050 ) -> DispatchResultWithPostInfo;20512052 /// Burn token.2053 ///2054 /// * `sender` - The user who owns the token.2055 /// * `token` - Token id that will burned.2056 /// * `amount` - The number of parts of the token that will be burned.2057 fn burn_item(2058 &self,2059 sender: T::CrossAccountId,2060 token: TokenId,2061 amount: u128,2062 ) -> DispatchResultWithPostInfo;20632064 /// Burn token and all nested tokens recursievly.2065 ///2066 /// * `sender` - The user who owns the token.2067 /// * `token` - Token id that will burned.2068 /// * `self_budget` - The budget that can be spent on burning tokens.2069 /// * `breadth_budget` - The budget that can be spent on burning nested tokens.2070 fn burn_item_recursively(2071 &self,2072 sender: T::CrossAccountId,2073 token: TokenId,2074 self_budget: &dyn Budget,2075 breadth_budget: &dyn Budget,2076 ) -> DispatchResultWithPostInfo;20772078 /// Set collection properties.2079 ///2080 /// * `sender` - Must be either the owner of the collection or its admin.2081 /// * `properties` - Properties to be set.2082 fn set_collection_properties(2083 &self,2084 sender: T::CrossAccountId,2085 properties: Vec<Property>,2086 ) -> DispatchResultWithPostInfo;20872088 /// Delete collection properties.2089 ///2090 /// * `sender` - Must be either the owner of the collection or its admin.2091 /// * `properties` - The properties to be removed.2092 fn delete_collection_properties(2093 &self,2094 sender: &T::CrossAccountId,2095 property_keys: Vec<PropertyKey>,2096 ) -> DispatchResultWithPostInfo;20972098 /// Set token properties.2099 ///2100 /// The appropriate [`PropertyPermission`] for the token property2101 /// must be set with [`Self::set_token_property_permissions`].2102 ///2103 /// * `sender` - Must be either the owner of the token or its admin.2104 /// * `token_id` - The token for which the properties are being set.2105 /// * `properties` - Properties to be set.2106 /// * `budget` - Budget for setting properties.2107 fn set_token_properties(2108 &self,2109 sender: T::CrossAccountId,2110 token_id: TokenId,2111 properties: Vec<Property>,2112 budget: &dyn Budget,2113 ) -> DispatchResultWithPostInfo;21142115 /// Remove token properties.2116 ///2117 /// The appropriate [`PropertyPermission`] for the token property2118 /// must be set with [`Self::set_token_property_permissions`].2119 ///2120 /// * `sender` - Must be either the owner of the token or its admin.2121 /// * `token_id` - The token for which the properties are being remove.2122 /// * `property_keys` - Keys to remove corresponding properties.2123 /// * `budget` - Budget for removing properties.2124 fn delete_token_properties(2125 &self,2126 sender: T::CrossAccountId,2127 token_id: TokenId,2128 property_keys: Vec<PropertyKey>,2129 budget: &dyn Budget,2130 ) -> DispatchResultWithPostInfo;21312132 /// Set token property permissions.2133 ///2134 /// * `sender` - Must be either the owner of the token or its admin.2135 /// * `token_id` - The token for which the properties are being set.2136 /// * `property_permissions` - Property permissions to be set.2137 /// * `budget` - Budget for setting properties.2138 fn set_token_property_permissions(2139 &self,2140 sender: &T::CrossAccountId,2141 property_permissions: Vec<PropertyKeyPermission>,2142 ) -> DispatchResultWithPostInfo;21432144 /// Transfer amount of token pieces.2145 ///2146 /// * `sender` - Donor user.2147 /// * `to` - Recepient user.2148 /// * `token` - The token of which parts are being sent.2149 /// * `amount` - The number of parts of the token that will be transferred.2150 /// * `budget` - The maximum budget that can be spent on the transfer.2151 fn transfer(2152 &self,2153 sender: T::CrossAccountId,2154 to: T::CrossAccountId,2155 token: TokenId,2156 amount: u128,2157 budget: &dyn Budget,2158 ) -> DispatchResultWithPostInfo;21592160 /// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].2161 ///2162 /// * `sender` - The user who grants access to the token.2163 /// * `spender` - The user to whom the rights are granted.2164 /// * `token` - The token to which access is granted.2165 /// * `amount` - The amount of pieces that another user can dispose of.2166 fn approve(2167 &self,2168 sender: T::CrossAccountId,2169 spender: T::CrossAccountId,2170 token: TokenId,2171 amount: u128,2172 ) -> DispatchResultWithPostInfo;21732174 /// Grant access to another account to transfer parts of the token owned by the calling user's eth mirror via [Self::transfer_from].2175 ///2176 /// * `sender` - The user who grants access to the token.2177 /// * `from` - Spender's eth mirror.2178 /// * `to` - The user to whom the rights are granted.2179 /// * `token` - The token to which access is granted.2180 /// * `amount` - The amount of pieces that another user can dispose of.2181 fn approve_from(2182 &self,2183 sender: T::CrossAccountId,2184 from: T::CrossAccountId,2185 to: T::CrossAccountId,2186 token: TokenId,2187 amount: u128,2188 ) -> DispatchResultWithPostInfo;21892190 /// Send parts of a token owned by another user.2191 ///2192 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2193 ///2194 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).2195 /// * `from` - The user who owns the token.2196 /// * `to` - Recepient user.2197 /// * `token` - The token of which parts are being sent.2198 /// * `amount` - The number of parts of the token that will be transferred.2199 /// * `budget` - The maximum budget that can be spent on the transfer.2200 fn transfer_from(2201 &self,2202 sender: T::CrossAccountId,2203 from: T::CrossAccountId,2204 to: T::CrossAccountId,2205 token: TokenId,2206 amount: u128,2207 budget: &dyn Budget,2208 ) -> DispatchResultWithPostInfo;22092210 /// Burn parts of a token owned by another user.2211 ///2212 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2213 ///2214 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).2215 /// * `from` - The user who owns the token.2216 /// * `token` - The token of which parts are being sent.2217 /// * `amount` - The number of parts of the token that will be transferred.2218 /// * `budget` - The maximum budget that can be spent on the burn.2219 fn burn_from(2220 &self,2221 sender: T::CrossAccountId,2222 from: T::CrossAccountId,2223 token: TokenId,2224 amount: u128,2225 budget: &dyn Budget,2226 ) -> DispatchResultWithPostInfo;22272228 /// Check permission to nest token.2229 ///2230 /// * `sender` - The user who initiated the check.2231 /// * `from` - The token that is checked for embedding.2232 /// * `under` - Token under which to check.2233 /// * `budget` - The maximum budget that can be spent on the check.2234 fn check_nesting(2235 &self,2236 sender: T::CrossAccountId,2237 from: (CollectionId, TokenId),2238 under: TokenId,2239 budget: &dyn Budget,2240 ) -> DispatchResult;22412242 /// Nest one token into another.2243 ///2244 /// * `under` - Token holder.2245 /// * `to_nest` - Nested token.2246 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));22472248 /// Unnest token.2249 ///2250 /// * `under` - Token holder.2251 /// * `to_nest` - Token to unnest.2252 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));22532254 /// Get all user tokens.2255 ///2256 /// * `account` - Account for which you need to get tokens.2257 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;22582259 /// Get all the tokens in the collection.2260 fn collection_tokens(&self) -> Vec<TokenId>;22612262 /// Check if the token exists.2263 ///2264 /// * `token` - Id token to check.2265 fn token_exists(&self, token: TokenId) -> bool;22662267 /// Get the id of the last minted token.2268 fn last_token_id(&self) -> TokenId;22692270 /// Get the owner of the token.2271 ///2272 /// * `token` - The token for which you need to find out the owner.2273 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError>;22742275 /// Returns 10 tokens owners in no particular order.2276 ///2277 /// * `token` - The token for which you need to find out the owners.2278 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;22792280 /// Get the value of the token property by key.2281 ///2282 /// * `token` - Token with the property to get.2283 /// * `key` - Property name.2284 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;22852286 /// Get a set of token properties by key vector.2287 ///2288 /// * `token` - Token with the property to get.2289 /// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),2290 /// then all properties are returned.2291 fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;22922293 /// Amount of unique collection tokens2294 fn total_supply(&self) -> u32;22952296 /// Amount of different tokens account has.2297 ///2298 /// * `account` - The account for which need to get the balance.2299 fn account_balance(&self, account: T::CrossAccountId) -> u32;23002301 /// Amount of specific token account have.2302 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;23032304 /// Amount of token pieces2305 fn total_pieces(&self, token: TokenId) -> Option<u128>;23062307 /// Get the number of parts of the token that a trusted user can manage.2308 ///2309 /// * `sender` - Trusted user.2310 /// * `spender` - Owner of the token.2311 /// * `token` - The token for which to get the value.2312 fn allowance(2313 &self,2314 sender: T::CrossAccountId,2315 spender: T::CrossAccountId,2316 token: TokenId,2317 ) -> u128;23182319 /// Get extension for RFT collection.2320 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;23212322 /// The `operator` is allowed to transfer all tokens of the `owner` on their behalf.2323 /// * `owner` - Token owner2324 /// * `operator` - Operator2325 /// * `approve` - Should operator status be granted or revoked?2326 fn set_allowance_for_all(2327 &self,2328 owner: T::CrossAccountId,2329 operator: T::CrossAccountId,2330 approve: bool,2331 ) -> DispatchResultWithPostInfo;23322333 /// Tells whether the given `owner` approves the `operator`.2334 fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;23352336 /// Repairs a possibly broken item.2337 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo;2338}23392340/// Extension for RFT collection.2341pub trait RefungibleExtensions<T>2342where2343 T: Config,2344{2345 /// Change the number of parts of the token.2346 ///2347 /// When the value changes down, this function is equivalent to burning parts of the token.2348 ///2349 /// * `sender` - The user calling the repartition operation. Must be the owner of the token.2350 /// * `token` - The token for which you want to change the number of parts.2351 /// * `amount` - The new value of the parts of the token.2352 fn repartition(2353 &self,2354 sender: &T::CrossAccountId,2355 token: TokenId,2356 amount: u128,2357 ) -> DispatchResultWithPostInfo;2358}23592360/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].2361///2362/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.2363pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {2364 let post_info = PostDispatchInfo {2365 actual_weight: Some(weight),2366 pays_fee: Pays::Yes,2367 };2368 match res {2369 Ok(()) => Ok(post_info),2370 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),2371 }2372}23732374impl<T: Config> From<PropertiesError> for Error<T> {2375 fn from(error: PropertiesError) -> Self {2376 match error {2377 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,2378 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,2379 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,2380 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,2381 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,2382 }2383 }2384}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::{57 ops::{Deref, DerefMut},58 slice::from_ref,59};60use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};61use sp_std::vec::Vec;62use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};63use evm_coder::ToLog;64use frame_support::{65 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},66 ensure,67 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},68 dispatch::Pays,69 transactional, fail,70};71use pallet_evm::GasWeightMapping;72use up_data_structs::{73 AccessMode,74 COLLECTION_NUMBER_LIMIT,75 Collection,76 RpcCollection,77 CollectionFlags,78 RpcCollectionFlags,79 CollectionId,80 CreateItemData,81 MAX_TOKEN_PREFIX_LENGTH,82 COLLECTION_ADMINS_LIMIT,83 TokenId,84 TokenChild,85 CollectionStats,86 MAX_TOKEN_OWNERSHIP,87 CollectionMode,88 NFT_SPONSOR_TRANSFER_TIMEOUT,89 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,90 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,91 MAX_SPONSOR_TIMEOUT,92 CUSTOM_DATA_LIMIT,93 CollectionLimits,94 CreateCollectionData,95 SponsorshipState,96 CreateItemExData,97 SponsoringRateLimit,98 budget::Budget,99 PhantomType,100 Property,101 Properties,102 PropertiesPermissionMap,103 PropertyKey,104 PropertyValue,105 PropertyPermission,106 PropertiesError,107 TokenOwnerError,108 PropertyKeyPermission,109 TokenData,110 TrySetProperty,111 PropertyScope,112 // RMRK113 RmrkCollectionInfo,114 RmrkInstanceInfo,115 RmrkResourceInfo,116 RmrkPropertyInfo,117 RmrkBaseInfo,118 RmrkPartType,119 RmrkBoundedTheme,120 RmrkNftChild,121 CollectionPermissions,122};123use up_pov_estimate_rpc::PovInfo;124125pub use pallet::*;126use sp_core::H160;127use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};128129use crate::erc::CollectionHelpersEvents;130#[cfg(feature = "runtime-benchmarks")]131pub mod benchmarking;132pub mod dispatch;133pub mod erc;134pub mod eth;135pub mod weights;136137/// Weight info.138pub type SelfWeightOf<T> = <T as Config>::WeightInfo;139140/// Collection handle contains information about collection data and id.141/// Also provides functionality to count consumed gas.142///143/// CollectionHandle is used as a generic wrapper for collections of all types.144/// It allows to perform common operations and queries on any collection type,145/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].146#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]147pub struct CollectionHandle<T: Config> {148 /// Collection id149 pub id: CollectionId,150 collection: Collection<T::AccountId>,151 /// Substrate recorder for counting consumed gas152 pub recorder: SubstrateRecorder<T>,153}154155impl<T: Config> WithRecorder<T> for CollectionHandle<T> {156 fn recorder(&self) -> &SubstrateRecorder<T> {157 &self.recorder158 }159 fn into_recorder(self) -> SubstrateRecorder<T> {160 self.recorder161 }162}163164impl<T: Config> CollectionHandle<T> {165 /// Same as [CollectionHandle::new] but with an explicit gas limit.166 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {167 <CollectionById<T>>::get(id).map(|collection| Self {168 id,169 collection,170 recorder: SubstrateRecorder::new(gas_limit),171 })172 }173174 /// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].175 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {176 <CollectionById<T>>::get(id).map(|collection| Self {177 id,178 collection,179 recorder,180 })181 }182183 /// Retrives collection data from storage and creates collection handle with default parameters.184 /// If collection not found return `None`185 pub fn new(id: CollectionId) -> Option<Self> {186 Self::new_with_gas_limit(id, u64::MAX)187 }188189 /// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.190 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {191 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)192 }193194 /// Consume gas for reading.195 pub fn consume_store_reads(196 &self,197 reads: u64,198 ) -> pallet_evm_coder_substrate::execution::Result<()> {199 self.recorder200 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(201 <T as frame_system::Config>::DbWeight::get()202 .read203 .saturating_mul(reads),204 )))205 }206207 /// Consume gas for writing.208 pub fn consume_store_writes(209 &self,210 writes: u64,211 ) -> pallet_evm_coder_substrate::execution::Result<()> {212 self.recorder213 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(214 <T as frame_system::Config>::DbWeight::get()215 .write216 .saturating_mul(writes),217 )))218 }219220 /// Consume gas for reading and writing.221 pub fn consume_store_reads_and_writes(222 &self,223 reads: u64,224 writes: u64,225 ) -> pallet_evm_coder_substrate::execution::Result<()> {226 let weight = <T as frame_system::Config>::DbWeight::get();227 let reads = weight.read.saturating_mul(reads);228 let writes = weight.read.saturating_mul(writes);229 self.recorder230 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(231 reads.saturating_add(writes),232 )))233 }234235 /// Save collection to storage.236 pub fn save(&self) -> DispatchResult {237 <CollectionById<T>>::insert(self.id, &self.collection);238 Ok(())239 }240241 /// Set collection sponsor.242 ///243 /// Unique collections allows sponsoring for certain actions.244 /// This method allows you to set the sponsor of the collection.245 /// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].246 pub fn set_sponsor(247 &mut self,248 sender: &T::CrossAccountId,249 sponsor: T::AccountId,250 ) -> DispatchResult {251 self.check_is_internal()?;252 self.check_is_owner_or_admin(sender)?;253254 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor.clone());255256 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor));257 <PalletEvm<T>>::deposit_log(258 erc::CollectionHelpersEvents::CollectionChanged {259 collection_id: eth::collection_id_to_address(self.id),260 }261 .to_log(T::ContractAddress::get()),262 );263264 self.save()265 }266267 /// Force set `sponsor`.268 ///269 /// Differs from [`set_sponsor`][`Self::set_sponsor`] in that confirmation270 /// from the `sponsor` is not required.271 ///272 /// # Arguments273 ///274 /// * `sender`: Caller's account.275 /// * `sponsor`: ID of the account of the sponsor-to-be.276 pub fn force_set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {277 self.check_is_internal()?;278279 self.collection.sponsorship = SponsorshipState::Confirmed(sponsor.clone());280281 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor.clone()));282 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sponsor));283 <PalletEvm<T>>::deposit_log(284 erc::CollectionHelpersEvents::CollectionChanged {285 collection_id: eth::collection_id_to_address(self.id),286 }287 .to_log(T::ContractAddress::get()),288 );289290 self.save()291 }292293 /// Confirm sponsorship294 ///295 /// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.296 /// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].297 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> DispatchResult {298 self.check_is_internal()?;299 ensure!(300 self.collection.sponsorship.pending_sponsor() == Some(sender),301 Error::<T>::ConfirmSponsorshipFail302 );303304 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());305306 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sender.clone()));307 <PalletEvm<T>>::deposit_log(308 erc::CollectionHelpersEvents::CollectionChanged {309 collection_id: eth::collection_id_to_address(self.id),310 }311 .to_log(T::ContractAddress::get()),312 );313314 self.save()315 }316317 /// Remove collection sponsor.318 pub fn remove_sponsor(&mut self, sender: &T::CrossAccountId) -> DispatchResult {319 self.check_is_internal()?;320 self.check_is_owner_or_admin(sender)?;321322 self.collection.sponsorship = SponsorshipState::Disabled;323324 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));325 <PalletEvm<T>>::deposit_log(326 erc::CollectionHelpersEvents::CollectionChanged {327 collection_id: eth::collection_id_to_address(self.id),328 }329 .to_log(T::ContractAddress::get()),330 );331 self.save()332 }333334 /// Force remove `sponsor`.335 ///336 /// Differs from `remove_sponsor` in that337 /// it doesn't require consent from the `owner` of the collection.338 pub fn force_remove_sponsor(&mut self) -> DispatchResult {339 self.check_is_internal()?;340341 self.collection.sponsorship = SponsorshipState::Disabled;342343 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));344 <PalletEvm<T>>::deposit_log(345 erc::CollectionHelpersEvents::CollectionChanged {346 collection_id: eth::collection_id_to_address(self.id),347 }348 .to_log(T::ContractAddress::get()),349 );350 self.save()351 }352353 /// Checks that the collection was created with, and must be operated upon through **Unique API**.354 /// Now check only the `external` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.355 pub fn check_is_internal(&self) -> DispatchResult {356 if self.flags.external {357 return Err(<Error<T>>::CollectionIsExternal)?;358 }359360 Ok(())361 }362363 /// Checks that the collection was created with, and must be operated upon through an **assimilated API**.364 /// Now check only the `external` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.365 pub fn check_is_external(&self) -> DispatchResult {366 if !self.flags.external {367 return Err(<Error<T>>::CollectionIsInternal)?;368 }369370 Ok(())371 }372}373374impl<T: Config> Deref for CollectionHandle<T> {375 type Target = Collection<T::AccountId>;376377 fn deref(&self) -> &Self::Target {378 &self.collection379 }380}381382impl<T: Config> DerefMut for CollectionHandle<T> {383 fn deref_mut(&mut self) -> &mut Self::Target {384 &mut self.collection385 }386}387388impl<T: Config> CollectionHandle<T> {389 /// Checks if the `user` is the owner of the collection.390 pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {391 ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);392 Ok(())393 }394395 /// Returns **true** if the `user` is the owner or administrator of the collection.396 pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {397 *user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))398 }399400 /// Checks if the `user` is the owner or administrator of the collection.401 pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {402 ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);403 Ok(())404 }405406 /// Returns **true** if407 /// * the `user`is a collection owner or admin408 /// * the collection limits allow the owner/admins to transfer/burn any collection token409 pub fn ignores_token_restrictions(&self, user: &T::CrossAccountId) -> bool {410 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)411 }412413 /// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.414 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {415 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)416 }417418 /// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.419 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {420 ensure!(421 <Allowlist<T>>::get((self.id, user)),422 <Error<T>>::AddressNotInAllowlist423 );424 Ok(())425 }426427 /// Changes collection owner to another account428 /// #### Store read/writes429 /// 1 writes430 pub fn change_owner(431 &mut self,432 caller: T::CrossAccountId,433 new_owner: T::CrossAccountId,434 ) -> DispatchResult {435 self.check_is_internal()?;436 self.check_is_owner(&caller)?;437 self.collection.owner = new_owner.as_sub().clone();438439 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnerChanged(440 self.id,441 new_owner.as_sub().clone(),442 ));443 <PalletEvm<T>>::deposit_log(444 erc::CollectionHelpersEvents::CollectionChanged {445 collection_id: eth::collection_id_to_address(self.id),446 }447 .to_log(T::ContractAddress::get()),448 );449450 self.save()451 }452}453454#[frame_support::pallet]455pub mod pallet {456 use super::*;457 use dispatch::CollectionDispatch;458 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};459 use frame_system::pallet_prelude::*;460 use frame_support::traits::Currency;461 use up_data_structs::{TokenId, mapping::TokenAddressMapping};462 use scale_info::TypeInfo;463 use weights::WeightInfo;464465 #[pallet::config]466 pub trait Config:467 frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config + TypeInfo468 {469 /// Weight information for functions of this pallet.470 type WeightInfo: WeightInfo;471472 /// Events compatible with [`frame_system::Config::Event`].473 type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;474475 /// Handler of accounts and payment.476 type Currency: Currency<Self::AccountId>;477478 /// Set price to create a collection.479 #[pallet::constant]480 type CollectionCreationPrice: Get<481 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,482 >;483484 /// Dispatcher of operations on collections.485 type CollectionDispatch: CollectionDispatch<Self>;486487 /// Account which holds the chain's treasury.488 type TreasuryAccountId: Get<Self::AccountId>;489490 /// Address under which the CollectionHelper contract would be available.491 #[pallet::constant]492 type ContractAddress: Get<H160>;493494 /// Mapper for token addresses to Ethereum addresses.495 type EvmTokenAddressMapping: TokenAddressMapping<H160>;496497 /// Mapper for token addresses to [`CrossAccountId`].498 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;499 }500501 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);502503 #[pallet::pallet]504 #[pallet::storage_version(STORAGE_VERSION)]505 #[pallet::generate_store(pub(super) trait Store)]506 pub struct Pallet<T>(_);507508 #[pallet::extra_constants]509 impl<T: Config> Pallet<T> {510 /// Maximum admins per collection.511 pub fn collection_admins_limit() -> u32 {512 COLLECTION_ADMINS_LIMIT513 }514 }515516 impl<T: Config> Pallet<T> {517 /// Helper function that handles deposit events518 pub fn deposit_event(event: Event<T>) {519 let event = <T as Config>::RuntimeEvent::from(event);520 let event = event.into();521 <frame_system::Pallet<T>>::deposit_event(event)522 }523 }524525 #[pallet::event]526 pub enum Event<T: Config> {527 /// New collection was created528 CollectionCreated(529 /// Globally unique identifier of newly created collection.530 CollectionId,531 /// [`CollectionMode`] converted into _u8_.532 u8,533 /// Collection owner.534 T::AccountId,535 ),536537 /// New collection was destroyed538 CollectionDestroyed(539 /// Globally unique identifier of collection.540 CollectionId,541 ),542543 /// New item was created.544 ItemCreated(545 /// Id of the collection where item was created.546 CollectionId,547 /// Id of an item. Unique within the collection.548 TokenId,549 /// Owner of newly created item550 T::CrossAccountId,551 /// Always 1 for NFT552 u128,553 ),554555 /// Collection item was burned.556 ItemDestroyed(557 /// Id of the collection where item was destroyed.558 CollectionId,559 /// Identifier of burned NFT.560 TokenId,561 /// Which user has destroyed its tokens.562 T::CrossAccountId,563 /// Amount of token pieces destroed. Always 1 for NFT.564 u128,565 ),566567 /// Item was transferred568 Transfer(569 /// Id of collection to which item is belong.570 CollectionId,571 /// Id of an item.572 TokenId,573 /// Original owner of item.574 T::CrossAccountId,575 /// New owner of item.576 T::CrossAccountId,577 /// Amount of token pieces transfered. Always 1 for NFT.578 u128,579 ),580581 /// Amount pieces of token owned by `sender` was approved for `spender`.582 Approved(583 /// Id of collection to which item is belong.584 CollectionId,585 /// Id of an item.586 TokenId,587 /// Original owner of item.588 T::CrossAccountId,589 /// Id for which the approval was granted.590 T::CrossAccountId,591 /// Amount of token pieces transfered. Always 1 for NFT.592 u128,593 ),594595 /// A `sender` approves operations on all owned tokens for `spender`.596 ApprovedForAll(597 /// Id of collection to which item is belong.598 CollectionId,599 /// Owner of a wallet.600 T::CrossAccountId,601 /// Id for which operator status was granted or rewoked.602 T::CrossAccountId,603 /// Is operator status granted or revoked?604 bool,605 ),606607 /// The colletion property has been added or edited.608 CollectionPropertySet(609 /// Id of collection to which property has been set.610 CollectionId,611 /// The property that was set.612 PropertyKey,613 ),614615 /// The property has been deleted.616 CollectionPropertyDeleted(617 /// Id of collection to which property has been deleted.618 CollectionId,619 /// The property that was deleted.620 PropertyKey,621 ),622623 /// The token property has been added or edited.624 TokenPropertySet(625 /// Identifier of the collection whose token has the property set.626 CollectionId,627 /// The token for which the property was set.628 TokenId,629 /// The property that was set.630 PropertyKey,631 ),632633 /// The token property has been deleted.634 TokenPropertyDeleted(635 /// Identifier of the collection whose token has the property deleted.636 CollectionId,637 /// The token for which the property was deleted.638 TokenId,639 /// The property that was deleted.640 PropertyKey,641 ),642643 /// The token property permission of a collection has been set.644 PropertyPermissionSet(645 /// ID of collection to which property permission has been set.646 CollectionId,647 /// The property permission that was set.648 PropertyKey,649 ),650651 /// Address was added to the allow list.652 AllowListAddressAdded(653 /// ID of the affected collection.654 CollectionId,655 /// Address of the added account.656 T::CrossAccountId,657 ),658659 /// Address was removed from the allow list.660 AllowListAddressRemoved(661 /// ID of the affected collection.662 CollectionId,663 /// Address of the removed account.664 T::CrossAccountId,665 ),666667 /// Collection admin was added.668 CollectionAdminAdded(669 /// ID of the affected collection.670 CollectionId,671 /// Admin address.672 T::CrossAccountId,673 ),674675 /// Collection admin was removed.676 CollectionAdminRemoved(677 /// ID of the affected collection.678 CollectionId,679 /// Removed admin address.680 T::CrossAccountId,681 ),682683 /// Collection limits were set.684 CollectionLimitSet(685 /// ID of the affected collection.686 CollectionId,687 ),688689 /// Collection owned was changed.690 CollectionOwnerChanged(691 /// ID of the affected collection.692 CollectionId,693 /// New owner address.694 T::AccountId,695 ),696697 /// Collection permissions were set.698 CollectionPermissionSet(699 /// ID of the affected collection.700 CollectionId,701 ),702703 /// Collection sponsor was set.704 CollectionSponsorSet(705 /// ID of the affected collection.706 CollectionId,707 /// New sponsor address.708 T::AccountId,709 ),710711 /// New sponsor was confirm.712 SponsorshipConfirmed(713 /// ID of the affected collection.714 CollectionId,715 /// New sponsor address.716 T::AccountId,717 ),718719 /// Collection sponsor was removed.720 CollectionSponsorRemoved(721 /// ID of the affected collection.722 CollectionId,723 ),724 }725726 #[pallet::error]727 pub enum Error<T> {728 /// This collection does not exist.729 CollectionNotFound,730 /// Sender parameter and item owner must be equal.731 MustBeTokenOwner,732 /// No permission to perform action733 NoPermission,734 /// Destroying only empty collections is allowed735 CantDestroyNotEmptyCollection,736 /// Collection is not in mint mode.737 PublicMintingNotAllowed,738 /// Address is not in allow list.739 AddressNotInAllowlist,740741 /// Collection name can not be longer than 63 char.742 CollectionNameLimitExceeded,743 /// Collection description can not be longer than 255 char.744 CollectionDescriptionLimitExceeded,745 /// Token prefix can not be longer than 15 char.746 CollectionTokenPrefixLimitExceeded,747 /// Total collections bound exceeded.748 TotalCollectionsLimitExceeded,749 /// Exceeded max admin count750 CollectionAdminCountExceeded,751 /// Collection limit bounds per collection exceeded752 CollectionLimitBoundsExceeded,753 /// Tried to enable permissions which are only permitted to be disabled754 OwnerPermissionsCantBeReverted,755 /// Collection settings not allowing items transferring756 TransferNotAllowed,757 /// Account token limit exceeded per collection758 AccountTokenLimitExceeded,759 /// Collection token limit exceeded760 CollectionTokenLimitExceeded,761 /// Metadata flag frozen762 MetadataFlagFrozen,763764 /// Item does not exist765 TokenNotFound,766 /// Item is balance not enough767 TokenValueTooLow,768 /// Requested value is more than the approved769 ApprovedValueTooLow,770 /// Tried to approve more than owned771 CantApproveMoreThanOwned,772 /// Only spending from eth mirror could be approved773 AddressIsNotEthMirror,774775 /// Can't transfer tokens to ethereum zero address776 AddressIsZero,777778 /// The operation is not supported779 UnsupportedOperation,780781 /// Insufficient funds to perform an action782 NotSufficientFounds,783784 /// User does not satisfy the nesting rule785 UserIsNotAllowedToNest,786 /// Only tokens from specific collections may nest tokens under this one787 SourceCollectionIsNotAllowedToNest,788789 /// Tried to store more data than allowed in collection field790 CollectionFieldSizeExceeded,791792 /// Tried to store more property data than allowed793 NoSpaceForProperty,794795 /// Tried to store more property keys than allowed796 PropertyLimitReached,797798 /// Property key is too long799 PropertyKeyIsTooLong,800801 /// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed802 InvalidCharacterInPropertyKey,803804 /// Empty property keys are forbidden805 EmptyPropertyKey,806807 /// Tried to access an external collection with an internal API808 CollectionIsExternal,809810 /// Tried to access an internal collection with an external API811 CollectionIsInternal,812813 /// This address is not set as sponsor, use setCollectionSponsor first.814 ConfirmSponsorshipFail,815816 /// The user is not an administrator.817 UserIsNotCollectionAdmin,818 }819820 /// Storage of the count of created collections. Essentially contains the last collection ID.821 #[pallet::storage]822 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;823824 /// Storage of the count of deleted collections.825 #[pallet::storage]826 pub type DestroyedCollectionCount<T> =827 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;828829 /// Storage of collection info.830 #[pallet::storage]831 pub type CollectionById<T> = StorageMap<832 Hasher = Blake2_128Concat,833 Key = CollectionId,834 Value = Collection<<T as frame_system::Config>::AccountId>,835 QueryKind = OptionQuery,836 >;837838 /// Storage of collection properties.839 #[pallet::storage]840 #[pallet::getter(fn collection_properties)]841 pub type CollectionProperties<T> = StorageMap<842 Hasher = Blake2_128Concat,843 Key = CollectionId,844 Value = Properties,845 QueryKind = ValueQuery,846 OnEmpty = up_data_structs::CollectionProperties,847 >;848849 /// Storage of token property permissions of a collection.850 #[pallet::storage]851 #[pallet::getter(fn property_permissions)]852 pub type CollectionPropertyPermissions<T> = StorageMap<853 Hasher = Blake2_128Concat,854 Key = CollectionId,855 Value = PropertiesPermissionMap,856 QueryKind = ValueQuery,857 >;858859 /// Storage of the amount of collection admins.860 #[pallet::storage]861 pub type AdminAmount<T> = StorageMap<862 Hasher = Blake2_128Concat,863 Key = CollectionId,864 Value = u32,865 QueryKind = ValueQuery,866 >;867868 /// List of collection admins.869 #[pallet::storage]870 pub type IsAdmin<T: Config> = StorageNMap<871 Key = (872 Key<Blake2_128Concat, CollectionId>,873 Key<Blake2_128Concat, T::CrossAccountId>,874 ),875 Value = bool,876 QueryKind = ValueQuery,877 >;878879 /// Allowlisted collection users.880 #[pallet::storage]881 pub type Allowlist<T: Config> = StorageNMap<882 Key = (883 Key<Blake2_128Concat, CollectionId>,884 Key<Blake2_128Concat, T::CrossAccountId>,885 ),886 Value = bool,887 QueryKind = ValueQuery,888 >;889890 /// Not used by code, exists only to provide some types to metadata.891 #[pallet::storage]892 pub type DummyStorageValue<T: Config> = StorageValue<893 Value = (894 CollectionStats,895 CollectionId,896 TokenId,897 TokenChild,898 PhantomType<(899 TokenData<T::CrossAccountId>,900 RpcCollection<T::AccountId>,901 // RMRK902 RmrkCollectionInfo<T::AccountId>,903 RmrkInstanceInfo<T::AccountId>,904 RmrkResourceInfo,905 RmrkPropertyInfo,906 RmrkBaseInfo<T::AccountId>,907 RmrkPartType,908 RmrkBoundedTheme,909 RmrkNftChild,910 // PoV Estimate Info911 PovInfo,912 )>,913 ),914 QueryKind = OptionQuery,915 >;916917 #[pallet::hooks]918 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {919 fn on_runtime_upgrade() -> Weight {920 StorageVersion::new(1).put::<Pallet<T>>();921922 Weight::zero()923 }924 }925}926927impl<T: Config> Pallet<T> {928 /// Enshure that receiver address is correct.929 ///930 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.931 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {932 ensure!(933 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,934 <Error<T>>::AddressIsZero935 );936 Ok(())937 }938939 /// Get a vector of collection admins.940 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {941 <IsAdmin<T>>::iter_prefix((collection,))942 .map(|(a, _)| a)943 .collect()944 }945946 /// Get a vector of users allowed to mint tokens.947 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {948 <Allowlist<T>>::iter_prefix((collection,))949 .map(|(a, _)| a)950 .collect()951 }952953 /// Is `user` allowed to mint token in `collection`.954 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {955 <Allowlist<T>>::get((collection, user))956 }957958 /// Get statistics of collections.959 pub fn collection_stats() -> CollectionStats {960 let created = <CreatedCollectionCount<T>>::get();961 let destroyed = <DestroyedCollectionCount<T>>::get();962 CollectionStats {963 created: created.0,964 destroyed: destroyed.0,965 alive: created.0 - destroyed.0,966 }967 }968969 /// Get the effective limits for the collection.970 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {971 let collection = <CollectionById<T>>::get(collection)?;972 let limits = collection.limits;973 let effective_limits = CollectionLimits {974 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),975 sponsored_data_size: Some(limits.sponsored_data_size()),976 sponsored_data_rate_limit: Some(977 limits978 .sponsored_data_rate_limit979 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),980 ),981 token_limit: Some(limits.token_limit()),982 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(983 match collection.mode {984 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,985 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,986 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,987 },988 )),989 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),990 owner_can_transfer: Some(limits.owner_can_transfer()),991 owner_can_destroy: Some(limits.owner_can_destroy()),992 transfers_enabled: Some(limits.transfers_enabled()),993 };994995 Some(effective_limits)996 }997998 /// Returns information about the `collection` adapted for rpc.999 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {1000 let Collection {1001 name,1002 description,1003 owner,1004 mode,1005 token_prefix,1006 sponsorship,1007 limits,1008 permissions,1009 flags,1010 } = <CollectionById<T>>::get(collection)?;10111012 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)1013 .into_iter()1014 .map(|(key, permission)| PropertyKeyPermission { key, permission })1015 .collect();10161017 let properties = <CollectionProperties<T>>::get(collection)1018 .into_iter()1019 .map(|(key, value)| Property { key, value })1020 .collect();10211022 let permissions = CollectionPermissions {1023 access: Some(permissions.access()),1024 mint_mode: Some(permissions.mint_mode()),1025 nesting: Some(permissions.nesting().clone()),1026 };10271028 Some(RpcCollection {1029 name: name.into_inner(),1030 description: description.into_inner(),1031 owner,1032 mode,1033 token_prefix: token_prefix.into_inner(),1034 sponsorship,1035 limits,1036 permissions,1037 token_property_permissions,1038 properties,1039 read_only: flags.external,10401041 flags: RpcCollectionFlags {1042 foreign: flags.foreign,1043 erc721metadata: flags.erc721metadata,1044 },1045 })1046 }1047}10481049macro_rules! limit_default {1050 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1051 $(1052 if let Some($new) = $new.$field {1053 let $old = $old.$field($($arg)?);1054 let _ = $new;1055 let _ = $old;1056 $check1057 } else {1058 $new.$field = $old.$field1059 }1060 )*1061 }};1062}1063macro_rules! limit_default_clone {1064 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1065 $(1066 if let Some($new) = $new.$field.clone() {1067 let $old = $old.$field($($arg)?);1068 let _ = $new;1069 let _ = $old;1070 $check1071 } else {1072 $new.$field = $old.$field.clone()1073 }1074 )*1075 }};1076}10771078impl<T: Config> Pallet<T> {1079 /// Create new collection.1080 ///1081 /// * `owner` - The owner of the collection.1082 /// * `data` - Description of the created collection.1083 /// * `flags` - Extra flags to store.1084 pub fn init_collection(1085 owner: T::CrossAccountId,1086 payer: T::CrossAccountId,1087 data: CreateCollectionData<T::AccountId>,1088 flags: CollectionFlags,1089 ) -> Result<CollectionId, DispatchError> {1090 {1091 ensure!(1092 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,1093 Error::<T>::CollectionTokenPrefixLimitExceeded1094 );1095 }10961097 let created_count = <CreatedCollectionCount<T>>::get()1098 .01099 .checked_add(1)1100 .ok_or(ArithmeticError::Overflow)?;1101 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;1102 let id = CollectionId(created_count);11031104 // bound Total number of collections1105 ensure!(1106 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,1107 <Error<T>>::TotalCollectionsLimitExceeded1108 );11091110 // =========11111112 let collection = Collection {1113 owner: owner.as_sub().clone(),1114 name: data.name,1115 mode: data.mode.clone(),1116 description: data.description,1117 token_prefix: data.token_prefix,1118 sponsorship: data1119 .pending_sponsor1120 .map(SponsorshipState::Unconfirmed)1121 .unwrap_or_default(),1122 limits: data1123 .limits1124 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))1125 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,1126 permissions: data1127 .permissions1128 .map(|permissions| {1129 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)1130 })1131 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,1132 flags,1133 };11341135 let mut collection_properties = up_data_structs::CollectionProperties::get();1136 collection_properties1137 .try_set_from_iter(data.properties.into_iter())1138 .map_err(<Error<T>>::from)?;11391140 CollectionProperties::<T>::insert(id, collection_properties);11411142 let mut token_props_permissions = PropertiesPermissionMap::new();1143 token_props_permissions1144 .try_set_from_iter(data.token_property_permissions.into_iter())1145 .map_err(<Error<T>>::from)?;11461147 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);11481149 // Take a (non-refundable) deposit of collection creation1150 {1151 let mut imbalance =1152 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();1153 imbalance.subsume(1154 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(1155 &T::TreasuryAccountId::get(),1156 T::CollectionCreationPrice::get(),1157 ),1158 );1159 <T as Config>::Currency::settle(1160 payer.as_sub(),1161 imbalance,1162 WithdrawReasons::TRANSFER,1163 ExistenceRequirement::KeepAlive,1164 )1165 .map_err(|_| Error::<T>::NotSufficientFounds)?;1166 }11671168 <CreatedCollectionCount<T>>::put(created_count);1169 <Pallet<T>>::deposit_event(Event::CollectionCreated(1170 id,1171 data.mode.id(),1172 owner.as_sub().clone(),1173 ));1174 <PalletEvm<T>>::deposit_log(1175 erc::CollectionHelpersEvents::CollectionCreated {1176 owner: *owner.as_eth(),1177 collection_id: eth::collection_id_to_address(id),1178 }1179 .to_log(T::ContractAddress::get()),1180 );1181 <CollectionById<T>>::insert(id, collection);1182 Ok(id)1183 }11841185 /// Destroy collection.1186 ///1187 /// * `collection` - Collection handler.1188 /// * `sender` - The owner or administrator of the collection.1189 pub fn destroy_collection(1190 collection: CollectionHandle<T>,1191 sender: &T::CrossAccountId,1192 ) -> DispatchResult {1193 ensure!(1194 collection.limits.owner_can_destroy(),1195 <Error<T>>::NoPermission,1196 );1197 collection.check_is_owner(sender)?;11981199 let destroyed_collections = <DestroyedCollectionCount<T>>::get()1200 .01201 .checked_add(1)1202 .ok_or(ArithmeticError::Overflow)?;12031204 // =========12051206 <DestroyedCollectionCount<T>>::put(destroyed_collections);1207 <CollectionById<T>>::remove(collection.id);1208 <AdminAmount<T>>::remove(collection.id);1209 let _ = <IsAdmin<T>>::clear_prefix((collection.id,), u32::MAX, None);1210 let _ = <Allowlist<T>>::clear_prefix((collection.id,), u32::MAX, None);1211 <CollectionProperties<T>>::remove(collection.id);12121213 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));12141215 <PalletEvm<T>>::deposit_log(1216 erc::CollectionHelpersEvents::CollectionDestroyed {1217 collection_id: eth::collection_id_to_address(collection.id),1218 }1219 .to_log(T::ContractAddress::get()),1220 );1221 Ok(())1222 }12231224 /// This function sets or removes a collection properties according to1225 /// `properties_updates` contents:1226 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1227 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.1228 ///1229 /// This function fires an event for each property change.1230 /// In case of an error, all the changes (including the events) will be reverted1231 /// since the function is transactional.1232 #[transactional]1233 fn modify_collection_properties(1234 collection: &CollectionHandle<T>,1235 sender: &T::CrossAccountId,1236 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1237 ) -> DispatchResult {1238 collection.check_is_owner_or_admin(sender)?;12391240 let mut stored_properties = <CollectionProperties<T>>::get(collection.id);12411242 for (key, value) in properties_updates {1243 match value {1244 Some(value) => {1245 stored_properties1246 .try_set(key.clone(), value)1247 .map_err(<Error<T>>::from)?;12481249 Self::deposit_event(Event::CollectionPropertySet(collection.id, key));1250 <PalletEvm<T>>::deposit_log(1251 erc::CollectionHelpersEvents::CollectionChanged {1252 collection_id: eth::collection_id_to_address(collection.id),1253 }1254 .to_log(T::ContractAddress::get()),1255 );1256 }1257 None => {1258 stored_properties.remove(&key).map_err(<Error<T>>::from)?;12591260 Self::deposit_event(Event::CollectionPropertyDeleted(collection.id, key));1261 <PalletEvm<T>>::deposit_log(1262 erc::CollectionHelpersEvents::CollectionChanged {1263 collection_id: eth::collection_id_to_address(collection.id),1264 }1265 .to_log(T::ContractAddress::get()),1266 );1267 }1268 }1269 }12701271 <CollectionProperties<T>>::set(collection.id, stored_properties);12721273 Ok(())1274 }12751276 /// A batch operation to add, edit or remove properties for a token.1277 /// It sets or removes a token's properties according to1278 /// `properties_updates` contents:1279 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1280 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.1281 ///1282 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.1283 /// - `is_token_create`: Indicates that method is called during token initialization.1284 /// Allows to bypass ownership check.1285 ///1286 /// All affected properties should have `mutable` permission1287 /// to be **deleted** or to be **set more than once**,1288 /// and the sender should have permission to edit those properties.1289 ///1290 /// This function fires an event for each property change.1291 /// In case of an error, all the changes (including the events) will be reverted1292 /// since the function is transactional.1293 pub fn modify_token_properties(1294 collection: &CollectionHandle<T>,1295 sender: &T::CrossAccountId,1296 token_id: TokenId,1297 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1298 is_token_create: bool,1299 mut stored_properties: Properties,1300 is_token_owner: impl Fn() -> Result<bool, DispatchError>,1301 set_token_properties: impl FnOnce(Properties),1302 ) -> DispatchResult {1303 let is_collection_admin = collection.is_owner_or_admin(sender);1304 let permissions = Self::property_permissions(collection.id);13051306 let mut token_owner_result = None;1307 let mut is_token_owner = || -> Result<bool, DispatchError> {1308 *token_owner_result.get_or_insert_with(&is_token_owner)1309 };13101311 for (key, value) in properties_updates {1312 let permission = permissions1313 .get(&key)1314 .cloned()1315 .unwrap_or_else(PropertyPermission::none);13161317 let is_property_exists = stored_properties.get(&key).is_some();13181319 match permission {1320 PropertyPermission { mutable: false, .. } if is_property_exists => {1321 return Err(<Error<T>>::NoPermission.into());1322 }13231324 PropertyPermission {1325 collection_admin,1326 token_owner,1327 ..1328 } => {1329 //TODO: investigate threats during public minting.1330 let is_token_create =1331 is_token_create && (collection_admin || token_owner) && value.is_some();1332 if !(is_token_create1333 || (collection_admin && is_collection_admin)1334 || (token_owner && is_token_owner()?))1335 {1336 fail!(<Error<T>>::NoPermission);1337 }1338 }1339 }13401341 match value {1342 Some(value) => {1343 stored_properties1344 .try_set(key.clone(), value)1345 .map_err(<Error<T>>::from)?;13461347 Self::deposit_event(Event::TokenPropertySet(collection.id, token_id, key));1348 }1349 None => {1350 stored_properties.remove(&key).map_err(<Error<T>>::from)?;13511352 Self::deposit_event(Event::TokenPropertyDeleted(collection.id, token_id, key));1353 }1354 }13551356 <PalletEvm<T>>::deposit_log(1357 CollectionHelpersEvents::TokenChanged {1358 collection_id: eth::collection_id_to_address(collection.id),1359 token_id: token_id.into(),1360 }1361 .to_log(T::ContractAddress::get()),1362 );1363 }13641365 set_token_properties(stored_properties);13661367 Ok(())1368 }13691370 /// Sets or unsets the approval of a given operator.1371 ///1372 /// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.1373 /// - `owner`: Token owner1374 /// - `operator`: Operator1375 /// - `approve`: Should operator status be granted or revoked?1376 pub fn set_allowance_for_all(1377 collection: &CollectionHandle<T>,1378 owner: &T::CrossAccountId,1379 operator: &T::CrossAccountId,1380 approve: bool,1381 set_allowance: impl FnOnce(),1382 log: evm_coder::ethereum::Log,1383 ) -> DispatchResult {1384 if collection.permissions.access() == AccessMode::AllowList {1385 collection.check_allowlist(owner)?;1386 collection.check_allowlist(operator)?;1387 }13881389 Self::ensure_correct_receiver(operator)?;13901391 set_allowance();13921393 <PalletEvm<T>>::deposit_log(log);1394 Self::deposit_event(Event::ApprovedForAll(1395 collection.id,1396 owner.clone(),1397 operator.clone(),1398 approve,1399 ));1400 Ok(())1401 }14021403 /// Set collection property.1404 ///1405 /// * `collection` - Collection handler.1406 /// * `sender` - The owner or administrator of the collection.1407 /// * `property` - The property to set.1408 pub fn set_collection_property(1409 collection: &CollectionHandle<T>,1410 sender: &T::CrossAccountId,1411 property: Property,1412 ) -> DispatchResult {1413 Self::set_collection_properties(collection, sender, [property].into_iter())1414 }14151416 /// Set a scoped collection property, where the scope is a special prefix1417 /// prohibiting a user access to change the property directly.1418 ///1419 /// * `collection_id` - ID of the collection for which the property is being set.1420 /// * `scope` - Property scope.1421 /// * `property` - The property to set.1422 pub fn set_scoped_collection_property(1423 collection_id: CollectionId,1424 scope: PropertyScope,1425 property: Property,1426 ) -> DispatchResult {1427 CollectionProperties::<T>::try_mutate(collection_id, |properties| {1428 properties.try_scoped_set(scope, property.key, property.value)1429 })1430 .map_err(<Error<T>>::from)?;14311432 Ok(())1433 }14341435 /// Set scoped collection properties, where the scope is a special prefix1436 /// prohibiting a user access to change the properties directly.1437 ///1438 /// * `collection_id` - ID of the collection for which the properties is being set.1439 /// * `scope` - Property scope.1440 /// * `properties` - The properties to set.1441 pub fn set_scoped_collection_properties(1442 collection_id: CollectionId,1443 scope: PropertyScope,1444 properties: impl Iterator<Item = Property>,1445 ) -> DispatchResult {1446 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1447 stored_properties.try_scoped_set_from_iter(scope, properties)1448 })1449 .map_err(<Error<T>>::from)?;14501451 Ok(())1452 }14531454 /// Set collection properties.1455 ///1456 /// * `collection` - Collection handler.1457 /// * `sender` - The owner or administrator of the collection.1458 /// * `properties` - The properties to set.1459 pub fn set_collection_properties(1460 collection: &CollectionHandle<T>,1461 sender: &T::CrossAccountId,1462 properties: impl Iterator<Item = Property>,1463 ) -> DispatchResult {1464 Self::modify_collection_properties(1465 collection,1466 sender,1467 properties.map(|property| (property.key, Some(property.value))),1468 )1469 }14701471 /// Delete collection property.1472 ///1473 /// * `collection` - Collection handler.1474 /// * `sender` - The owner or administrator of the collection.1475 /// * `property` - The property to delete.1476 pub fn delete_collection_property(1477 collection: &CollectionHandle<T>,1478 sender: &T::CrossAccountId,1479 property_key: PropertyKey,1480 ) -> DispatchResult {1481 Self::delete_collection_properties(collection, sender, [property_key].into_iter())1482 }14831484 /// Delete collection properties.1485 ///1486 /// * `collection` - Collection handler.1487 /// * `sender` - The owner or administrator of the collection.1488 /// * `properties` - The properties to delete.1489 pub fn delete_collection_properties(1490 collection: &CollectionHandle<T>,1491 sender: &T::CrossAccountId,1492 property_keys: impl Iterator<Item = PropertyKey>,1493 ) -> DispatchResult {1494 Self::modify_collection_properties(collection, sender, property_keys.map(|key| (key, None)))1495 }14961497 /// Set collection propetry permission without any checks.1498 ///1499 /// Used for migrations.1500 ///1501 /// * `collection` - Collection handler.1502 /// * `property_permissions` - Property permissions.1503 pub fn set_property_permission_unchecked(1504 collection: CollectionId,1505 property_permission: PropertyKeyPermission,1506 ) -> DispatchResult {1507 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1508 permissions.try_set(property_permission.key, property_permission.permission)1509 })1510 .map_err(<Error<T>>::from)?;1511 Ok(())1512 }15131514 /// Set collection property permission.1515 ///1516 /// * `collection` - Collection handler.1517 /// * `sender` - The owner or administrator of the collection.1518 /// * `property_permission` - Property permission.1519 pub fn set_property_permission(1520 collection: &CollectionHandle<T>,1521 sender: &T::CrossAccountId,1522 property_permission: PropertyKeyPermission,1523 ) -> DispatchResult {1524 Self::set_scoped_property_permission(1525 collection,1526 sender,1527 PropertyScope::None,1528 property_permission,1529 )1530 }15311532 /// Set collection property permission with scope.1533 ///1534 /// * `collection` - Collection handler.1535 /// * `sender` - The owner or administrator of the collection.1536 /// * `scope` - Property scope.1537 /// * `property_permission` - Property permission.1538 pub fn set_scoped_property_permission(1539 collection: &CollectionHandle<T>,1540 sender: &T::CrossAccountId,1541 scope: PropertyScope,1542 property_permission: PropertyKeyPermission,1543 ) -> DispatchResult {1544 collection.check_is_owner_or_admin(sender)?;15451546 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1547 let current_permission = all_permissions.get(&property_permission.key);1548 if matches![1549 current_permission,1550 Some(PropertyPermission { mutable: false, .. })1551 ] {1552 return Err(<Error<T>>::NoPermission.into());1553 }15541555 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1556 let property_permission = property_permission.clone();1557 permissions.try_scoped_set(1558 scope,1559 property_permission.key,1560 property_permission.permission,1561 )1562 })1563 .map_err(<Error<T>>::from)?;15641565 Self::deposit_event(Event::PropertyPermissionSet(1566 collection.id,1567 property_permission.key,1568 ));1569 <PalletEvm<T>>::deposit_log(1570 erc::CollectionHelpersEvents::CollectionChanged {1571 collection_id: eth::collection_id_to_address(collection.id),1572 }1573 .to_log(T::ContractAddress::get()),1574 );15751576 Ok(())1577 }15781579 /// Set token property permission.1580 ///1581 /// * `collection` - Collection handler.1582 /// * `sender` - The owner or administrator of the collection.1583 /// * `property_permissions` - Property permissions.1584 #[transactional]1585 pub fn set_token_property_permissions(1586 collection: &CollectionHandle<T>,1587 sender: &T::CrossAccountId,1588 property_permissions: Vec<PropertyKeyPermission>,1589 ) -> DispatchResult {1590 Self::set_scoped_token_property_permissions(1591 collection,1592 sender,1593 PropertyScope::None,1594 property_permissions,1595 )1596 }15971598 /// Set token property permission with scope.1599 ///1600 /// * `collection` - Collection handler.1601 /// * `sender` - The owner or administrator of the collection.1602 /// * `scope` - Property scope.1603 /// * `property_permissions` - Property permissions.1604 #[transactional]1605 pub fn set_scoped_token_property_permissions(1606 collection: &CollectionHandle<T>,1607 sender: &T::CrossAccountId,1608 scope: PropertyScope,1609 property_permissions: Vec<PropertyKeyPermission>,1610 ) -> DispatchResult {1611 for prop_pemission in property_permissions {1612 Self::set_scoped_property_permission(collection, sender, scope, prop_pemission)?;1613 }16141615 Ok(())1616 }16171618 /// Get collection property.1619 pub fn get_collection_property(1620 collection_id: CollectionId,1621 key: &PropertyKey,1622 ) -> Option<PropertyValue> {1623 Self::collection_properties(collection_id).get(key).cloned()1624 }16251626 /// Convert byte vector to property key vector.1627 pub fn bytes_keys_to_property_keys(1628 keys: Vec<Vec<u8>>,1629 ) -> Result<Vec<PropertyKey>, DispatchError> {1630 keys.into_iter()1631 .map(|key| -> Result<PropertyKey, DispatchError> {1632 key.try_into()1633 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1634 })1635 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1636 }16371638 /// Get properties according to given keys.1639 pub fn filter_collection_properties(1640 collection_id: CollectionId,1641 keys: Option<Vec<PropertyKey>>,1642 ) -> Result<Vec<Property>, DispatchError> {1643 let properties = Self::collection_properties(collection_id);16441645 let properties = keys1646 .map(|keys| {1647 keys.into_iter()1648 .filter_map(|key| {1649 properties.get(&key).map(|value| Property {1650 key,1651 value: value.clone(),1652 })1653 })1654 .collect()1655 })1656 .unwrap_or_else(|| {1657 properties1658 .into_iter()1659 .map(|(key, value)| Property { key, value })1660 .collect()1661 });16621663 Ok(properties)1664 }16651666 /// Get property permissions according to given keys.1667 pub fn filter_property_permissions(1668 collection_id: CollectionId,1669 keys: Option<Vec<PropertyKey>>,1670 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1671 let permissions = Self::property_permissions(collection_id);16721673 let key_permissions = keys1674 .map(|keys| {1675 keys.into_iter()1676 .filter_map(|key| {1677 permissions1678 .get(&key)1679 .map(|permission| PropertyKeyPermission {1680 key,1681 permission: permission.clone(),1682 })1683 })1684 .collect()1685 })1686 .unwrap_or_else(|| {1687 permissions1688 .into_iter()1689 .map(|(key, permission)| PropertyKeyPermission { key, permission })1690 .collect()1691 });16921693 Ok(key_permissions)1694 }16951696 /// Toggle `user` participation in the `collection`'s allow list.1697 /// #### Store read/writes1698 /// 1 writes1699 pub fn toggle_allowlist(1700 collection: &CollectionHandle<T>,1701 sender: &T::CrossAccountId,1702 user: &T::CrossAccountId,1703 allowed: bool,1704 ) -> DispatchResult {1705 collection.check_is_owner_or_admin(sender)?;17061707 // =========17081709 if allowed {1710 <Allowlist<T>>::insert((collection.id, user), true);1711 Self::deposit_event(Event::<T>::AllowListAddressAdded(1712 collection.id,1713 user.clone(),1714 ));1715 } else {1716 <Allowlist<T>>::remove((collection.id, user));1717 Self::deposit_event(Event::<T>::AllowListAddressRemoved(1718 collection.id,1719 user.clone(),1720 ));1721 }17221723 <PalletEvm<T>>::deposit_log(1724 erc::CollectionHelpersEvents::CollectionChanged {1725 collection_id: eth::collection_id_to_address(collection.id),1726 }1727 .to_log(T::ContractAddress::get()),1728 );17291730 Ok(())1731 }17321733 /// Toggle `user` participation in the `collection`'s admin list.1734 /// #### Store read/writes1735 /// 2 reads, 2 writes1736 pub fn toggle_admin(1737 collection: &CollectionHandle<T>,1738 sender: &T::CrossAccountId,1739 user: &T::CrossAccountId,1740 admin: bool,1741 ) -> DispatchResult {1742 collection.check_is_internal()?;1743 collection.check_is_owner(sender)?;17441745 let is_admin = <IsAdmin<T>>::get((collection.id, user));1746 if is_admin == admin {1747 if admin {1748 return Ok(());1749 } else {1750 return Err(Error::<T>::UserIsNotCollectionAdmin.into());1751 }1752 }1753 let amount = <AdminAmount<T>>::get(collection.id);17541755 // =========17561757 if admin {1758 let amount = amount1759 .checked_add(1)1760 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1761 ensure!(1762 amount <= Self::collection_admins_limit(),1763 <Error<T>>::CollectionAdminCountExceeded,1764 );17651766 <AdminAmount<T>>::insert(collection.id, amount);1767 <IsAdmin<T>>::insert((collection.id, user), true);17681769 Self::deposit_event(Event::<T>::CollectionAdminAdded(1770 collection.id,1771 user.clone(),1772 ));1773 } else {1774 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1775 <IsAdmin<T>>::remove((collection.id, user));17761777 Self::deposit_event(Event::<T>::CollectionAdminRemoved(1778 collection.id,1779 user.clone(),1780 ));1781 }17821783 <PalletEvm<T>>::deposit_log(1784 erc::CollectionHelpersEvents::CollectionChanged {1785 collection_id: eth::collection_id_to_address(collection.id),1786 }1787 .to_log(T::ContractAddress::get()),1788 );17891790 Ok(())1791 }17921793 /// Update collection limits.1794 pub fn update_limits(1795 user: &T::CrossAccountId,1796 collection: &mut CollectionHandle<T>,1797 new_limit: CollectionLimits,1798 ) -> DispatchResult {1799 collection.check_is_internal()?;1800 collection.check_is_owner_or_admin(user)?;18011802 collection.limits =1803 Self::clamp_limits(collection.mode.clone(), &collection.limits, new_limit)?;18041805 Self::deposit_event(Event::<T>::CollectionLimitSet(collection.id));1806 <PalletEvm<T>>::deposit_log(1807 erc::CollectionHelpersEvents::CollectionChanged {1808 collection_id: eth::collection_id_to_address(collection.id),1809 }1810 .to_log(T::ContractAddress::get()),1811 );18121813 collection.save()1814 }18151816 /// Merge set fields from `new_limit` to `old_limit`.1817 fn clamp_limits(1818 mode: CollectionMode,1819 old_limit: &CollectionLimits,1820 mut new_limit: CollectionLimits,1821 ) -> Result<CollectionLimits, DispatchError> {1822 let limits = old_limit;1823 limit_default!(old_limit, new_limit,1824 account_token_ownership_limit => ensure!(1825 new_limit <= MAX_TOKEN_OWNERSHIP,1826 <Error<T>>::CollectionLimitBoundsExceeded,1827 ),1828 sponsored_data_size => ensure!(1829 new_limit <= CUSTOM_DATA_LIMIT,1830 <Error<T>>::CollectionLimitBoundsExceeded,1831 ),18321833 sponsored_data_rate_limit => {},1834 token_limit => ensure!(1835 old_limit >= new_limit && new_limit > 0,1836 <Error<T>>::CollectionTokenLimitExceeded1837 ),18381839 sponsor_transfer_timeout(match mode {1840 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1841 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1842 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1843 }) => ensure!(1844 new_limit <= MAX_SPONSOR_TIMEOUT,1845 <Error<T>>::CollectionLimitBoundsExceeded,1846 ),1847 sponsor_approve_timeout => {},1848 owner_can_transfer => ensure!(1849 !limits.owner_can_transfer_instaled() ||1850 old_limit || !new_limit,1851 <Error<T>>::OwnerPermissionsCantBeReverted,1852 ),1853 owner_can_destroy => ensure!(1854 old_limit || !new_limit,1855 <Error<T>>::OwnerPermissionsCantBeReverted,1856 ),1857 transfers_enabled => {},1858 );1859 Ok(new_limit)1860 }18611862 /// Update collection permissions.1863 pub fn update_permissions(1864 user: &T::CrossAccountId,1865 collection: &mut CollectionHandle<T>,1866 new_permission: CollectionPermissions,1867 ) -> DispatchResult {1868 collection.check_is_internal()?;1869 collection.check_is_owner_or_admin(user)?;1870 collection.permissions = Self::clamp_permissions(1871 collection.mode.clone(),1872 &collection.permissions,1873 new_permission,1874 )?;18751876 Self::deposit_event(Event::<T>::CollectionPermissionSet(collection.id));1877 <PalletEvm<T>>::deposit_log(1878 erc::CollectionHelpersEvents::CollectionChanged {1879 collection_id: eth::collection_id_to_address(collection.id),1880 }1881 .to_log(T::ContractAddress::get()),1882 );18831884 collection.save()1885 }18861887 /// Merge set fields from `new_permission` to `old_permission`.1888 fn clamp_permissions(1889 _mode: CollectionMode,1890 old_permission: &CollectionPermissions,1891 mut new_permission: CollectionPermissions,1892 ) -> Result<CollectionPermissions, DispatchError> {1893 limit_default_clone!(old_permission, new_permission,1894 access => {},1895 mint_mode => {},1896 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1897 );1898 Ok(new_permission)1899 }19001901 /// Repair possibly broken properties of a collection.1902 pub fn repair_collection(collection_id: CollectionId) -> DispatchResult {1903 CollectionProperties::<T>::mutate(collection_id, |properties| {1904 properties.recompute_consumed_space();1905 });19061907 Ok(())1908 }1909}19101911/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1912#[macro_export]1913macro_rules! unsupported {1914 ($runtime:path) => {1915 Err($crate::Error::<$runtime>::UnsupportedOperation.into())1916 };1917}19181919/// Return weights for various worst-case operations.1920pub trait CommonWeightInfo<CrossAccountId> {1921 /// Weight of item creation.1922 fn create_item(data: &CreateItemData) -> Weight {1923 Self::create_multiple_items(from_ref(data))1924 }19251926 /// Weight of items creation.1927 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;19281929 /// Weight of items creation.1930 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;19311932 /// The weight of the burning item.1933 fn burn_item() -> Weight;19341935 /// Property setting weight.1936 ///1937 /// * `amount`- The number of properties to set.1938 fn set_collection_properties(amount: u32) -> Weight;19391940 /// Collection property deletion weight.1941 ///1942 /// * `amount`- The number of properties to set.1943 fn delete_collection_properties(amount: u32) -> Weight;19441945 /// Token property setting weight.1946 ///1947 /// * `amount`- The number of properties to set.1948 fn set_token_properties(amount: u32) -> Weight;19491950 /// Token property deletion weight.1951 ///1952 /// * `amount`- The number of properties to delete.1953 fn delete_token_properties(amount: u32) -> Weight;19541955 /// Token property permissions set weight.1956 ///1957 /// * `amount`- The number of property permissions to set.1958 fn set_token_property_permissions(amount: u32) -> Weight;19591960 /// Transfer price of the token or its parts.1961 fn transfer() -> Weight;19621963 /// The price of setting the permission of the operation from another user.1964 fn approve() -> Weight;19651966 /// The price of setting the permission of the operation from another user for eth mirror.1967 fn approve_from() -> Weight;19681969 /// Transfer price from another user.1970 fn transfer_from() -> Weight;19711972 /// The price of burning a token from another user.1973 fn burn_from() -> Weight;19741975 /// Differs from burn_item in case of Fungible and Refungible, as it should burn1976 /// whole users's balance.1977 ///1978 /// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1979 fn burn_recursively_self_raw() -> Weight;19801981 /// Cost of iterating over `amount` children while burning, without counting child burning itself.1982 ///1983 /// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1984 fn burn_recursively_breadth_raw(amount: u32) -> Weight;19851986 /// The price of recursive burning a token.1987 ///1988 /// `max_selfs` - The maximum burning weight of the token itself.1989 /// `max_breadth` - The maximum number of nested tokens to burn.1990 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1991 Self::burn_recursively_self_raw()1992 .saturating_mul(max_selfs.max(1) as u64)1993 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1994 }19951996 /// The price of retrieving token owner1997 fn token_owner() -> Weight;19981999 /// The price of setting approval for all2000 fn set_allowance_for_all() -> Weight;20012002 /// The price of repairing an item.2003 fn force_repair_item() -> Weight;2004}20052006/// Weight info extension trait for refungible pallet.2007pub trait RefungibleExtensionsWeightInfo {2008 /// Weight of token repartition.2009 fn repartition() -> Weight;2010}20112012/// Common collection operations.2013///2014/// It wraps methods in Fungible, Nonfungible and Refungible pallets2015/// and adds weight info.2016pub trait CommonCollectionOperations<T: Config> {2017 /// Create token.2018 ///2019 /// * `sender` - The user who mint the token and pays for the transaction.2020 /// * `to` - The user who will own the token.2021 /// * `data` - Token data.2022 /// * `nesting_budget` - A budget that can be spent on nesting tokens.2023 fn create_item(2024 &self,2025 sender: T::CrossAccountId,2026 to: T::CrossAccountId,2027 data: CreateItemData,2028 nesting_budget: &dyn Budget,2029 ) -> DispatchResultWithPostInfo;20302031 /// Create multiple tokens.2032 ///2033 /// * `sender` - The user who mint the token and pays for the transaction.2034 /// * `to` - The user who will own the token.2035 /// * `data` - Token data.2036 /// * `nesting_budget` - A budget that can be spent on nesting tokens.2037 fn create_multiple_items(2038 &self,2039 sender: T::CrossAccountId,2040 to: T::CrossAccountId,2041 data: Vec<CreateItemData>,2042 nesting_budget: &dyn Budget,2043 ) -> DispatchResultWithPostInfo;20442045 /// Create multiple tokens.2046 ///2047 /// * `sender` - The user who mint the token and pays for the transaction.2048 /// * `to` - The user who will own the token.2049 /// * `data` - Token data.2050 /// * `nesting_budget` - A budget that can be spent on nesting tokens.2051 fn create_multiple_items_ex(2052 &self,2053 sender: T::CrossAccountId,2054 data: CreateItemExData<T::CrossAccountId>,2055 nesting_budget: &dyn Budget,2056 ) -> DispatchResultWithPostInfo;20572058 /// Burn token.2059 ///2060 /// * `sender` - The user who owns the token.2061 /// * `token` - Token id that will burned.2062 /// * `amount` - The number of parts of the token that will be burned.2063 fn burn_item(2064 &self,2065 sender: T::CrossAccountId,2066 token: TokenId,2067 amount: u128,2068 ) -> DispatchResultWithPostInfo;20692070 /// Burn token and all nested tokens recursievly.2071 ///2072 /// * `sender` - The user who owns the token.2073 /// * `token` - Token id that will burned.2074 /// * `self_budget` - The budget that can be spent on burning tokens.2075 /// * `breadth_budget` - The budget that can be spent on burning nested tokens.2076 fn burn_item_recursively(2077 &self,2078 sender: T::CrossAccountId,2079 token: TokenId,2080 self_budget: &dyn Budget,2081 breadth_budget: &dyn Budget,2082 ) -> DispatchResultWithPostInfo;20832084 /// Set collection properties.2085 ///2086 /// * `sender` - Must be either the owner of the collection or its admin.2087 /// * `properties` - Properties to be set.2088 fn set_collection_properties(2089 &self,2090 sender: T::CrossAccountId,2091 properties: Vec<Property>,2092 ) -> DispatchResultWithPostInfo;20932094 /// Delete collection properties.2095 ///2096 /// * `sender` - Must be either the owner of the collection or its admin.2097 /// * `properties` - The properties to be removed.2098 fn delete_collection_properties(2099 &self,2100 sender: &T::CrossAccountId,2101 property_keys: Vec<PropertyKey>,2102 ) -> DispatchResultWithPostInfo;21032104 /// Set token properties.2105 ///2106 /// The appropriate [`PropertyPermission`] for the token property2107 /// must be set with [`Self::set_token_property_permissions`].2108 ///2109 /// * `sender` - Must be either the owner of the token or its admin.2110 /// * `token_id` - The token for which the properties are being set.2111 /// * `properties` - Properties to be set.2112 /// * `budget` - Budget for setting properties.2113 fn set_token_properties(2114 &self,2115 sender: T::CrossAccountId,2116 token_id: TokenId,2117 properties: Vec<Property>,2118 budget: &dyn Budget,2119 ) -> DispatchResultWithPostInfo;21202121 /// Remove token properties.2122 ///2123 /// The appropriate [`PropertyPermission`] for the token property2124 /// must be set with [`Self::set_token_property_permissions`].2125 ///2126 /// * `sender` - Must be either the owner of the token or its admin.2127 /// * `token_id` - The token for which the properties are being remove.2128 /// * `property_keys` - Keys to remove corresponding properties.2129 /// * `budget` - Budget for removing properties.2130 fn delete_token_properties(2131 &self,2132 sender: T::CrossAccountId,2133 token_id: TokenId,2134 property_keys: Vec<PropertyKey>,2135 budget: &dyn Budget,2136 ) -> DispatchResultWithPostInfo;21372138 /// Set token property permissions.2139 ///2140 /// * `sender` - Must be either the owner of the token or its admin.2141 /// * `token_id` - The token for which the properties are being set.2142 /// * `property_permissions` - Property permissions to be set.2143 /// * `budget` - Budget for setting properties.2144 fn set_token_property_permissions(2145 &self,2146 sender: &T::CrossAccountId,2147 property_permissions: Vec<PropertyKeyPermission>,2148 ) -> DispatchResultWithPostInfo;21492150 /// Transfer amount of token pieces.2151 ///2152 /// * `sender` - Donor user.2153 /// * `to` - Recepient user.2154 /// * `token` - The token of which parts are being sent.2155 /// * `amount` - The number of parts of the token that will be transferred.2156 /// * `budget` - The maximum budget that can be spent on the transfer.2157 fn transfer(2158 &self,2159 sender: T::CrossAccountId,2160 to: T::CrossAccountId,2161 token: TokenId,2162 amount: u128,2163 budget: &dyn Budget,2164 ) -> DispatchResultWithPostInfo;21652166 /// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].2167 ///2168 /// * `sender` - The user who grants access to the token.2169 /// * `spender` - The user to whom the rights are granted.2170 /// * `token` - The token to which access is granted.2171 /// * `amount` - The amount of pieces that another user can dispose of.2172 fn approve(2173 &self,2174 sender: T::CrossAccountId,2175 spender: T::CrossAccountId,2176 token: TokenId,2177 amount: u128,2178 ) -> DispatchResultWithPostInfo;21792180 /// Grant access to another account to transfer parts of the token owned by the calling user's eth mirror via [Self::transfer_from].2181 ///2182 /// * `sender` - The user who grants access to the token.2183 /// * `from` - Spender's eth mirror.2184 /// * `to` - The user to whom the rights are granted.2185 /// * `token` - The token to which access is granted.2186 /// * `amount` - The amount of pieces that another user can dispose of.2187 fn approve_from(2188 &self,2189 sender: T::CrossAccountId,2190 from: T::CrossAccountId,2191 to: T::CrossAccountId,2192 token: TokenId,2193 amount: u128,2194 ) -> DispatchResultWithPostInfo;21952196 /// Send parts of a token owned by another user.2197 ///2198 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2199 ///2200 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).2201 /// * `from` - The user who owns the token.2202 /// * `to` - Recepient user.2203 /// * `token` - The token of which parts are being sent.2204 /// * `amount` - The number of parts of the token that will be transferred.2205 /// * `budget` - The maximum budget that can be spent on the transfer.2206 fn transfer_from(2207 &self,2208 sender: T::CrossAccountId,2209 from: T::CrossAccountId,2210 to: T::CrossAccountId,2211 token: TokenId,2212 amount: u128,2213 budget: &dyn Budget,2214 ) -> DispatchResultWithPostInfo;22152216 /// Burn parts of a token owned by another user.2217 ///2218 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2219 ///2220 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).2221 /// * `from` - The user who owns the token.2222 /// * `token` - The token of which parts are being sent.2223 /// * `amount` - The number of parts of the token that will be transferred.2224 /// * `budget` - The maximum budget that can be spent on the burn.2225 fn burn_from(2226 &self,2227 sender: T::CrossAccountId,2228 from: T::CrossAccountId,2229 token: TokenId,2230 amount: u128,2231 budget: &dyn Budget,2232 ) -> DispatchResultWithPostInfo;22332234 /// Check permission to nest token.2235 ///2236 /// * `sender` - The user who initiated the check.2237 /// * `from` - The token that is checked for embedding.2238 /// * `under` - Token under which to check.2239 /// * `budget` - The maximum budget that can be spent on the check.2240 fn check_nesting(2241 &self,2242 sender: T::CrossAccountId,2243 from: (CollectionId, TokenId),2244 under: TokenId,2245 budget: &dyn Budget,2246 ) -> DispatchResult;22472248 /// Nest one token into another.2249 ///2250 /// * `under` - Token holder.2251 /// * `to_nest` - Nested token.2252 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));22532254 /// Unnest token.2255 ///2256 /// * `under` - Token holder.2257 /// * `to_nest` - Token to unnest.2258 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));22592260 /// Get all user tokens.2261 ///2262 /// * `account` - Account for which you need to get tokens.2263 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;22642265 /// Get all the tokens in the collection.2266 fn collection_tokens(&self) -> Vec<TokenId>;22672268 /// Check if the token exists.2269 ///2270 /// * `token` - Id token to check.2271 fn token_exists(&self, token: TokenId) -> bool;22722273 /// Get the id of the last minted token.2274 fn last_token_id(&self) -> TokenId;22752276 /// Get the owner of the token.2277 ///2278 /// * `token` - The token for which you need to find out the owner.2279 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError>;22802281 /// Returns 10 tokens owners in no particular order.2282 ///2283 /// * `token` - The token for which you need to find out the owners.2284 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;22852286 /// Get the value of the token property by key.2287 ///2288 /// * `token` - Token with the property to get.2289 /// * `key` - Property name.2290 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;22912292 /// Get a set of token properties by key vector.2293 ///2294 /// * `token` - Token with the property to get.2295 /// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),2296 /// then all properties are returned.2297 fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;22982299 /// Amount of unique collection tokens2300 fn total_supply(&self) -> u32;23012302 /// Amount of different tokens account has.2303 ///2304 /// * `account` - The account for which need to get the balance.2305 fn account_balance(&self, account: T::CrossAccountId) -> u32;23062307 /// Amount of specific token account have.2308 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;23092310 /// Amount of token pieces2311 fn total_pieces(&self, token: TokenId) -> Option<u128>;23122313 /// Get the number of parts of the token that a trusted user can manage.2314 ///2315 /// * `sender` - Trusted user.2316 /// * `spender` - Owner of the token.2317 /// * `token` - The token for which to get the value.2318 fn allowance(2319 &self,2320 sender: T::CrossAccountId,2321 spender: T::CrossAccountId,2322 token: TokenId,2323 ) -> u128;23242325 /// Get extension for RFT collection.2326 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;23272328 /// The `operator` is allowed to transfer all tokens of the `owner` on their behalf.2329 /// * `owner` - Token owner2330 /// * `operator` - Operator2331 /// * `approve` - Should operator status be granted or revoked?2332 fn set_allowance_for_all(2333 &self,2334 owner: T::CrossAccountId,2335 operator: T::CrossAccountId,2336 approve: bool,2337 ) -> DispatchResultWithPostInfo;23382339 /// Tells whether the given `owner` approves the `operator`.2340 fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;23412342 /// Repairs a possibly broken item.2343 fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo;2344}23452346/// Extension for RFT collection.2347pub trait RefungibleExtensions<T>2348where2349 T: Config,2350{2351 /// Change the number of parts of the token.2352 ///2353 /// When the value changes down, this function is equivalent to burning parts of the token.2354 ///2355 /// * `sender` - The user calling the repartition operation. Must be the owner of the token.2356 /// * `token` - The token for which you want to change the number of parts.2357 /// * `amount` - The new value of the parts of the token.2358 fn repartition(2359 &self,2360 sender: &T::CrossAccountId,2361 token: TokenId,2362 amount: u128,2363 ) -> DispatchResultWithPostInfo;2364}23652366/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].2367///2368/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.2369pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {2370 let post_info = PostDispatchInfo {2371 actual_weight: Some(weight),2372 pays_fee: Pays::Yes,2373 };2374 match res {2375 Ok(()) => Ok(post_info),2376 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),2377 }2378}23792380impl<T: Config> From<PropertiesError> for Error<T> {2381 fn from(error: PropertiesError) -> Self {2382 match error {2383 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,2384 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,2385 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,2386 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,2387 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,2388 }2389 }2390}pallets/evm-coder-substrate/Cargo.tomldiffbeforeafterboth--- a/pallets/evm-coder-substrate/Cargo.toml
+++ b/pallets/evm-coder-substrate/Cargo.toml
@@ -7,10 +7,11 @@
[dependencies]
# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.
codec = { workspace = true, package = "parity-scale-codec" }
-
scale-info = { workspace = true }
evm-coder = { workspace = true }
+evm-core = { workspace = true }
+
frame-benchmarking = { workspace = true, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
@@ -19,6 +20,9 @@
sp-std = { workspace = true }
up-data-structs = { workspace = true }
+evm-coder-substrate-procedural = { path = "./procedural" }
+spez = "0.1.1"
+
[features]
default = ["std"]
runtime-benchmarks = ['frame-benchmarking']
pallets/evm-coder-substrate/procedural/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/pallets/evm-coder-substrate/procedural/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+edition = "2021"
+name = "evm-coder-substrate-procedural"
+version = "0.1.0"
+
+[dependencies]
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = "1.0"
+
+[lib]
+proc-macro = true
pallets/evm-coder-substrate/procedural/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/evm-coder-substrate/procedural/src/lib.rs
@@ -0,0 +1,135 @@
+use std::result;
+
+use proc_macro2::{TokenStream, Ident};
+use quote::quote;
+use syn::{
+ Error, DeriveInput, Data, Attribute,
+ parse::{Parse, ParseBuffer},
+ spanned::Spanned,
+ Expr, parenthesized,
+};
+
+type Result<T = TokenStream, E = syn::Error> = result::Result<T, E>;
+
+fn parse_attr<A: Parse, I>(attrs: &[Attribute], ident: I) -> Result<Option<A>>
+where
+ Ident: PartialEq<I>,
+{
+ let attrs = attrs
+ .iter()
+ .filter(|a| a.path.is_ident(&ident))
+ .collect::<Vec<_>>();
+ if attrs.len() > 1 {
+ return Err(Error::new(
+ attrs[1].span(),
+ "this attribute may be specified only once",
+ ));
+ } else if attrs.is_empty() {
+ return Ok(None);
+ }
+ let attr = attrs[0];
+
+ let parsed = syn::parse2(attr.tokens.clone())?;
+ Ok(Some(parsed))
+}
+
+struct WeightAttr {
+ handler: Expr,
+}
+impl Parse for WeightAttr {
+ fn parse(input: &ParseBuffer) -> Result<Self> {
+ let expr;
+ parenthesized!(expr in input);
+ let handler = Expr::parse(&expr)?;
+
+ Ok(Self { handler })
+ }
+}
+
+#[proc_macro_derive(PreDispatch, attributes(pre_dispatch, weight))]
+pub fn derive_predispatch(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ fn inner(input: DeriveInput) -> Result {
+ let (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl();
+ let ident = &input.ident;
+ let Data::Enum(data) = &input.data else {
+ return Err(Error::new_spanned(input, "PreDispatch input is enum"))
+ };
+
+ let matching = data
+ .variants
+ .iter()
+ .map(|var| {
+ let name = &var.ident;
+ let handler = match &var.fields {
+ syn::Fields::Named(named) => {
+ if let Some(weight) = parse_attr::<WeightAttr, _>(&var.attrs, "weight")? {
+ let weight = &weight.handler;
+ let fields = named.named.iter().flat_map(|n| &n.ident);
+ quote! {
+ {#(#fields,)*} => {
+ ::pallet_evm_coder_substrate::execution::DispatchInfo {
+ weight: ::pallet_evm_coder_substrate::execution::Weight::from(#weight),
+ }
+ }
+ }
+ } else {
+ quote! {
+ {..} => {
+ ::pallet_evm_coder_substrate::execution::DispatchInfo {
+ weight: ::pallet_evm_coder_substrate::execution::Weight::zero()
+ }
+ }
+ }
+ }
+ }
+ syn::Fields::Unit => {
+ if let Some(weight) = parse_attr::<WeightAttr, _>(&var.attrs, "weight")? {
+ let weight = &weight.handler;
+ quote! {
+ => {
+ ::pallet_evm_coder_substrate::execution::DispatchInfo {
+ weight: ::pallet_evm_coder_substrate::execution::Weight::from(#weight),
+ }
+ }
+ }
+ } else {
+ quote! {
+ => {
+ ::pallet_evm_coder_substrate::execution::DispatchInfo {
+ weight: ::pallet_evm_coder_substrate::execution::Weight::zero()
+ }
+ }
+ }
+ }
+ }
+ syn::Fields::Unnamed(_) => {
+ quote! {
+ (call, ..) => {
+ call.dispatch_info()
+ }
+ }
+ }
+ };
+ Ok(quote! {
+ Self::#name #handler,
+ })
+ })
+ .collect::<Result>()?;
+
+ Ok(quote! {
+ #[allow(unused_variables)]
+ impl #impl_generics ::pallet_evm_coder_substrate::execution::PreDispatch for #ident #ty_generics where T: crate::Config {
+ fn dispatch_info(&self) -> ::pallet_evm_coder_substrate::execution::DispatchInfo {
+ match self {
+ #matching
+ }
+ }
+ }
+ })
+ }
+ let item = syn::parse_macro_input!(item as DeriveInput);
+ match inner(item) {
+ Ok(o) => o.into(),
+ Err(e) => e.into_compile_error().into(),
+ }
+}
pallets/evm-coder-substrate/src/execution.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/evm-coder-substrate/src/execution.rs
@@ -0,0 +1,186 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+//! Contract execution related types
+
+#[cfg(not(feature = "std"))]
+use alloc::string::{String, ToString};
+#[cfg(feature = "std")]
+use std::string::{String, ToString};
+
+use evm_coder::ERC165Call;
+use evm_core::{ExitError, ExitFatal};
+
+pub use frame_support::weights::Weight;
+pub use evm_coder_substrate_procedural::PreDispatch;
+
+/// Execution error, should be convertible between EVM and Substrate.
+#[derive(Debug, Clone)]
+pub enum Error {
+ /// Non-fatal contract error occured
+ Revert(String),
+ /// EVM fatal error
+ Fatal(ExitFatal),
+ /// EVM normal error
+ Error(ExitError),
+}
+
+impl<E> From<E> for Error
+where
+ E: ToString,
+{
+ fn from(e: E) -> Self {
+ Self::Revert(e.to_string())
+ }
+}
+
+/// To be used in [`crate::solidity_interface`] implementation.
+pub type Result<T> = core::result::Result<T, Error>;
+/// Return type of items in [`crate::solidity_interface`] definition
+pub type ResultWithPostInfo<T> =
+ core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;
+
+pub trait PreDispatch {
+ fn dispatch_info(&self) -> DispatchInfo;
+}
+
+impl PreDispatch for ERC165Call {
+ fn dispatch_info(&self) -> DispatchInfo {
+ DispatchInfo {
+ // ERC165 impl should be cheap
+ weight: Weight::from_ref_time(200),
+ }
+ }
+}
+
+/// Static information collected from [`crate::weight`].
+pub struct DispatchInfo {
+ /// Statically predicted call weight
+ pub weight: Weight,
+}
+
+impl From<Weight> for DispatchInfo {
+ fn from(weight: Weight) -> Self {
+ Self { weight }
+ }
+}
+impl From<u64> for DispatchInfo {
+ fn from(weight: u64) -> Self {
+ Self {
+ weight: Weight::from_ref_time(weight),
+ }
+ }
+}
+impl From<()> for DispatchInfo {
+ fn from(_: ()) -> Self {
+ Self {
+ weight: Weight::zero(),
+ }
+ }
+}
+
+/// Weight information that is only available post dispatch.
+/// Note: This can only be used to reduce the weight or fee, not increase it.
+#[derive(Default, Clone)]
+pub struct PostDispatchInfo {
+ /// Actual weight consumed by call
+ pub actual_weight: Option<Weight>,
+}
+
+impl PostDispatchInfo {
+ /// Calculate amount to be returned back to user
+ pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
+ info.weight - self.calc_actual_weight(info)
+ }
+
+ /// Calculate actual consumed weight, saturating to weight reported
+ /// pre-dispatch
+ pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
+ if let Some(actual_weight) = self.actual_weight {
+ actual_weight.min(info.weight)
+ } else {
+ info.weight
+ }
+ }
+}
+
+/// Wrapper for PostDispatchInfo and any user-provided data
+#[derive(Clone)]
+pub struct WithPostDispatchInfo<T> {
+ /// User provided data
+ pub data: T,
+ /// Info known after dispatch
+ pub post_info: PostDispatchInfo,
+}
+
+impl<T> From<T> for WithPostDispatchInfo<T> {
+ fn from(data: T) -> Self {
+ Self {
+ data,
+ post_info: Default::default(),
+ }
+ }
+}
+#[allow(clippy::crate_in_macro_def)]
+#[macro_export]
+macro_rules! frontier_contract {
+ (
+ macro_rules! $res:ident {...}
+ impl$(<$($gen:ident $(: $($(+)? $bound:ty)*)?),+ $(,)?>)? Contract for $ty:ty {...}
+ ) => {
+ /// Generate macro to convert function return value into Contract result
+ macro_rules! $res {
+ ($i:expr) => {{
+ pallet_evm_coder_substrate::spez! {
+ for res = $i;
+ match<T> ::pallet_evm_coder_substrate::execution::ResultWithPostInfo<T> -> ::pallet_evm_coder_substrate::execution::ResultWithPostInfo<T> {
+ res
+ }
+ match<T> ::pallet_evm_coder_substrate::execution::Result<T> -> ::pallet_evm_coder_substrate::execution::ResultWithPostInfo<T> {
+ res
+ .map(pallet_evm_coder_substrate::execution::WithPostDispatchInfo::from)
+ .map_err(pallet_evm_coder_substrate::execution::WithPostDispatchInfo::from)
+ }
+ match<T> T -> ::pallet_evm_coder_substrate::execution::ResultWithPostInfo<T> {
+ Ok(pallet_evm_coder_substrate::execution::WithPostDispatchInfo::from(res))
+ }
+ }
+ }};
+ }
+ impl $(<$($gen),+>)? $crate::Contract for $ty where T: crate::Config {
+ type Error = ::pallet_evm_coder_substrate::execution::Error;
+ type WithPostInfo<R> = ::pallet_evm_coder_substrate::execution::WithPostDispatchInfo<R>;
+ type Result<R, E> = core::result::Result<R, E>;
+ fn map_post<I, O>(
+ v: Self::WithPostInfo<I>,
+ mapper: impl FnOnce(I) -> O,
+ ) -> Self::WithPostInfo<O> {
+ ::pallet_evm_coder_substrate::execution::WithPostDispatchInfo {
+ data: mapper(v.data),
+ post_info: v.post_info,
+ }
+ }
+ fn with_default_post<V>(v: V) -> Self::WithPostInfo<V> {
+ ::pallet_evm_coder_substrate::execution::WithPostDispatchInfo {
+ data: v,
+ post_info: ::pallet_evm_coder_substrate::execution::PostDispatchInfo {
+ actual_weight: None,
+ },
+ }
+ }
+ }
+ };
+}
pallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-coder-substrate/src/lib.rs
+++ b/pallets/evm-coder-substrate/src/lib.rs
@@ -16,10 +16,13 @@
#![cfg_attr(not(feature = "std"), no_std)]
+extern crate self as pallet_evm_coder_substrate;
+
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::format;
+use execution::PreDispatch;
use frame_support::dispatch::Weight;
use core::marker::PhantomData;
@@ -37,10 +40,14 @@
use sp_core::H160;
// #[cfg(feature = "runtime-benchmarks")]
// pub mod benchmarking;
+pub mod execution;
+pub use evm_coder::*;
+#[doc(hidden)]
+pub use spez::spez;
+
use evm_coder::{
abi::{AbiReader, AbiWrite, AbiWriter},
- execution,
types::{Msg, Value},
};
@@ -175,7 +182,7 @@
handle: &mut impl PrecompileHandle,
result: execution::Result<Option<AbiWriter>>,
) -> Option<PrecompileResult> {
- use evm_coder::execution::Error;
+ use execution::Error;
// We ignore error here, as it should not occur, as we have our own bookkeeping of gas
let _ = handle.record_cost(self.initial_gas - self.gas_left());
Some(match result {
@@ -200,7 +207,7 @@
}
pub fn dispatch_to_evm<T: Config>(err: DispatchError) -> execution::Error {
- use evm_coder::execution::Error as ExError;
+ use execution::Error as ExError;
match err {
DispatchError::Module(ModuleError { index, error, .. })
if index
@@ -231,15 +238,14 @@
}
/// Helper to simplify implementing bridge between evm-coder definitions and pallet-evm
-pub fn call<
+pub fn call<T, C, E, H>(handle: &mut H, mut e: E) -> Option<PrecompileResult>
+where
T: Config,
- C: evm_coder::Call + evm_coder::Weighted,
+ C: evm_coder::Call + PreDispatch,
E: evm_coder::Callable<C> + WithRecorder<T>,
H: PrecompileHandle,
->(
- handle: &mut H,
- mut e: E,
-) -> Option<PrecompileResult> {
+ execution::ResultWithPostInfo<AbiWriter>: From<ResultWithPostInfoOf<E, AbiWriter>>,
+{
let result = call_internal(
handle.context().caller,
&mut e,
@@ -249,16 +255,18 @@
e.into_recorder().evm_to_precompile_output(handle, result)
}
-fn call_internal<
- T: Config,
- C: evm_coder::Call + evm_coder::Weighted,
- E: evm_coder::Callable<C> + WithRecorder<T>,
->(
+fn call_internal<T, C, E>(
caller: H160,
e: &mut E,
value: Value,
input: &[u8],
-) -> execution::Result<Option<AbiWriter>> {
+) -> execution::Result<Option<AbiWriter>>
+where
+ T: Config,
+ C: evm_coder::Call + PreDispatch,
+ E: Contract + evm_coder::Callable<C> + WithRecorder<T>,
+ execution::ResultWithPostInfo<AbiWriter>: From<ResultWithPostInfoOf<E, AbiWriter>>,
+{
let (selector, mut reader) = AbiReader::new_call(input)?;
let call = C::parse(selector, &mut reader)?;
if call.is_none() {
@@ -267,15 +275,15 @@
}
let call = call.unwrap();
- let dispatch_info = call.weight();
+ let dispatch_info = call.dispatch_info();
e.recorder()
.consume_gas(T::GasWeightMapping::weight_to_gas(dispatch_info.weight))?;
- match e.call(Msg {
+ match execution::ResultWithPostInfo::from(e.call(Msg {
call,
caller,
value,
- }) {
+ })) {
Ok(v) => {
let unspent = v.post_info.calc_unspent(&dispatch_info);
e.recorder()
@@ -290,3 +298,26 @@
}
}
}
+
+#[cfg(test)]
+#[allow(dead_code)]
+mod tests {
+ use core::marker::PhantomData;
+
+ use evm_coder::ERC165Call;
+ use frame_support::weights::Weight;
+
+ use crate::execution::PreDispatch;
+
+ #[derive(PreDispatch)]
+ enum ExampleCall<T: super::Config> {
+ ERC165Call(ERC165Call, PhantomData<fn() -> T>),
+ OtherCall(ERC165Call),
+
+ #[weight(Weight::from_ref_time(a + b))]
+ Example {
+ a: u64,
+ b: u64,
+ },
+ }
+}
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -20,7 +20,6 @@
use core::marker::PhantomData;
use evm_coder::{
abi::{AbiWriter, AbiType},
- execution::Result,
generate_stubgen, solidity_interface,
types::*,
ToLog,
@@ -30,7 +29,11 @@
ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,
account::CrossAccountId,
};
-use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder, dispatch_to_evm};
+use pallet_evm_coder_substrate::{
+ SubstrateRecorder, WithRecorder, dispatch_to_evm,
+ execution::{Result, PreDispatch},
+ frontier_contract,
+};
use pallet_evm_transaction_payment::CallContext;
use sp_core::{H160, U256};
use up_data_structs::SponsorshipState;
@@ -42,6 +45,11 @@
use up_sponsorship::SponsorshipHandler;
use sp_std::vec::Vec;
+frontier_contract! {
+ macro_rules! ContractHelpers_result {...}
+ impl<T: Config> Contract for ContractHelpers<T> {...}
+}
+
/// Pallet events.
#[derive(ToLog)]
pub enum ContractHelpersEvents {
@@ -84,7 +92,7 @@
}
/// @title Magic contract, which allows users to reconfigure other contracts
-#[solidity_interface(name = ContractHelpers, events(ContractHelpersEvents))]
+#[solidity_interface(name = ContractHelpers, events(ContractHelpersEvents), enum(derive(PreDispatch)))]
impl<T: Config> ContractHelpers<T>
where
T::AccountId: AsRef<[u8; 32]>,
pallets/fungible/src/erc.rsdiffbeforeafterboth--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -20,10 +20,7 @@
use core::char::{REPLACEMENT_CHARACTER, decode_utf16};
use core::convert::TryInto;
use evm_coder::AbiCoder;
-use evm_coder::{
- abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*,
- weight,
-};
+use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};
use up_data_structs::CollectionMode;
use pallet_common::{
CollectionHandle,
@@ -32,7 +29,11 @@
};
use sp_std::vec::Vec;
use pallet_evm::{account::CrossAccountId, PrecompileHandle};
-use pallet_evm_coder_substrate::{call, dispatch_to_evm};
+use pallet_evm_coder_substrate::{
+ call, dispatch_to_evm,
+ execution::{PreDispatch, Result},
+ frontier_contract,
+};
use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
use sp_core::{U256, Get};
@@ -41,6 +42,11 @@
weights::WeightInfo,
};
+frontier_contract! {
+ macro_rules! FungibleHandle_result {...}
+ impl<T: Config> Contract for FungibleHandle<T> {...}
+}
+
#[derive(ToLog)]
pub enum ERC20Events {
Transfer {
@@ -65,7 +71,7 @@
amount: U256,
}
-#[solidity_interface(name = ERC20, events(ERC20Events), expect_selector = 0x942e8b22)]
+#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]
impl<T: Config> FungibleHandle<T> {
fn name(&self) -> Result<String> {
Ok(decode_utf16(self.name.iter().copied())
@@ -145,7 +151,7 @@
}
}
-#[solidity_interface(name = ERC20Mintable)]
+#[solidity_interface(name = ERC20Mintable, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> FungibleHandle<T> {
/// Mint tokens for `to` account.
/// @param to account that will receive minted tokens
@@ -158,13 +164,13 @@
let budget = self
.recorder
.weight_calls_budget(<StructureWeight<T>>::find_parent());
- <Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)
+ <Pallet<T>>::create_item(self, &caller, (to, amount), &budget)
.map_err(dispatch_to_evm::<T>)?;
Ok(true)
}
}
-#[solidity_interface(name = ERC20UniqueExtensions)]
+#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> FungibleHandle<T>
where
T::AccountId: From<[u8; 32]>,
@@ -181,10 +187,10 @@
}
/// @notice A description for the collection.
- fn description(&self) -> Result<String> {
- Ok(decode_utf16(self.description.iter().copied())
+ fn description(&self) -> String {
+ decode_utf16(self.description.iter().copied())
.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
- .collect::<String>())
+ .collect::<String>()
}
#[weight(<SelfWeightOf<T>>::create_item())]
@@ -278,7 +284,7 @@
})
.collect::<Result<_>>()?;
- <Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)
+ <Pallet<T>>::create_multiple_items(self, &caller, amounts, &budget)
.map_err(dispatch_to_evm::<T>)?;
Ok(true)
}
@@ -330,7 +336,8 @@
ERC20Mintable,
ERC20UniqueExtensions,
Collection(via(common_mut returns CollectionHandle<T>)),
- )
+ ),
+ enum(derive(PreDispatch))
)]
impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -24,16 +24,16 @@
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
};
-use evm_coder::{
- abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*,
- weight,
-};
+use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};
use frame_support::BoundedVec;
use up_data_structs::{
TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey,
CollectionPropertiesVec,
};
-use pallet_evm_coder_substrate::dispatch_to_evm;
+use pallet_evm_coder_substrate::{
+ dispatch_to_evm, frontier_contract,
+ execution::{Result, PreDispatch, Error},
+};
use sp_std::{vec::Vec, vec};
use pallet_common::{
CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
@@ -50,8 +50,13 @@
SelfWeightOf, weights::WeightInfo, TokenProperties,
};
+frontier_contract! {
+ macro_rules! NonfungibleHandle_result {...}
+ impl<T: Config> Contract for NonfungibleHandle<T> {...}
+}
+
/// @title A contract that allows to set and delete token properties and change token property permissions.
-#[solidity_interface(name = TokenProperties)]
+#[solidity_interface(name = TokenProperties, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> NonfungibleHandle<T> {
/// @notice Set permissions for token property.
/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
@@ -59,8 +64,8 @@
/// @param isMutable Permission to mutate property.
/// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
/// @param tokenOwner Permission to mutate property by token owner if property is mutable.
+ #[solidity(hide)]
#[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]
- #[solidity(hide)]
fn set_token_property_permission(
&mut self,
caller: Caller,
@@ -293,7 +298,7 @@
/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
-#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)]
+#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> NonfungibleHandle<T>
where
T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
@@ -301,14 +306,14 @@
/// @notice A descriptive name for a collection of NFTs in this contract
/// @dev real implementation of this function lies in `ERC721UniqueExtensions`
#[solidity(hide, rename_selector = "name")]
- fn name_proxy(&self) -> Result<String> {
+ fn name_proxy(&self) -> String {
self.name()
}
/// @notice An abbreviated name for NFTs in this contract
/// @dev real implementation of this function lies in `ERC721UniqueExtensions`
#[solidity(hide, rename_selector = "symbol")]
- fn symbol_proxy(&self) -> Result<String> {
+ fn symbol_proxy(&self) -> String {
self.symbol()
}
@@ -362,14 +367,14 @@
/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
-#[solidity_interface(name = ERC721Enumerable, expect_selector = 0x780e9d63)]
+#[solidity_interface(name = ERC721Enumerable, expect_selector = 0x780e9d63, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> NonfungibleHandle<T> {
/// @notice Enumerate valid NFTs
/// @param index A counter less than `totalSupply()`
/// @return The token identifier for the `index`th NFT,
/// (sort order not specified)
- fn token_by_index(&self, index: U256) -> Result<U256> {
- Ok(index)
+ fn token_by_index(&self, index: U256) -> U256 {
+ index
}
/// @dev Not implemented
@@ -389,7 +394,7 @@
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-#[solidity_interface(name = ERC721, events(ERC721Events), expect_selector = 0x80ac58cd)]
+#[solidity_interface(name = ERC721, events(ERC721Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x80ac58cd)]
impl<T: Config> NonfungibleHandle<T> {
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
@@ -516,7 +521,7 @@
}
/// @title ERC721 Token that can be irreversibly burned (destroyed).
-#[solidity_interface(name = ERC721Burnable)]
+#[solidity_interface(name = ERC721Burnable, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> NonfungibleHandle<T> {
/// @notice Burns a specific ERC721 token.
/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
@@ -533,7 +538,7 @@
}
/// @title ERC721 minting logic.
-#[solidity_interface(name = ERC721UniqueMintable)]
+#[solidity_interface(name = ERC721UniqueMintable, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> NonfungibleHandle<T> {
/// @notice Function to mint a token.
/// @param to The new owner
@@ -698,28 +703,28 @@
}
/// @title Unique extensions for ERC721.
-#[solidity_interface(name = ERC721UniqueExtensions)]
+#[solidity_interface(name = ERC721UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> NonfungibleHandle<T>
where
T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
{
/// @notice A descriptive name for a collection of NFTs in this contract
- fn name(&self) -> Result<String> {
- Ok(decode_utf16(self.name.iter().copied())
+ fn name(&self) -> String {
+ decode_utf16(self.name.iter().copied())
.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
- .collect::<String>())
+ .collect::<String>()
}
/// @notice An abbreviated name for NFTs in this contract
- fn symbol(&self) -> Result<String> {
- Ok(String::from_utf8_lossy(&self.token_prefix).into())
+ fn symbol(&self) -> String {
+ String::from_utf8_lossy(&self.token_prefix).into()
}
/// @notice A description for the collection.
- fn description(&self) -> Result<String> {
- Ok(decode_utf16(self.description.iter().copied())
+ fn description(&self) -> String {
+ decode_utf16(self.description.iter().copied())
.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
- .collect::<String>())
+ .collect::<String>()
}
/// Returns the owner (in cross format) of the token.
@@ -1035,8 +1040,8 @@
}
/// @notice Returns collection helper contract address
- fn collection_helper_address(&self) -> Result<Address> {
- Ok(T::ContractAddress::get())
+ fn collection_helper_address(&self) -> Address {
+ T::ContractAddress::get()
}
}
@@ -1051,7 +1056,8 @@
ERC721Metadata(if(this.flags.erc721metadata)),
Collection(via(common_mut returns CollectionHandle<T>)),
TokenProperties,
- )
+ ),
+ enum(derive(PreDispatch)),
)]
impl<T: Config> NonfungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}
pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -25,10 +25,7 @@
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
};
-use evm_coder::{
- abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*,
- weight,
-};
+use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};
use frame_support::{BoundedBTreeMap, BoundedVec};
use pallet_common::{
CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
@@ -37,7 +34,11 @@
eth::{self, TokenUri},
};
use pallet_evm::{account::CrossAccountId, PrecompileHandle};
-use pallet_evm_coder_substrate::{call, dispatch_to_evm};
+use pallet_evm_coder_substrate::{
+ call, dispatch_to_evm,
+ execution::{PreDispatch, Result, Error},
+ frontier_contract,
+};
use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
use sp_core::{H160, U256, Get};
use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec};
@@ -51,10 +52,15 @@
TokenProperties, TokensMinted, TotalSupply, weights::WeightInfo,
};
+frontier_contract! {
+ macro_rules! RefungibleHandle_result {...}
+ impl<T: Config> Contract for RefungibleHandle<T> {...}
+}
+
pub const ADDRESS_FOR_PARTIALLY_OWNED_TOKENS: H160 = H160::repeat_byte(0xff);
/// @title A contract that allows to set and delete token properties and change token property permissions.
-#[solidity_interface(name = TokenProperties)]
+#[solidity_interface(name = TokenProperties, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> RefungibleHandle<T> {
/// @notice Set permissions for token property.
/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
@@ -62,8 +68,8 @@
/// @param isMutable Permission to mutate property.
/// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
/// @param tokenOwner Permission to mutate property by token owner if property is mutable.
+ #[solidity(hide)]
#[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]
- #[solidity(hide)]
fn set_token_property_permission(
&mut self,
caller: Caller,
@@ -290,7 +296,7 @@
/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
-#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)]
+#[solidity_interface(name = ERC721Metadata, enum(derive(PreDispatch)), expect_selector = 0x5b5e139f)]
impl<T: Config> RefungibleHandle<T>
where
T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
@@ -359,14 +365,14 @@
/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
-#[solidity_interface(name = ERC721Enumerable, expect_selector = 0x780e9d63)]
+#[solidity_interface(name = ERC721Enumerable, enum(derive(PreDispatch)), expect_selector = 0x780e9d63)]
impl<T: Config> RefungibleHandle<T> {
/// @notice Enumerate valid RFTs
/// @param index A counter less than `totalSupply()`
/// @return The token identifier for the `index`th NFT,
/// (sort order not specified)
- fn token_by_index(&self, index: U256) -> Result<U256> {
- Ok(index)
+ fn token_by_index(&self, index: U256) -> U256 {
+ index
}
/// Not implemented
@@ -386,7 +392,7 @@
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-#[solidity_interface(name = ERC721, events(ERC721Events), expect_selector = 0x80ac58cd)]
+#[solidity_interface(name = ERC721, events(ERC721Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x80ac58cd)]
impl<T: Config> RefungibleHandle<T> {
/// @notice Count all RFTs assigned to an owner
/// @dev RFTs assigned to the zero address are considered invalid, and this
@@ -547,7 +553,7 @@
}
/// @title ERC721 Token that can be irreversibly burned (destroyed).
-#[solidity_interface(name = ERC721Burnable)]
+#[solidity_interface(name = ERC721Burnable, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> RefungibleHandle<T> {
/// @notice Burns a specific ERC721 token.
/// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
@@ -567,7 +573,7 @@
}
/// @title ERC721 minting logic.
-#[solidity_interface(name = ERC721UniqueMintable)]
+#[solidity_interface(name = ERC721UniqueMintable, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> RefungibleHandle<T> {
/// @notice Function to mint a token.
/// @param to The new owner
@@ -739,7 +745,7 @@
}
/// @title Unique extensions for ERC721.
-#[solidity_interface(name = ERC721UniqueExtensions)]
+#[solidity_interface(name = ERC721UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> RefungibleHandle<T>
where
T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
@@ -1120,7 +1126,8 @@
ERC721Metadata(if(this.flags.erc721metadata)),
Collection(via(common_mut returns CollectionHandle<T>)),
TokenProperties,
- )
+ ),
+ enum(derive(PreDispatch)),
)]
impl<T: Config> RefungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}
pallets/refungible/src/erc_token.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc_token.rs
+++ b/pallets/refungible/src/erc_token.rs
@@ -24,40 +24,41 @@
convert::TryInto,
ops::Deref,
};
-use evm_coder::{
- abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, solidity, types::*,
- weight,
-};
+use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};
use pallet_common::{
- CommonWeightInfo,
erc::{CommonEvmHandler, PrecompileResult},
eth::{collection_id_to_address, CrossAddress},
};
use pallet_evm::{account::CrossAccountId, PrecompileHandle};
-use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};
+use pallet_evm_coder_substrate::{
+ call, dispatch_to_evm, WithRecorder, frontier_contract,
+ execution::{Result, PreDispatch},
+};
use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
use sp_std::vec::Vec;
use sp_core::U256;
use up_data_structs::TokenId;
-use crate::{
- Allowance, Balance, common::CommonWeights, Config, Pallet, RefungibleHandle, SelfWeightOf,
- TotalSupply, weights::WeightInfo,
-};
+use crate::{Allowance, Balance, Config, Pallet, RefungibleHandle, TotalSupply};
/// Refungible token handle contains information about token's collection and id
///
/// RefungibleTokenHandle doesn't check token's existance upon creation
pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);
-#[solidity_interface(name = ERC1633)]
+frontier_contract! {
+ macro_rules! RefungibleTokenHandle_result {...}
+ impl<T: Config> Contract for RefungibleTokenHandle<T> {...}
+}
+
+#[solidity_interface(name = ERC1633, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> RefungibleTokenHandle<T> {
- fn parent_token(&self) -> Result<Address> {
- Ok(collection_id_to_address(self.id))
+ fn parent_token(&self) -> Address {
+ collection_id_to_address(self.id)
}
- fn parent_token_id(&self) -> Result<U256> {
- Ok(self.1.into())
+ fn parent_token_id(&self) -> U256 {
+ self.1.into()
}
}
@@ -89,18 +90,18 @@
///
/// @dev Implementation of the basic standard token.
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
-#[solidity_interface(name = ERC20, events(ERC20Events))]
+#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> RefungibleTokenHandle<T> {
/// @return the name of the token.
- fn name(&self) -> Result<String> {
- Ok(decode_utf16(self.name.iter().copied())
+ fn name(&self) -> String {
+ decode_utf16(self.name.iter().copied())
.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
- .collect::<String>())
+ .collect::<String>()
}
/// @return the symbol of the token.
- fn symbol(&self) -> Result<String> {
- Ok(String::from_utf8_lossy(&self.token_prefix).into())
+ fn symbol(&self) -> String {
+ String::from_utf8_lossy(&self.token_prefix).into()
}
/// @dev Total number of tokens in existence
@@ -198,7 +199,7 @@
}
}
-#[solidity_interface(name = ERC20UniqueExtensions)]
+#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> RefungibleTokenHandle<T>
where
T::AccountId: From<[u8; 32]>,
@@ -361,7 +362,8 @@
#[solidity_interface(
name = UniqueRefungibleToken,
- is(ERC20, ERC20UniqueExtensions, ERC1633)
+ is(ERC20, ERC20UniqueExtensions, ERC1633),
+ enum(derive(PreDispatch)),
)]
impl<T: Config> RefungibleTokenHandle<T> where T::AccountId: From<[u8; 32]> {}
pallets/unique/src/eth/mod.rsdiffbeforeafterboth--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -18,9 +18,7 @@
use core::marker::PhantomData;
use ethereum as _;
-use evm_coder::{
- abi::AbiType, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight,
-};
+use evm_coder::{abi::AbiType, generate_stubgen, solidity_interface, types::*};
use frame_support::traits::Get;
use crate::Pallet;
@@ -32,7 +30,11 @@
Pallet as PalletCommon,
};
use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};
-use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};
+use pallet_evm_coder_substrate::{
+ dispatch_to_evm, SubstrateRecorder, WithRecorder,
+ execution::{PreDispatch, Result, Error},
+ frontier_contract,
+};
use up_data_structs::{
CollectionDescription, CollectionMode, CollectionName, CollectionTokenPrefix,
CreateCollectionData,
@@ -43,6 +45,10 @@
use alloc::format;
use sp_std::vec::Vec;
+frontier_contract! {
+ macro_rules! EvmCollectionHelpers_result {...}
+ impl<T: Config> Contract for EvmCollectionHelpers<T> {...}
+}
/// See [`CollectionHelpersCall`]
pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);
impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {
@@ -135,7 +141,7 @@
}
/// @title Contract, which allows users to operate with collections
-#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]
+#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents), enum(derive(PreDispatch)), enum_attr(weight))]
impl<T> EvmCollectionHelpers<T>
where
T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,
@@ -183,9 +189,9 @@
/// @param description Informative description of the collection
/// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
/// @return address Address of the newly created collection
- #[weight(<SelfWeightOf<T>>::create_collection())]
#[deprecated(note = "mathod was renamed to `create_nft_collection`, prefer it instead")]
#[solidity(hide)]
+ #[weight(<SelfWeightOf<T>>::create_collection())]
fn create_nonfungible_collection(
&mut self,
caller: Caller,
runtime/tests/Cargo.tomldiffbeforeafterboth--- a/runtime/tests/Cargo.toml
+++ b/runtime/tests/Cargo.toml
@@ -40,5 +40,5 @@
parity-scale-codec = { version = "3.2.2", default-features = false, features = ["derive"] }
scale-info = "*"
-evm-coder = { default-features = false, path = "../../crates/evm-coder" }
+evm-coder = { workspace = true }
up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.37" }