diff --git a/nftopia-stellar/Cargo.lock b/nftopia-stellar/Cargo.lock index bee2594b..b7e5ecc5 100644 --- a/nftopia-stellar/Cargo.lock +++ b/nftopia-stellar/Cargo.lock @@ -865,19 +865,1282 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crate-git-revision" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c521bf1f43d31ed2f73441775ed31935d77901cb3451e44b38a1c1612fcbaf98" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.114", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.114", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "escape-bytes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2" + +[[package]] +name = "ethnum" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca81e6b4777c89fd810c25a4be2b1bd93ea034fbe58e6a75216a34c6b82c539b" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "indexmap-nostd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "marketplace_settlement" version = "0.1.0" [[package]] -name = "memchr" -version = "2.7.6" +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "nft_contract" +version = "0.1.0" +dependencies = [ + "soroban-sdk", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.114", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_with" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.13.0", + "schemars 0.8.22", + "schemars 0.9.0", + "schemars 1.2.0", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "soroban-builtin-sdk-macros" +version = "25.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7192e3a5551a7aeee90d2110b11b615798e81951fd8c8293c87ea7f88b0168f5" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "soroban-env-common" +version = "25.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfc49a80a68fc1005847308e63b9fce39874de731940b1807b721d472de3ff01" +dependencies = [ + "crate-git-revision", + "ethnum", + "num-derive", + "num-traits", + "soroban-env-macros", + "soroban-wasmi", + "static_assertions", + "stellar-xdr", + "wasmparser", +] + +[[package]] +name = "soroban-env-guest" +version = "25.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2334ba1cfe0a170ab744d96db0b4ca86934de9ff68187ceebc09dc342def55" +dependencies = [ + "soroban-env-common", + "static_assertions", +] + +[[package]] +name = "soroban-env-host" +version = "25.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43af5d53c57bc2f546e122adc0b1cca6f93942c718977379aa19ddd04f06fcec" +dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "curve25519-dalek", + "ecdsa", + "ed25519-dalek", + "elliptic-curve", + "generic-array", + "getrandom", + "hex-literal", + "hmac", + "k256", + "num-derive", + "num-integer", + "num-traits", + "p256", + "rand", + "rand_chacha", + "sec1", + "sha2", + "sha3", + "soroban-builtin-sdk-macros", + "soroban-env-common", + "soroban-wasmi", + "static_assertions", + "stellar-strkey 0.0.13", + "wasmparser", +] + +[[package]] +name = "soroban-env-macros" +version = "25.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "a989167512e3592d455b1e204d703cfe578a36672a77ed2f9e6f7e1bbfd9cc5c" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "serde", + "serde_json", + "stellar-xdr", + "syn 2.0.114", +] [[package]] -name = "nft_contract" -version = "0.1.0" +name = "soroban-sdk" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9953e782d6da30974eea520c2b5f624c28bbc518c3bb926ec581242dd3f9d2a2" +dependencies = [ + "bytes-lit", + "crate-git-revision", + "rand", + "rustc_version", + "serde", + "serde_json", + "soroban-env-guest", + "soroban-env-host", + "soroban-sdk-macros", + "stellar-strkey 0.0.16", + "visibility", +] + +[[package]] +name = "soroban-sdk-macros" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a8cecb6acc735670dad3303c6a9d2b47e51adfb11224ad5a8ced55fd7b0a600" +dependencies = [ + "darling 0.20.11", + "heck", + "itertools", + "macro-string", + "proc-macro2", + "quote", + "sha2", + "soroban-env-common", + "soroban-spec", + "soroban-spec-rust", + "stellar-xdr", + "syn 2.0.114", +] + +[[package]] +name = "soroban-spec" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c79501d0636f86fe2c9b1dd7e88b9397415b3493a59b34f466abd7758c84b92b" +dependencies = [ + "base64", + "stellar-xdr", + "thiserror", + "wasmparser", +] + +[[package]] +name = "soroban-spec-rust" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b520b5fb013fde70796d9a6057591f53817aa0c38f8bad460126f97f59394af9" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "sha2", + "soroban-spec", + "stellar-xdr", + "syn 2.0.114", + "thiserror", +] + +[[package]] +name = "soroban-wasmi" +version = "0.31.1-soroban.20.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710403de32d0e0c35375518cb995d4fc056d0d48966f2e56ea471b8cb8fc9719" +dependencies = [ + "smallvec", + "spin", + "wasmi_arena", + "wasmi_core", + "wasmparser-nostd", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stellar-strkey" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1832fb50c651ad10f734aaf5d31ca5acdfb197a6ecda64d93fcdb8885af913" +dependencies = [ + "crate-git-revision", + "data-encoding", +] + +[[package]] +name = "stellar-strkey" +version = "0.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084afcb0d458c3d5d5baa2d294b18f881e62cc258ef539d8fdf68be7dbe45520" +dependencies = [ + "crate-git-revision", + "data-encoding", + "heapless", +] + +[[package]] +name = "stellar-xdr" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d20dafed80076b227d4b17c0c508a4bbc4d5e4c3d4c1de7cd42242df4b1eaf" +dependencies = [ + "base64", + "cfg_eval", + "crate-git-revision", + "escape-bytes", + "ethnum", + "hex", + "serde", + "serde_with", + "sha2", + "stellar-strkey 0.0.13", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "time" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" +dependencies = [ + "num-conv", + "time-core", +] [[package]] name = "num-bigint" diff --git a/nftopia-stellar/contracts/nft_contract/Cargo.toml b/nftopia-stellar/contracts/nft_contract/Cargo.toml index 1bc40b61..0fb5f4eb 100644 --- a/nftopia-stellar/contracts/nft_contract/Cargo.toml +++ b/nftopia-stellar/contracts/nft_contract/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +soroban-sdk = "25.0.2" + +[lib] +crate-type = ["cdylib"] diff --git a/nftopia-stellar/contracts/nft_contract/src/access_control.rs b/nftopia-stellar/contracts/nft_contract/src/access_control.rs new file mode 100644 index 00000000..18872b7c --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/access_control.rs @@ -0,0 +1,36 @@ +use soroban_sdk::{contracttype, Address, Env}; + +use crate::error::ContractError; +use crate::storage::{self, DataKey}; + +#[contracttype] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Role { + Owner, + Admin, + Minter, + Burner, + MetadataUpdater, + Marketplace, +} + +pub fn require_owner(env: &Env) -> Result { + let owner = storage::read_owner(env)?; + owner.require_auth(); + Ok(owner) +} + +pub fn require_admin(env: &Env) -> Result { + require_owner(env) +} + +pub fn require_role(env: &Env, _role: Role) -> Result { + require_owner(env) +} + +pub fn set_role(env: &Env, role: Role, account: Address, enabled: bool) -> Result<(), ContractError> { + let _ = require_owner(env)?; + let key = DataKey::Role(role, account.clone()); + env.storage().persistent().set(&key, &enabled); + Ok(()) +} diff --git a/nftopia-stellar/contracts/nft_contract/src/error.rs b/nftopia-stellar/contracts/nft_contract/src/error.rs new file mode 100644 index 00000000..62c5f994 --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/error.rs @@ -0,0 +1,22 @@ +use soroban_sdk::contracterror; + +#[contracterror] +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum ContractError { + AlreadyInitialized = 1, + NotInitialized = 2, + Unauthorized = 3, + TokenNotFound = 4, + NotOwner = 5, + NotApproved = 6, + TransferPaused = 7, + MintPaused = 8, + MetadataFrozen = 9, + InvalidInput = 10, + MaxSupplyReached = 11, + RoyaltyTooHigh = 12, + ConfirmRequired = 13, + ArrayLengthMismatch = 14, + WhitelistRequired = 15, + RevealNotReady = 16, +} diff --git a/nftopia-stellar/contracts/nft_contract/src/events.rs b/nftopia-stellar/contracts/nft_contract/src/events.rs new file mode 100644 index 00000000..7b938fd9 --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/events.rs @@ -0,0 +1,47 @@ +use soroban_sdk::{symbol_short, Address, Env, String}; + +use crate::token::RoyaltyInfo; + +pub fn emit_mint(env: &Env, to: &Address, token_id: u64) { + env.events() + .publish((symbol_short!("mint"), to), token_id); +} + +pub fn emit_burn(env: &Env, owner: &Address, token_id: u64) { + env.events() + .publish((symbol_short!("burn"), owner), token_id); +} + +pub fn emit_transfer(env: &Env, from: &Address, to: &Address, token_id: u64) { + env.events() + .publish((symbol_short!("transfer"), from, to), token_id); +} + +pub fn emit_approval(env: &Env, owner: &Address, approved: &Option
, token_id: u64) { + env.events().publish( + (symbol_short!("approve"), owner), + (approved.clone(), token_id), + ); +} + +pub fn emit_approval_for_all(env: &Env, owner: &Address, operator: &Address, approved: bool) { + env.events().publish( + (symbol_short!("appr_all"), owner), + (operator, approved), + ); +} + +pub fn emit_metadata_update(env: &Env, token_id: u64, uri: &String) { + env.events() + .publish((symbol_short!("metadata"), token_id), uri.clone()); +} + +pub fn emit_base_uri_update(env: &Env, uri: &String) { + env.events() + .publish((symbol_short!("base_uri"),), uri.clone()); +} + +pub fn emit_royalty_update(env: &Env, token_id: Option, info: &RoyaltyInfo) { + env.events() + .publish((symbol_short!("royalty"), token_id), info.clone()); +} diff --git a/nftopia-stellar/contracts/nft_contract/src/interface.rs b/nftopia-stellar/contracts/nft_contract/src/interface.rs new file mode 100644 index 00000000..e7b05cfd --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/interface.rs @@ -0,0 +1,33 @@ +use soroban_sdk::{BytesN, Env}; + +pub fn nft_received_magic(env: &Env) -> BytesN<32> { + BytesN::from_array( + env, + &[ + 0x4e, 0x46, 0x54, 0x4f, 0x50, 0x49, 0x41, 0x5f, 0x4e, 0x46, 0x54, 0x5f, + 0x52, 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, 0x44, 0x5f, 0x4d, 0x41, 0x47, + 0x49, 0x43, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, + ], + ) +} + +pub fn interface_id(env: &Env, name: &str) -> BytesN<32> { + let bytes = soroban_sdk::Bytes::from_slice(env, name.as_bytes()); + env.crypto().sha256(&bytes).into() +} + +pub fn nft_interface_id(env: &Env) -> BytesN<32> { + interface_id(env, "nftopia.nft.v1") +} + +pub fn royalty_interface_id(env: &Env) -> BytesN<32> { + interface_id(env, "nftopia.royalty.v1") +} + +pub fn metadata_interface_id(env: &Env) -> BytesN<32> { + interface_id(env, "nftopia.metadata.v1") +} + +pub fn access_control_interface_id(env: &Env) -> BytesN<32> { + interface_id(env, "nftopia.access.v1") +} diff --git a/nftopia-stellar/contracts/nft_contract/src/main.rs b/nftopia-stellar/contracts/nft_contract/src/main.rs deleted file mode 100644 index e7a11a96..00000000 --- a/nftopia-stellar/contracts/nft_contract/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/nftopia-stellar/contracts/nft_contract/src/metadata.rs b/nftopia-stellar/contracts/nft_contract/src/metadata.rs new file mode 100644 index 00000000..0543120d --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/metadata.rs @@ -0,0 +1,89 @@ +use soroban_sdk::{Env, String}; + +use crate::access_control::require_owner; +use crate::error::ContractError; +use crate::events; +use crate::storage; + +pub fn token_uri(env: &Env, token_id: u64) -> Result { + let token = storage::read_token(env, token_id)?; + let config = storage::read_config(env)?; + if config.is_revealed || is_reveal_ready(env, &config) { + Ok(token.metadata_uri) + } else { + Ok(config.base_uri) + } +} + +pub fn token_metadata(env: &Env, token_id: u64) -> Result { + storage::read_token(env, token_id) +} + +pub fn set_token_uri( + env: &Env, + token_id: u64, + uri: String, +) -> Result<(), ContractError> { + let config = storage::read_config(env)?; + if config.metadata_is_frozen { + return Err(ContractError::MetadataFrozen); + } + + let mut token = storage::read_token(env, token_id)?; + token.owner.require_auth(); + + token.metadata_uri = uri.clone(); + storage::write_token(env, &token); + events::emit_metadata_update(env, token_id, &uri); + Ok(()) +} + +pub fn set_base_uri(env: &Env, uri: String) -> Result<(), ContractError> { + let _ = require_owner(env)?; + let mut config = storage::read_config(env)?; + if config.metadata_is_frozen { + return Err(ContractError::MetadataFrozen); + } + config.base_uri = uri.clone(); + storage::write_config(env, &config); + events::emit_base_uri_update(env, &uri); + Ok(()) +} + +pub fn freeze_metadata(env: &Env) -> Result<(), ContractError> { + let _ = require_owner(env)?; + let mut config = storage::read_config(env)?; + if config.metadata_is_frozen { + return Ok(()); + } + config.metadata_is_frozen = true; + storage::write_config(env, &config); + Ok(()) +} + +pub fn set_reveal_time(env: &Env, reveal_time: Option) -> Result<(), ContractError> { + let _ = require_owner(env)?; + let mut config = storage::read_config(env)?; + config.reveal_time = reveal_time; + storage::write_config(env, &config); + Ok(()) +} + +pub fn set_revealed(env: &Env, revealed: bool) -> Result<(), ContractError> { + let _ = require_owner(env)?; + let mut config = storage::read_config(env)?; + if revealed && !is_reveal_ready(env, &config) { + return Err(ContractError::RevealNotReady); + } + config.is_revealed = revealed; + storage::write_config(env, &config); + Ok(()) +} + +fn is_reveal_ready(env: &Env, config: &crate::token::CollectionConfig) -> bool { + if let Some(reveal_time) = config.reveal_time { + env.ledger().timestamp() >= reveal_time + } else { + true + } +} diff --git a/nftopia-stellar/contracts/nft_contract/src/royalty.rs b/nftopia-stellar/contracts/nft_contract/src/royalty.rs new file mode 100644 index 00000000..4ed2b4c0 --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/royalty.rs @@ -0,0 +1,74 @@ +use soroban_sdk::{Address, Env}; + +use crate::access_control::{require_admin, require_role, Role}; +use crate::error::ContractError; +use crate::events; +use crate::storage; +use crate::token::RoyaltyInfo; + +const MAX_BPS: u32 = 10_000; + +pub fn set_default_royalty( + env: &Env, + recipient: Address, + percentage: u32, +) -> Result<(), ContractError> { + let _ = require_admin(env)?; + if percentage > MAX_BPS { + return Err(ContractError::RoyaltyTooHigh); + } + let mut config = storage::read_config(env)?; + config.royalty_default = RoyaltyInfo { + recipient: recipient.clone(), + percentage, + }; + storage::write_config(env, &config); + events::emit_royalty_update(env, None, &config.royalty_default); + Ok(()) +} + +pub fn set_token_royalty( + env: &Env, + token_id: u64, + recipient: Address, + percentage: u32, +) -> Result<(), ContractError> { + let mut token = storage::read_token(env, token_id)?; + token.owner.require_auth(); + if percentage > MAX_BPS { + return Err(ContractError::RoyaltyTooHigh); + } + token.royalty_recipient = recipient.clone(); + token.royalty_percentage = percentage; + storage::write_token(env, &token); + events::emit_royalty_update( + env, + Some(token_id), + &RoyaltyInfo { + recipient, + percentage, + }, + ); + Ok(()) +} + +pub fn get_royalty_info( + env: &Env, + token_id: u64, + sale_price: i128, +) -> Result<(Address, i128), ContractError> { + if sale_price < 0 { + return Err(ContractError::InvalidInput); + } + let token = storage::read_token(env, token_id)?; + let percentage = token.royalty_percentage as i128; + let royalty_amount = sale_price + .saturating_mul(percentage) + .checked_div(MAX_BPS as i128) + .unwrap_or(0); + Ok((token.royalty_recipient, royalty_amount)) +} + +pub fn require_marketplace(env: &Env) -> Result { + require_role(env, Role::Marketplace) +} diff --git a/nftopia-stellar/contracts/nft_contract/src/storage.rs b/nftopia-stellar/contracts/nft_contract/src/storage.rs new file mode 100644 index 00000000..3279aeb4 --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/storage.rs @@ -0,0 +1,206 @@ +use soroban_sdk::{contracttype, Address, Env, Vec}; + +use crate::access_control::Role; +use crate::error::ContractError; +use crate::token::{CollectionConfig, SaleRecord, TokenData, TransferRecord}; + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum DataKey { + Config, + Owner, + NextTokenId, + TotalSupply, + Token(u64), + Balance(Address), + OperatorApproval(Address, Address), + Role(Role, Address), + TransferPaused, + MintPaused, + Whitelist(Address), + TokenHistory(u64), + TransferHistory(u64), +} + +pub fn is_initialized(env: &Env) -> bool { + env.storage().instance().has(&DataKey::Config) +} + +pub fn read_config(env: &Env) -> Result { + env.storage() + .instance() + .get(&DataKey::Config) + .ok_or(ContractError::NotInitialized) +} + +pub fn write_config(env: &Env, config: &CollectionConfig) { + env.storage().instance().set(&DataKey::Config, config); +} + +pub fn read_owner(env: &Env) -> Result { + env.storage() + .instance() + .get(&DataKey::Owner) + .ok_or(ContractError::NotInitialized) +} + +pub fn write_owner(env: &Env, owner: &Address) { + env.storage().instance().set(&DataKey::Owner, owner); + env.storage() + .persistent() + .set(&DataKey::Role(Role::Owner, owner.clone()), &true); +} + +pub fn read_next_token_id(env: &Env) -> u64 { + env.storage() + .instance() + .get(&DataKey::NextTokenId) + .unwrap_or(1) +} + +pub fn write_next_token_id(env: &Env, next_id: u64) { + env.storage().instance().set(&DataKey::NextTokenId, &next_id); +} + +pub fn read_total_supply(env: &Env) -> u64 { + env.storage() + .instance() + .get(&DataKey::TotalSupply) + .unwrap_or(0) +} + +pub fn write_total_supply(env: &Env, total: u64) { + env.storage().instance().set(&DataKey::TotalSupply, &total); +} + +pub fn read_token(env: &Env, token_id: u64) -> Result { + env.storage() + .persistent() + .get(&DataKey::Token(token_id)) + .ok_or(ContractError::TokenNotFound) +} + +pub fn write_token(env: &Env, token: &TokenData) { + env.storage() + .persistent() + .set(&DataKey::Token(token.id), token); +} + +pub fn delete_token(env: &Env, token_id: u64) { + env.storage().persistent().remove(&DataKey::Token(token_id)); +} + +pub fn read_balance(env: &Env, owner: &Address) -> u64 { + env.storage() + .persistent() + .get(&DataKey::Balance(owner.clone())) + .unwrap_or(0) +} + +pub fn write_balance(env: &Env, owner: &Address, balance: u64) { + env.storage() + .persistent() + .set(&DataKey::Balance(owner.clone()), &balance); +} + +pub fn read_approval(env: &Env, token_id: u64) -> Option
{ + let token = read_token(env, token_id).ok()?; + token.approved +} + +pub fn set_approval(env: &Env, token_id: u64, approved: Option
) -> Result<(), ContractError> { + let mut token = read_token(env, token_id)?; + token.approved = approved; + write_token(env, &token); + Ok(()) +} + +pub fn set_operator_approval(env: &Env, owner: &Address, operator: &Address, approved: bool) { + env.storage() + .persistent() + .set(&DataKey::OperatorApproval(owner.clone(), operator.clone()), &approved); +} + +pub fn is_operator_approved(env: &Env, owner: &Address, operator: &Address) -> bool { + env.storage() + .persistent() + .get(&DataKey::OperatorApproval(owner.clone(), operator.clone())) + .unwrap_or(false) +} + +pub fn set_paused(env: &Env, mint_paused: bool, transfer_paused: bool) { + env.storage().instance().set(&DataKey::MintPaused, &mint_paused); + env.storage() + .instance() + .set(&DataKey::TransferPaused, &transfer_paused); +} + +pub fn is_mint_paused(env: &Env) -> bool { + env.storage() + .instance() + .get(&DataKey::MintPaused) + .unwrap_or(false) +} + +pub fn is_transfer_paused(env: &Env) -> bool { + env.storage() + .instance() + .get(&DataKey::TransferPaused) + .unwrap_or(false) +} + +pub fn set_whitelisted(env: &Env, account: &Address, enabled: bool) { + env.storage() + .persistent() + .set(&DataKey::Whitelist(account.clone()), &enabled); +} + +pub fn is_whitelisted(env: &Env, account: &Address) -> bool { + env.storage() + .persistent() + .get(&DataKey::Whitelist(account.clone())) + .unwrap_or(false) +} + +pub fn has_role(env: &Env, role: Role, account: &Address) -> Result { + if role == Role::Owner { + let owner = read_owner(env)?; + Ok(owner == *account) + } else { + Ok(env + .storage() + .persistent() + .get(&DataKey::Role(role, account.clone())) + .unwrap_or(false)) + } +} + +pub fn read_history(env: &Env, token_id: u64) -> Vec { + env.storage() + .persistent() + .get(&DataKey::TokenHistory(token_id)) + .unwrap_or(Vec::new(env)) +} + +pub fn append_history(env: &Env, token_id: u64, record: SaleRecord) { + let mut history = read_history(env, token_id); + history.push_back(record); + env.storage() + .persistent() + .set(&DataKey::TokenHistory(token_id), &history); +} + +pub fn read_transfer_history(env: &Env, token_id: u64) -> Vec { + env.storage() + .persistent() + .get(&DataKey::TransferHistory(token_id)) + .unwrap_or(Vec::new(env)) +} + +pub fn append_transfer_history(env: &Env, token_id: u64, record: TransferRecord) { + let mut history = read_transfer_history(env, token_id); + history.push_back(record); + env.storage() + .persistent() + .set(&DataKey::TransferHistory(token_id), &history); +} diff --git a/nftopia-stellar/contracts/nft_contract/src/token.rs b/nftopia-stellar/contracts/nft_contract/src/token.rs new file mode 100644 index 00000000..1e91acfb --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/token.rs @@ -0,0 +1,65 @@ +use soroban_sdk::{contracttype, Address, String, Vec}; + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TokenAttribute { + pub trait_type: String, + pub value: String, + pub display_type: Option, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RoyaltyInfo { + pub recipient: Address, + pub percentage: u32, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TokenData { + pub id: u64, + pub owner: Address, + pub approved: Option
, + pub metadata_uri: String, + pub created_at: u64, + pub creator: Address, + pub royalty_percentage: u32, + pub royalty_recipient: Address, + pub attributes: Vec, + pub edition_number: Option, + pub total_editions: Option, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CollectionConfig { + pub name: String, + pub symbol: String, + pub base_uri: String, + pub max_supply: Option, + pub mint_price: Option, + pub is_revealed: bool, + pub royalty_default: RoyaltyInfo, + pub metadata_is_frozen: bool, + pub whitelist_enabled: bool, + pub reveal_time: Option, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SaleRecord { + pub seller: Address, + pub buyer: Address, + pub price: i128, + pub timestamp: u64, +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TransferRecord { + pub operator: Address, + pub from: Address, + pub to: Address, + pub timestamp: u64, +} diff --git a/nftopia-stellar/contracts/nft_contract/src/transfer.rs b/nftopia-stellar/contracts/nft_contract/src/transfer.rs new file mode 100644 index 00000000..0a4316d4 --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/transfer.rs @@ -0,0 +1,79 @@ +use soroban_sdk::{vec, Address, Bytes, BytesN, Env, Executable, IntoVal, Symbol}; + +use crate::error::ContractError; +use crate::events; +use crate::interface::nft_received_magic; +use crate::storage; +use crate::token::TransferRecord; + +pub fn transfer( + env: &Env, + from: Address, + to: Address, + token_id: u64, + data: Option, + safe: bool, +) -> Result<(), ContractError> { + if storage::is_transfer_paused(env) { + return Err(ContractError::TransferPaused); + } + + let mut token = storage::read_token(env, token_id)?; + if token.owner != from { + return Err(ContractError::NotOwner); + } + + from.require_auth(); + + if from == to { + return Ok(()); + } + + let from_balance = storage::read_balance(env, &from); + let to_balance = storage::read_balance(env, &to); + storage::write_balance(env, &from, from_balance.saturating_sub(1)); + storage::write_balance(env, &to, to_balance.saturating_add(1)); + + token.owner = to.clone(); + token.approved = None; + storage::write_token(env, &token); + + storage::append_transfer_history( + env, + token_id, + TransferRecord { + operator: from.clone(), + from: from.clone(), + to: to.clone(), + timestamp: env.ledger().timestamp(), + }, + ); + + events::emit_transfer(env, &from, &to, token_id); + + if safe { + let is_contract = matches!(to.executable(), Some(Executable::Wasm(_))); + if is_contract { + let result = env.try_invoke_contract::, soroban_sdk::InvokeError>( + &to, + &Symbol::new(env, "on_nft_received"), + vec![ + env, + from.clone().into_val(env), + from.into_val(env), + token_id.into_val(env), + data.into_val(env), + ], + ); + let magic = match result { + Ok(Ok(value)) => value, + _ => return Err(ContractError::InvalidInput), + }; + if magic != nft_received_magic(env) { + return Err(ContractError::InvalidInput); + } + } + } + + Ok(()) +} diff --git a/nftopia-stellar/contracts/nft_contract/src/utils.rs b/nftopia-stellar/contracts/nft_contract/src/utils.rs new file mode 100644 index 00000000..2877b94c --- /dev/null +++ b/nftopia-stellar/contracts/nft_contract/src/utils.rs @@ -0,0 +1,5 @@ +use soroban_sdk::Env; + +pub fn now(env: &Env) -> u64 { + env.ledger().timestamp() +}