diff --git a/contracts/.gitignore b/contracts/.gitignore index b512c09..34977ee 100644 --- a/contracts/.gitignore +++ b/contracts/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +.idea \ No newline at end of file diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 9c5e6a1..6d81359 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -7,6 +7,10 @@ name = "Inflector" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] [[package]] name = "actix" @@ -64,6 +68,15 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli 0.28.1", +] + [[package]] name = "adler" version = "1.0.2" @@ -101,6 +114,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -198,6 +217,164 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-broadcast" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.1.0", + "futures-lite 2.3.0", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "blocking", + "futures-lite 1.13.0", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if 1.0.0", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock 3.4.0", + "cfg-if 1.0.0", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.4.0", + "rustix 0.38.28", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", + "blocking", + "cfg-if 1.0.0", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.28", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "async-signal" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" +dependencies = [ + "async-io 2.3.3", + "async-lock 3.4.0", + "atomic-waker", + "cfg-if 1.0.0", + "futures-core", + "futures-io", + "rustix 0.38.28", + "signal-hook-registry", + "slab", + "windows-sys 0.52.0", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -220,6 +397,12 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.80" @@ -231,6 +414,12 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" @@ -248,6 +437,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.11.0" @@ -288,7 +492,7 @@ dependencies = [ "dirs-next", "flate2", "fs2", - "hex", + "hex 0.4.3", "is_executable", "siphasher", "tar", @@ -296,6 +500,35 @@ dependencies = [ "zip 0.6.6", ] +[[package]] +name = "bip39" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "rand_core 0.6.4", + "serde", + "unicode-normalization", +] + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -338,11 +571,20 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" dependencies = [ - "crypto-mac", + "crypto-mac 0.8.0", "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -362,23 +604,47 @@ dependencies = [ ] [[package]] -name = "borsh" -version = "0.9.3" +name = "block-padding" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "borsh-derive 0.9.3", - "hashbrown 0.11.2", + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite 2.3.0", + "piper", +] + +[[package]] +name = "blst" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", ] [[package]] name = "borsh" -version = "0.10.3" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" dependencies = [ - "borsh-derive 0.10.3", - "hashbrown 0.12.3", + "borsh-derive 0.9.3", + "hashbrown 0.11.2", ] [[package]] @@ -397,21 +663,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" dependencies = [ - "borsh-derive-internal 0.9.3", - "borsh-schema-derive-internal 0.9.3", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" -dependencies = [ - "borsh-derive-internal 0.10.3", - "borsh-schema-derive-internal 0.10.3", + "borsh-derive-internal", + "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.109", @@ -442,17 +695,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "borsh-schema-derive-internal" version = "0.9.3" @@ -464,17 +706,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "brownstone" version = "1.1.0" @@ -574,27 +805,38 @@ dependencies = [ [[package]] name = "cargo-near" -version = "0.3.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f73eb01da3b6737778d2006645533e75563d1080c64bf714bfb88d3fb0ac09b" +checksum = "02835fdf82de4345b21f542e9ddb61786513d05e4c9722db74871de321d8d728" dependencies = [ - "anyhow", "atty", "bs58 0.4.0", "camino", - "cargo_metadata", - "clap 3.2.25", + "cargo_metadata 0.14.2", + "clap", + "color-eyre", "colored", + "derive_more", + "dunce", "env_logger 0.9.3", + "inquire", + "interactive-clap", + "interactive-clap-derive", "libloading", + "linked-hash-map", "log", - "near-abi", + "names", + "near-abi 0.4.3", + "near-cli-rs", "rustc_version", "schemars", "serde_json", "sha2 0.10.7", + "shell-words", + "strum 0.24.1", + "strum_macros 0.24.3", "symbolic-debuginfo", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -606,6 +848,28 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a51c783163bdf4549820b80968d386c94ed45ed23819c93f59cca7ebd97fe0eb" +dependencies = [ + "anyhow", + "core-foundation", + "crypto-hash", + "filetime", + "hex 0.4.3", + "jobserver", + "libc", + "log", + "miow", + "same-file", + "shell-escape", + "tempfile", + "walkdir", + "winapi", +] + [[package]] name = "cargo_metadata" version = "0.14.2" @@ -619,6 +883,29 @@ dependencies = [ "serde_json", ] +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "cc" version = "1.0.94" @@ -649,9 +936,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.30" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -659,7 +946,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -681,23 +968,6 @@ dependencies = [ "inout", ] -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_derive 3.2.25", - "clap_lex 0.2.4", - "indexmap 1.9.3", - "once_cell", - "strsim 0.10.0", - "termcolor", - "textwrap", -] - [[package]] name = "clap" version = "4.5.4" @@ -705,7 +975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", - "clap_derive 4.5.4", + "clap_derive", ] [[package]] @@ -716,49 +986,54 @@ checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.0", - "strsim 0.11.1", + "clap_lex", + "strsim", ] [[package]] name = "clap_derive" -version = "3.2.25" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck 0.4.1", - "proc-macro-error", + "heck 0.5.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.65", ] [[package]] -name = "clap_derive" -version = "4.5.4" +name = "clap_lex" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.65", -] +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] -name = "clap_lex" -version = "0.2.4" +name = "color-eyre" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ - "os_str_bytes", + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", ] [[package]] -name = "clap_lex" -version = "0.7.0" +name = "color-spantrace" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] [[package]] name = "colorchoice" @@ -776,6 +1051,33 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "commoncrypto" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" +dependencies = [ + "commoncrypto-sys", +] + +[[package]] +name = "commoncrypto-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" +dependencies = [ + "libc", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -788,6 +1090,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" + [[package]] name = "core-foundation" version = "0.9.4" @@ -837,6 +1145,31 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags 1.3.2", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -853,6 +1186,18 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-hash" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a77162240fd97248d19a564a565eb563a3f592b386e4136fb300909e67dddca" +dependencies = [ + "commoncrypto", + "hex 0.3.2", + "openssl", + "winapi", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -863,6 +1208,37 @@ dependencies = [ "subtle", ] +[[package]] +name = "crypto-mac" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bcd97a54c7ca5ce2f6eb16f6bede5b0ab5f0055fedc17d2f0b4466e21671ca" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + [[package]] name = "curve25519-dalek" version = "3.2.1" @@ -876,6 +1252,34 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "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.65", +] + [[package]] name = "darling" version = "0.20.9" @@ -896,7 +1300,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.11.1", + "strsim", "syn 2.0.65", ] @@ -930,6 +1334,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_arbitrary" version = "1.3.2" @@ -947,7 +1362,7 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", @@ -974,6 +1389,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -984,6 +1408,18 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1001,6 +1437,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0bc8fbe9441c17c9f46f75dfe27fa1ddb6c68a461ccaed0481419219d4f10d3" +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "dyn-clone" version = "1.0.13" @@ -1013,13 +1455,28 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53aff6fdc1b181225acdcb5b14c47106726fd8e486707315b1b138baed68ee31" +[[package]] +name = "easy-ext" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5d6d6a8504f8caedd7de14576464383900cd3840b7033a7a3dce5ac00121ca" + [[package]] name = "ed25519" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature 2.2.0", ] [[package]] @@ -1028,14 +1485,27 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek", - "ed25519", + "curve25519-dalek 3.2.1", + "ed25519 1.5.3", "rand 0.7.3", "serde", "sha2 0.9.9", "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "rand_core 0.6.4", + "sha2 0.10.7", + "subtle", +] + [[package]] name = "either" version = "1.12.0" @@ -1052,6 +1522,12 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.34" @@ -1081,6 +1557,27 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "enumflags2" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + [[package]] name = "env_filter" version = "0.1.0" @@ -1133,18 +1630,81 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fallible-iterator" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "filetime" version = "0.2.23" @@ -1191,6 +1751,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1245,6 +1811,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1284,6 +1851,45 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand 2.1.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -1305,6 +1911,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1355,6 +1962,18 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "goblin" version = "0.5.4" @@ -1399,9 +2018,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] [[package]] name = "hashbrown" @@ -1409,6 +2025,17 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "heck" version = "0.3.3" @@ -1445,6 +2072,18 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" + [[package]] name = "hex" version = "0.4.3" @@ -1454,6 +2093,31 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deae6d9dbb35ec2c502d62b8f7b1c000a0822c3b0794ba36b3149c0a1c840dff" +dependencies = [ + "crypto-mac 0.9.1", + "digest 0.9.0", +] + [[package]] name = "hmac" version = "0.12.1" @@ -1626,6 +2290,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.9.3" @@ -1654,15 +2324,105 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ + "block-padding", "generic-array", ] +[[package]] +name = "inquire" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33e7c1ddeb15c9abcbfef6029d8e29f69b52b6d6c891031b88ed91b5065803b" +dependencies = [ + "bitflags 1.3.2", + "crossterm", + "dyn-clone", + "lazy_static", + "newline-converter", + "thiserror", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "interactive-clap" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7295a8d03a71e15612a524a8e1dec1a913459e0000e530405f20d09fb0f014f7" +dependencies = [ + "interactive-clap-derive", + "strum 0.24.1", + "strum_macros 0.24.3", +] + +[[package]] +name = "interactive-clap-derive" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a0c8d4a6b99054853778e3e9ffb0b74bcb5e8f43d99d97e5c0252c57ce67bf6" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + [[package]] name = "is_executable" version = "0.1.2" @@ -1743,6 +2503,20 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keyring" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363387f0019d714aa60cc30ab4fe501a747f4c08fc58f069dd14be971bd495a0" +dependencies = [ + "byteorder", + "lazy_static", + "linux-keyutils", + "secret-service", + "security-framework", + "windows-sys 0.52.0", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1784,6 +2558,31 @@ dependencies = [ "libc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +dependencies = [ + "serde", +] + +[[package]] +name = "linux-keyutils" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -1794,7 +2593,7 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" name = "lists" version = "0.1.0" dependencies = [ - "near-sdk", + "near-sdk 4.1.1", ] [[package]] @@ -1813,6 +2612,15 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.0", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1837,6 +2645,33 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "memory_units" version = "0.4.0" @@ -1871,16 +2706,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + [[package]] name = "multimap" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "names" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -1911,6 +2765,58 @@ dependencies = [ "serde", ] +[[package]] +name = "near-abi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c49593c9e94454a2368a4c0a511bf4bf1413aff4d23f16e1d8f4e64b5215351" +dependencies = [ + "borsh 1.5.0", + "schemars", + "semver", + "serde", +] + +[[package]] +name = "near-abi-client" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879ac02b2e8d6498294adce1de7a2424a5474b35a73e9262c851be39c89d7f92" +dependencies = [ + "anyhow", + "convert_case 0.5.0", + "near-abi-client-impl", + "near-abi-client-macros", + "prettyplease", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "near-abi-client-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1139e8a6f60fd8ed1c53c700b67bcecbf6deb4b1f47bbe9a9d5eea760d8a8e91" +dependencies = [ + "anyhow", + "near-abi 0.4.3", + "near_schemafy_lib", + "proc-macro2", + "quote", + "schemars", + "serde_json", +] + +[[package]] +name = "near-abi-client-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebaf2aae80086b310bf96e657bbee0c599c3452afd35e72999f8d6764d6b1899" +dependencies = [ + "near-abi-client-impl", + "syn 1.0.109", +] + [[package]] name = "near-account-id" version = "0.14.0" @@ -1923,41 +2829,102 @@ dependencies = [ [[package]] name = "near-account-id" -version = "0.17.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0cb40869cab7f5232f934f45db35bffe0f2d2a7cb0cd0346202fbe4ebf2dd7" +checksum = "35cbb989542587b47205e608324ddd391f0cee1c22b4b64ae49f458334b95907" dependencies = [ - "borsh 0.10.3", + "borsh 1.5.0", "serde", ] [[package]] name = "near-chain-configs" -version = "0.17.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f9a1c805846237d56f99b328ba6ab77e5d43ef59aaaf8d2a41d42fdc708a7b" +checksum = "d05e5a8ace81c09d7eb165dffc1742358a021b2fa761f2160943305f83216003" dependencies = [ "anyhow", + "bytesize", "chrono", "derive_more", - "near-config-utils", - "near-crypto 0.17.0", - "near-o11y", - "near-primitives 0.17.0", - "num-rational", + "near-config-utils 0.20.1", + "near-crypto 0.20.1", + "near-parameters 0.20.1", + "near-primitives 0.20.1", + "num-rational 0.3.2", "once_cell", "serde", "serde_json", "sha2 0.10.7", - "smart-default", + "smart-default 0.6.0", + "tracing", +] + +[[package]] +name = "near-cli-rs" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94799fd728fadc895daada6934016cb1fe3fc7e7a01200e5c88708ad8076a8a6" +dependencies = [ + "bip39", + "bs58 0.5.1", + "bytesize", + "cargo-util", + "clap", + "color-eyre", + "derive_more", + "dirs", + "easy-ext 1.0.2", + "ed25519-dalek 1.0.1", + "futures", + "hex 0.4.3", + "inquire", + "interactive-clap", + "interactive-clap-derive", + "keyring", + "linked-hash-map", + "near-crypto 0.20.1", + "near-gas 0.2.5", + "near-jsonrpc-client", + "near-jsonrpc-primitives", + "near-primitives 0.20.1", + "near-socialdb-client", + "near-token 0.2.0", + "open", + "openssl", + "prettytable", + "reqwest", + "serde", + "serde_json", + "shell-words", + "shellexpand", + "slip10", + "smart-default 0.7.1", + "strum 0.24.1", + "strum_macros 0.24.3", + "thiserror", + "tokio", + "toml 0.7.8", + "url", +] + +[[package]] +name = "near-config-utils" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1eaab1d545a9be7a55b6ef09f365c2017f93a03063547591d12c0c6d27e58" +dependencies = [ + "anyhow", + "json_comments", + "thiserror", "tracing", ] [[package]] name = "near-config-utils" -version = "0.17.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5523e7dce493c45bc3241eb3100d943ec471852f9b1f84b46a34789eadf17031" +checksum = "d96c1682d13e9a8a62ea696395bf17afc4ed4b60535223251168217098c27a50" dependencies = [ "anyhow", "json_comments", @@ -1972,13 +2939,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e75673d69fd7365508f3d32483669fe45b03bfb34e4d9363e90adae9dfb416c" dependencies = [ "arrayref", - "blake2", + "blake2 0.9.2", "borsh 0.9.3", "bs58 0.4.0", "c2-chacha", - "curve25519-dalek", + "curve25519-dalek 3.2.1", "derive_more", - "ed25519-dalek", + "ed25519-dalek 1.0.1", "near-account-id 0.14.0", "once_cell", "parity-secp256k1", @@ -1993,21 +2960,21 @@ dependencies = [ [[package]] name = "near-crypto" -version = "0.17.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6b382b626e7e0cd372d027c6672ac97b4b6ee6114288c9e58d8180b935d315" +checksum = "2991d2912218a80ec0733ac87f84fa803accea105611eea209d4419271957667" dependencies = [ - "blake2", - "borsh 0.10.3", + "blake2 0.9.2", + "borsh 1.5.0", "bs58 0.4.0", "c2-chacha", - "curve25519-dalek", + "curve25519-dalek 4.1.3", "derive_more", - "ed25519-dalek", - "hex", - "near-account-id 0.17.0", - "near-config-utils", - "near-stdx", + "ed25519-dalek 2.1.1", + "hex 0.4.3", + "near-account-id 1.0.0", + "near-config-utils 0.20.1", + "near-stdx 0.20.1", "once_cell", "primitive-types", "rand 0.7.3", @@ -2018,13 +2985,48 @@ dependencies = [ "thiserror", ] +[[package]] +name = "near-crypto" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907fdcefa3a42976cd6a8bf626fe2a87eb0d3b3ff144adc67cf32d53c9494b32" +dependencies = [ + "blake2 0.10.6", + "borsh 1.5.0", + "bs58 0.4.0", + "curve25519-dalek 4.1.3", + "derive_more", + "ed25519-dalek 2.1.1", + "hex 0.4.3", + "near-account-id 1.0.0", + "near-config-utils 0.26.0", + "near-stdx 0.26.0", + "once_cell", + "primitive-types", + "rand 0.8.5", + "secp256k1", + "serde", + "serde_json", + "subtle", + "thiserror", +] + [[package]] name = "near-fmt" -version = "0.17.0" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d998dfc1e04001608899b2498ad5a782c7d036b73769d510de21964db99286" +dependencies = [ + "near-primitives-core 0.20.1", +] + +[[package]] +name = "near-fmt" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c44c842c6cfcd9b8c387cccd4cd0619a5f21920cde5d5c292af3cc5d40510672" +checksum = "7a36518bfcf2177096d4298d9158ba698ffd6944cb035ecc0938b098337b933c" dependencies = [ - "near-primitives-core 0.17.0", + "near-primitives-core 0.26.0", ] [[package]] @@ -2034,23 +3036,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14e75c875026229902d065e4435804497337b631ec69ba746b102954273e9ad1" dependencies = [ "borsh 1.5.0", + "interactive-clap", "schemars", "serde", ] +[[package]] +name = "near-gas" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180edcc7dc2fac41f93570d0c7b759c1b6d492f6ad093d749d644a40b4310a97" +dependencies = [ + "borsh 1.5.0", + "serde", +] + [[package]] name = "near-jsonrpc-client" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "118f44c02ad211db805c1370ad3ff26576af6ff554093c9fece1b835d29d233a" +checksum = "18ad81e015f7aced8925d5b9ba3f369b36da9575c15812cfd0786bc1213284ca" dependencies = [ - "borsh 0.10.3", + "borsh 1.5.0", "lazy_static", "log", "near-chain-configs", - "near-crypto 0.17.0", + "near-crypto 0.20.1", "near-jsonrpc-primitives", - "near-primitives 0.17.0", + "near-primitives 0.20.1", "reqwest", "serde", "serde_json", @@ -2059,15 +3072,15 @@ dependencies = [ [[package]] name = "near-jsonrpc-primitives" -version = "0.17.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b2934b5ab243e25e951c984525ba0aff0e719ed915c988c5195405aa0f6987" +checksum = "b0ce745e954ae776eef05957602e638ee9581106a3675946fb43c2fe7e38ef03" dependencies = [ "arbitrary", "near-chain-configs", - "near-crypto 0.17.0", - "near-primitives 0.17.0", - "near-rpc-error-macro 0.17.0", + "near-crypto 0.20.1", + "near-primitives 0.20.1", + "near-rpc-error-macro 0.20.1", "serde", "serde_json", "thiserror", @@ -2075,22 +3088,24 @@ dependencies = [ [[package]] name = "near-o11y" -version = "0.17.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7d35397b02b131c188c72f3885e97daeccab134ec2fc8cc0073a94cf1cfe19" +checksum = "d20762631bc8253030013bbae9b5f0542691edc1aa6722f1e8141cc9b928ae5b" dependencies = [ "actix", - "atty", - "clap 4.5.4", - "near-crypto 0.17.0", - "near-primitives-core 0.17.0", + "base64 0.21.7", + "clap", + "near-crypto 0.20.1", + "near-fmt 0.20.1", + "near-primitives-core 0.20.1", "once_cell", "opentelemetry", "opentelemetry-otlp", "opentelemetry-semantic-conventions", "prometheus", "serde", - "strum", + "serde_json", + "strum 0.24.1", "thiserror", "tokio", "tracing", @@ -2099,6 +3114,43 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "near-parameters" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f16a59b6c3e69b0585be951af6fe42a0ba86c0e207cb8c63badd19efd16680" +dependencies = [ + "assert_matches", + "borsh 1.5.0", + "enum-map", + "near-account-id 1.0.0", + "near-primitives-core 0.20.1", + "num-rational 0.3.2", + "serde", + "serde_repr", + "serde_yaml", + "strum 0.24.1", + "thiserror", +] + +[[package]] +name = "near-parameters" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e41afea5c5e84763586bafc5f5e1b63d90ef4e5454e18406cab8df120178db8d" +dependencies = [ + "borsh 1.5.0", + "enum-map", + "near-account-id 1.0.0", + "near-primitives-core 0.26.0", + "num-rational 0.3.2", + "serde", + "serde_repr", + "serde_yaml", + "strum 0.24.1", + "thiserror", +] + [[package]] name = "near-primitives" version = "0.14.0" @@ -2110,61 +3162,109 @@ dependencies = [ "bytesize", "chrono", "derive_more", - "easy-ext", - "hex", + "easy-ext 0.2.9", + "hex 0.4.3", "near-crypto 0.14.0", "near-primitives-core 0.14.0", "near-rpc-error-macro 0.14.0", - "near-vm-errors 0.14.0", - "num-rational", + "near-vm-errors", + "num-rational 0.3.2", "once_cell", "primitive-types", "rand 0.7.3", "reed-solomon-erasure", "serde", "serde_json", - "smart-default", - "strum", + "smart-default 0.6.0", + "strum 0.24.1", "thiserror", ] [[package]] name = "near-primitives" -version = "0.17.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f7051aaf199adc4d068620fca6d5f70f906a1540d03a8bb3701271f8881835" +checksum = "0462b067732132babcc89d5577db3bfcb0a1bcfbaaed3f2db4c11cd033666314" dependencies = [ "arbitrary", - "borsh 0.10.3", + "base64 0.21.7", + "borsh 1.5.0", "bytesize", "cfg-if 1.0.0", "chrono", "derive_more", - "easy-ext", + "easy-ext 0.2.9", "enum-map", - "hex", - "near-crypto 0.17.0", - "near-fmt", - "near-primitives-core 0.17.0", - "near-rpc-error-macro 0.17.0", - "near-stdx", - "near-vm-errors 0.17.0", - "num-rational", + "hex 0.4.3", + "near-crypto 0.20.1", + "near-fmt 0.20.1", + "near-o11y", + "near-parameters 0.20.1", + "near-primitives-core 0.20.1", + "near-rpc-error-macro 0.20.1", + "near-stdx 0.20.1", + "near-vm-runner 0.20.1", + "num-rational 0.3.2", "once_cell", "primitive-types", "rand 0.8.5", + "rand_chacha 0.3.1", "reed-solomon-erasure", "serde", "serde_json", "serde_with", "serde_yaml", - "smart-default", - "strum", + "sha3", + "smart-default 0.6.0", + "strum 0.24.1", "thiserror", "time", "tracing", ] +[[package]] +name = "near-primitives" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165c2dc0fc20d839cfd7948d930ef5e8a4ed2b095abe83e0076ef5d4a5df58ed" +dependencies = [ + "arbitrary", + "base64 0.21.7", + "borsh 1.5.0", + "bytes", + "bytesize", + "cfg-if 1.0.0", + "chrono", + "derive_more", + "easy-ext 0.2.9", + "enum-map", + "hex 0.4.3", + "itertools", + "near-crypto 0.26.0", + "near-fmt 0.26.0", + "near-parameters 0.26.0", + "near-primitives-core 0.26.0", + "near-rpc-error-macro 0.26.0", + "near-stdx 0.26.0", + "near-structs-checker-lib", + "near-time", + "num-rational 0.3.2", + "once_cell", + "ordered-float", + "primitive-types", + "rand 0.8.5", + "rand_chacha 0.3.1", + "serde", + "serde_json", + "serde_with", + "sha3", + "smart-default 0.6.0", + "strum 0.24.1", + "thiserror", + "tracing", + "zstd 0.13.2", +] + [[package]] name = "near-primitives-core" version = "0.14.0" @@ -2176,31 +3276,52 @@ dependencies = [ "bs58 0.4.0", "derive_more", "near-account-id 0.14.0", - "num-rational", + "num-rational 0.3.2", "serde", "sha2 0.10.7", - "strum", + "strum 0.24.1", ] [[package]] name = "near-primitives-core" -version = "0.17.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775fec19ef51a341abdbf792a9dda5b4cb89f488f681b2fd689b9321d24db47b" +checksum = "8443eb718606f572c438be6321a097a8ebd69f8e48d953885b4f16601af88225" dependencies = [ "arbitrary", "base64 0.21.7", - "borsh 0.10.3", + "borsh 1.5.0", "bs58 0.4.0", "derive_more", "enum-map", - "near-account-id 0.17.0", - "num-rational", + "near-account-id 1.0.0", + "num-rational 0.3.2", "serde", "serde_repr", "serde_with", "sha2 0.10.7", - "strum", + "strum 0.24.1", + "thiserror", +] + +[[package]] +name = "near-primitives-core" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51fd53f992168589c52022dd220c84a7f2ede92251631a06a3817e4b22af5836" +dependencies = [ + "arbitrary", + "base64 0.21.7", + "borsh 1.5.0", + "bs58 0.4.0", + "derive_more", + "enum-map", + "near-account-id 1.0.0", + "near-structs-checker-lib", + "num-rational 0.3.2", + "serde", + "serde_repr", + "sha2 0.10.7", "thiserror", ] @@ -2217,9 +3338,20 @@ dependencies = [ [[package]] name = "near-rpc-error-core" -version = "0.17.0" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80fca203c51edd9595ec14db1d13359fb9ede32314990bf296b6c5c4502f6ab7" +dependencies = [ + "quote", + "serde", + "syn 2.0.65", +] + +[[package]] +name = "near-rpc-error-core" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c1eda300e2e78f4f945ae58117d49e806899f4a51ee2faa09eda5ebc2e6571" +checksum = "df598b0785a3e36d7e4fb73afcdf20536988b13d07cead71dfa777db4783e552" dependencies = [ "quote", "serde", @@ -2239,21 +3371,32 @@ dependencies = [ [[package]] name = "near-rpc-error-macro" -version = "0.17.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31d2dadd765101c77e664029dd6fbec090e696877d4ae903c620d02ceda4969a" +checksum = "897a445de2102f6732c8a185d922f5e3bf7fd0a41243ce40854df2197237f799" dependencies = [ "fs2", - "near-rpc-error-core 0.17.0", + "near-rpc-error-core 0.20.1", + "serde", + "syn 2.0.65", +] + +[[package]] +name = "near-rpc-error-macro" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "647ef261df99ad877c08c97af2f10368c8b8cde0968250d3482a5a249e9f3926" +dependencies = [ + "near-rpc-error-core 0.26.0", "serde", "syn 2.0.65", ] [[package]] name = "near-sandbox-utils" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2de216bb0152bfb64f59016d9e6a5b1ac56dd85f729e5fde08461571e2182c8f" +checksum = "bb707ae2f73e10f253155c34993970422b9de41d64e9639a946ad44fec957bc3" dependencies = [ "anyhow", "binary-install", @@ -2272,11 +3415,11 @@ dependencies = [ "base64 0.13.1", "borsh 0.9.3", "bs58 0.4.0", - "near-abi", + "near-abi 0.3.0", "near-crypto 0.14.0", "near-primitives 0.14.0", "near-primitives-core 0.14.0", - "near-sdk-macros", + "near-sdk-macros 4.1.1", "near-sys", "near-vm-logic", "once_cell", @@ -2286,6 +3429,31 @@ dependencies = [ "wee_alloc", ] +[[package]] +name = "near-sdk" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e296b02c85539c16659e171242d6c6bbea87eec7c9ef860d8dfd3fb3168a18a" +dependencies = [ + "base64 0.22.1", + "borsh 1.5.0", + "bs58 0.5.1", + "near-account-id 1.0.0", + "near-crypto 0.26.0", + "near-gas 0.3.0", + "near-parameters 0.26.0", + "near-primitives 0.26.0", + "near-primitives-core 0.26.0", + "near-sdk-macros 5.5.0", + "near-sys", + "near-token 0.3.0", + "near-vm-runner 0.26.0", + "once_cell", + "serde", + "serde_json", + "wee_alloc", +] + [[package]] name = "near-sdk-macros" version = "4.1.1" @@ -2299,16 +3467,90 @@ dependencies = [ ] [[package]] -name = "near-stdx" -version = "0.17.0" +name = "near-sdk-macros" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0adc79466aa556f56a995c0db34a933b32597ab92bbb0e526597118899c8bcaf" +dependencies = [ + "Inflector", + "darling", + "proc-macro2", + "quote", + "serde", + "serde_json", + "strum 0.26.3", + "strum_macros 0.26.4", + "syn 2.0.65", +] + +[[package]] +name = "near-socialdb-client" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfaf5ca57fd62d678cb67183d1d31e6bbb04b98abc45fd57b986962d97ad8c4a" +dependencies = [ + "color-eyre", + "near-crypto 0.20.1", + "near-jsonrpc-client", + "near-jsonrpc-primitives", + "near-primitives 0.20.1", + "near-token 0.2.0", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "near-stdx" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855fd5540e3b4ff6fedf12aba2db1ee4b371b36f465da1363a6d022b27cb43b8" + +[[package]] +name = "near-stdx" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d5c43f6181873287ddaa25edcc2943d0f2d5da9588231516f2ed0549db1fbac" + +[[package]] +name = "near-structs-checker-core" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e53379bee876286de4ad31dc7f9fde8db12527c39d401d94f4d42cd021b8fce" + +[[package]] +name = "near-structs-checker-lib" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f984805f225c9b19681a124af7783078459e87ea63dde751b62e7cb404b1d6a" +dependencies = [ + "near-structs-checker-core", + "near-structs-checker-macro", +] + +[[package]] +name = "near-structs-checker-macro" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6540152fba5e96fe5d575b79e8cd244cf2add747bb01362426bdc069bc3a23bc" +checksum = "66319954983ae164fd0b714ae9d8b09edc26c74d9b3a1f51e564bb14720adb8e" [[package]] name = "near-sys" -version = "0.2.1" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf4ca5c805cb78700e10e43484902d8da05f25788db277999d209568aaf4c8e" + +[[package]] +name = "near-time" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397688591acf8d3ebf2c2485ba32d4b24fc10aad5334e3ad8ec0b7179bfdf06b" +checksum = "f1d37b864f04d9aebbc3b88ac63ba989d94f221de694bcc8af639cc284a89f64" +dependencies = [ + "once_cell", + "serde", + "time", + "tokio", +] [[package]] name = "near-token" @@ -2316,33 +3558,31 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b68f3f8a2409f72b43efdbeff8e820b81e70824c49fee8572979d789d1683fb" dependencies = [ + "borsh 1.5.0", + "interactive-clap", "serde", ] [[package]] -name = "near-vm-errors" -version = "0.14.0" +name = "near-token" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0da466a30f0446639cbd788c30865086fac3e8dcb07a79e51d2b0775ed4261e" +checksum = "cd3e60aa26a74dc514b1b6408fdd06cefe2eb0ff029020956c1c6517594048fd" dependencies = [ - "borsh 0.9.3", - "near-account-id 0.14.0", - "near-rpc-error-macro 0.14.0", + "borsh 1.5.0", "serde", ] [[package]] name = "near-vm-errors" -version = "0.17.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec545d1bede0579e7c15dd2dce9b998dc975c52f2165702ff40bec7ff69728bb" +checksum = "d0da466a30f0446639cbd788c30865086fac3e8dcb07a79e51d2b0775ed4261e" dependencies = [ - "borsh 0.10.3", - "near-account-id 0.17.0", - "near-rpc-error-macro 0.17.0", + "borsh 0.9.3", + "near-account-id 0.14.0", + "near-rpc-error-macro 0.14.0", "serde", - "strum", - "thiserror", ] [[package]] @@ -2359,37 +3599,99 @@ dependencies = [ "near-crypto 0.14.0", "near-primitives 0.14.0", "near-primitives-core 0.14.0", - "near-vm-errors 0.14.0", + "near-vm-errors", + "ripemd", + "serde", + "sha2 0.10.7", + "sha3", + "zeropool-bn", +] + +[[package]] +name = "near-vm-runner" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56c80bdb1954808f59bd36a9112377197b38d424991383bf05f52d0fe2e0da5" +dependencies = [ + "base64 0.21.7", + "borsh 1.5.0", + "ed25519-dalek 2.1.1", + "enum-map", + "memoffset 0.8.0", + "near-crypto 0.20.1", + "near-parameters 0.20.1", + "near-primitives-core 0.20.1", + "near-stdx 0.20.1", + "num-rational 0.3.2", + "once_cell", + "prefix-sum-vec", + "ripemd", + "serde", + "serde_repr", + "serde_with", + "sha2 0.10.7", + "sha3", + "strum 0.24.1", + "thiserror", + "tracing", + "zeropool-bn", +] + +[[package]] +name = "near-vm-runner" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a2fecdbec69a1748bd80aa0d73e4de0064d2d8097f429677d3e37a6bde3b2d" +dependencies = [ + "blst", + "borsh 1.5.0", + "bytesize", + "ed25519-dalek 2.1.1", + "enum-map", + "lru", + "near-crypto 0.26.0", + "near-parameters 0.26.0", + "near-primitives-core 0.26.0", + "near-stdx 0.26.0", + "num-rational 0.3.2", + "once_cell", "ripemd", + "rustix 0.38.28", "serde", + "serde_repr", "sha2 0.10.7", "sha3", + "strum 0.24.1", + "tempfile", + "thiserror", + "tracing", "zeropool-bn", ] [[package]] name = "near-workspaces" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a14e772e49ba9644c06dad20f635b6463f74d378fa19822bfc35fef479c72e5" +checksum = "02a9c60c2ea4735297625d46a69683998f1130533abdb1c53f109d8ef87680db" dependencies = [ "async-trait", "base64 0.21.7", - "borsh 0.10.3", "bs58 0.5.1", "cargo-near", + "cargo_metadata 0.18.1", "chrono", "fs2", "json-patch", "libc", - "near-account-id 0.17.0", - "near-crypto 0.17.0", - "near-gas", + "near-abi-client", + "near-account-id 1.0.0", + "near-crypto 0.20.1", + "near-gas 0.2.5", "near-jsonrpc-client", "near-jsonrpc-primitives", - "near-primitives 0.17.0", + "near-primitives 0.20.1", "near-sandbox-utils", - "near-token", + "near-token 0.2.0", "rand 0.8.5", "reqwest", "serde", @@ -2403,12 +3705,60 @@ dependencies = [ "url", ] +[[package]] +name = "near_schemafy_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d7a1f809a319578773329389529dbf8c8f0abfbb05a429b37f437105f7caf6" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "near_schemafy_lib" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39ccae55df51adaa1a4e567b7a79ab4380826a695121cebf41f518076d8c3dd" +dependencies = [ + "Inflector", + "near_schemafy_core", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "syn 1.0.109", + "uriparse", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "newline-converter" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f71d09d5c87634207f894c6b31b6a2b2c64ea3bdcf71bd5599fdbbe1600c00f" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if 1.0.0", + "libc", + "memoffset 0.7.1", +] + [[package]] name = "nom" version = "7.1.3" @@ -2442,6 +3792,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint 0.4.4", + "num-complex", + "num-integer", + "num-iter", + "num-rational 0.4.2", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.3.3" @@ -2453,6 +3817,26 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2469,6 +3853,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.3.2" @@ -2476,17 +3871,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ "autocfg", - "num-bigint", + "num-bigint 0.3.3", "num-integer", "num-traits", "serde", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint 0.4.4", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -2501,6 +3907,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -2513,6 +3928,17 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "open" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a083c0c7e5e4a8ec4176346cf61f67ac674e8bfb059d9226e1c54a96b377c12" +dependencies = [ + "is-wsl", + "libc", + "pathdiff", +] + [[package]] name = "openssl" version = "0.10.64" @@ -2545,6 +3971,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.3.2+3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.102" @@ -2553,6 +3988,7 @@ checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -2606,10 +4042,32 @@ dependencies = [ ] [[package]] -name = "os_str_bytes" -version = "6.6.1" +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e7ccb95e240b7c9506a3d544f10d935e142cc90b0a1d56954fb44d89ad6b97" +dependencies = [ + "borsh 1.5.0", + "num-traits", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "ordered-stream" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] [[package]] name = "overload" @@ -2617,6 +4075,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + [[package]] name = "parity-scale-codec" version = "2.3.1" @@ -2655,6 +4119,12 @@ dependencies = [ "rand 0.7.3", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.2" @@ -2689,6 +4159,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "pathdiff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" + [[package]] name = "pbkdf2" version = "0.11.0" @@ -2696,7 +4172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ "digest 0.10.7", - "hmac", + "hmac 0.12.1", "password-hash", "sha2 0.10.7", ] @@ -2769,6 +4245,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.1.0", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -2781,14 +4268,45 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if 1.0.0", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +dependencies = [ + "cfg-if 1.0.0", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.28", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "potlock-campaigns" version = "0.1.0" dependencies = [ "anyhow", + "chrono", "env_logger 0.11.3", "log", - "near-sdk", + "near-sdk 5.5.0", "near-workspaces", "tokio", ] @@ -2797,28 +4315,28 @@ dependencies = [ name = "potlock-donation" version = "0.1.0" dependencies = [ - "near-sdk", + "near-sdk 4.1.1", ] [[package]] name = "potlock-pot" version = "0.1.0" dependencies = [ - "near-sdk", + "near-sdk 4.1.1", ] [[package]] name = "potlock-pot-factory" version = "0.1.0" dependencies = [ - "near-sdk", + "near-sdk 4.1.1", ] [[package]] name = "potlock-registry" version = "0.1.0" dependencies = [ - "near-sdk", + "near-sdk 4.1.1", ] [[package]] @@ -2839,6 +4357,36 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "prefix-sum-vec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa06bd51638b6e76ac9ba9b6afb4164fa647bd2916d722f2623fbb6d1ed8bdba" + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "prettytable" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46480520d1b77c9a3482d39939fcf96831537a250ec62d4fd8fbdf8e0302e781" +dependencies = [ + "csv", + "encode_unicode", + "is-terminal", + "lazy_static", + "term", + "unicode-width", +] + [[package]] name = "primitive-types" version = "0.10.1" @@ -2856,7 +4404,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] @@ -3028,6 +4576,7 @@ dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", + "serde", ] [[package]] @@ -3066,6 +4615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom 0.2.10", + "serde", ] [[package]] @@ -3223,6 +4773,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -3235,7 +4791,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", ] [[package]] @@ -3247,7 +4817,7 @@ dependencies = [ "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] @@ -3294,6 +4864,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.23" @@ -3388,6 +4967,25 @@ dependencies = [ "cc", ] +[[package]] +name = "secret-service" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5204d39df37f06d1944935232fd2dfe05008def7ca599bf28c0800366c8a8f9" +dependencies = [ + "aes", + "cbc", + "futures-util", + "generic-array", + "hkdf", + "num", + "once_cell", + "rand 0.8.5", + "serde", + "sha2 0.10.7", + "zbus", +] + [[package]] name = "security-framework" version = "2.11.0" @@ -3473,6 +5071,15 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3493,7 +5100,7 @@ checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ "base64 0.22.1", "chrono", - "hex", + "hex 0.4.3", "indexmap 1.9.3", "indexmap 2.0.0", "serde", @@ -3582,6 +5189,48 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shellexpand" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +dependencies = [ + "dirs", +] + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -3597,6 +5246,12 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + [[package]] name = "siphasher" version = "0.3.11" @@ -3612,6 +5267,17 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slip10" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28724a6e6f70b0cb115c580891483da6f3aa99e6a353598303a57f89d23aa6bc" +dependencies = [ + "ed25519-dalek 1.0.1", + "hmac 0.9.0", + "sha2 0.9.9", +] + [[package]] name = "smallvec" version = "1.11.0" @@ -3629,6 +5295,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "smart-default" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + [[package]] name = "socket2" version = "0.4.10" @@ -3687,12 +5364,6 @@ dependencies = [ "serde", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" @@ -3705,9 +5376,15 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros", + "strum_macros 0.24.3", ] +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + [[package]] name = "strum_macros" version = "0.24.3" @@ -3721,6 +5398,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.65", +] + [[package]] name = "subtle" version = "2.5.0" @@ -3731,14 +5421,14 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" name = "sybil" version = "0.1.0" dependencies = [ - "near-sdk", + "near-sdk 4.1.1", ] [[package]] name = "sybil_provider_simulator" version = "0.1.0" dependencies = [ - "near-sdk", + "near-sdk 4.1.1", ] [[package]] @@ -3764,7 +5454,7 @@ dependencies = [ "elementtree", "fallible-iterator", "flate2", - "gimli", + "gimli 0.26.2", "goblin", "lazy_static", "lazycell", @@ -3868,12 +5558,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if 1.0.0", - "fastrand", + "fastrand 2.1.0", "redox_syscall 0.4.1", - "rustix", + "rustix 0.38.28", "windows-sys 0.52.0", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -3883,12 +5584,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" - [[package]] name = "thiserror" version = "1.0.48" @@ -3919,6 +5614,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.3.36" @@ -4073,11 +5777,26 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -4086,6 +5805,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] @@ -4221,6 +5942,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + [[package]] name = "tracing-futures" version = "0.2.5" @@ -4297,6 +6028,17 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset 0.9.1", + "tempfile", + "winapi", +] + [[package]] name = "uint" version = "0.9.5" @@ -4305,7 +6047,7 @@ checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", - "hex", + "hex 0.4.3", "static_assertions", ] @@ -4323,9 +6065,9 @@ checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] @@ -4336,6 +6078,12 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -4364,6 +6112,16 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + [[package]] name = "url" version = "2.5.0" @@ -4406,6 +6164,22 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -4536,7 +6310,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.28", ] [[package]] @@ -4759,8 +6533,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1" dependencies = [ "libc", - "linux-raw-sys", - "rustix", + "linux-raw-sys 0.4.14", + "rustix 0.38.28", +] + +[[package]] +name = "xdg-home" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" +dependencies = [ + "libc", + "windows-sys 0.52.0", ] [[package]] @@ -4769,6 +6553,72 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +[[package]] +name = "zbus" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder", + "derivative", + "enumflags2", + "event-listener 2.5.3", + "futures-core", + "futures-sink", + "futures-util", + "hex 0.4.3", + "nix", + "once_cell", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + [[package]] name = "zeroize" version = "1.3.0" @@ -4828,11 +6678,11 @@ dependencies = [ "crc32fast", "crossbeam-utils", "flate2", - "hmac", + "hmac 0.12.1", "pbkdf2", "sha1", "time", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -4841,7 +6691,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe 7.2.1", ] [[package]] @@ -4854,6 +6713,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.10+zstd.1.5.6" @@ -4863,3 +6731,41 @@ dependencies = [ "cc", "pkg-config", ] + +[[package]] +name = "zvariant" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] diff --git a/contracts/campaigns/Cargo.toml b/contracts/campaigns/Cargo.toml index 0bdc156..b95ef1f 100644 --- a/contracts/campaigns/Cargo.toml +++ b/contracts/campaigns/Cargo.toml @@ -10,12 +10,14 @@ crate-type = ["cdylib"] [dependencies] env_logger = "0.11.3" log = "0.4.21" -near-sdk = "4.1.1" +chrono = "0.4.38" +near-sdk = { version = "5.3.0", features = ["unstable"] } [dev-dependencies] anyhow = "1.0" tokio = { version = "1.14", features = ["full"] } -near-workspaces = { version = "0.9.0", default-features = false, features = ["install"] } +near-sdk = { version = "5.3.0", features = ["unit-testing"] } +near-workspaces = { version = "0.10.0", features = ["unstable"] } # near-sdk = "5.0.0-alpha.2" # [profile.release] # removed as added to root Cargo.toml diff --git a/contracts/campaigns/README.md b/contracts/campaigns/README.md index b194ec8..b5f8d89 100644 --- a/contracts/campaigns/README.md +++ b/contracts/campaigns/README.md @@ -32,22 +32,22 @@ type ReferrerPayouts = HashMap; pub struct Contract { contract_source_metadata: LazyOption, owner: AccountId, - admins: UnorderedSet, + admins: IterableSet, protocol_fee_basis_points: u32, protocol_fee_recipient_account: AccountId, default_referral_fee_basis_points: u32, default_creator_fee_basis_points: u32, next_campaign_id: CampaignId, - campaigns_by_id: UnorderedMap, - campaign_ids_by_owner: UnorderedMap>, - campaign_ids_by_recipient: UnorderedMap>, + campaigns_by_id: IterableMap, + campaign_ids_by_owner: IterableMap>, + campaign_ids_by_recipient: IterableMap>, next_donation_id: DonationId, - donations_by_id: UnorderedMap, - escrowed_donation_ids_by_campaign_id: UnorderedMap>, - unescrowed_donation_ids_by_campaign_id: UnorderedMap>, - returned_donation_ids_by_campaign_id: UnorderedMap>, - donation_ids_by_donor_id: UnorderedMap>, - storage_deposits: UnorderedMap, + donations_by_id: IterableMap, + escrowed_donation_ids_by_campaign_id: IterableMap>, + unescrowed_donation_ids_by_campaign_id: IterableMap>, + returned_donation_ids_by_campaign_id: IterableMap>, + donation_ids_by_donor_id: IterableMap>, + storage_deposits: IterableMap, } /// NOT stored in contract storage; only used for get_config response diff --git a/contracts/campaigns/out/main.wasm b/contracts/campaigns/out/main.wasm index e1d7007..be7c0e0 100755 Binary files a/contracts/campaigns/out/main.wasm and b/contracts/campaigns/out/main.wasm differ diff --git a/contracts/campaigns/src/admin.rs b/contracts/campaigns/src/admin.rs index beb29cf..61d3cec 100644 --- a/contracts/campaigns/src/admin.rs +++ b/contracts/campaigns/src/admin.rs @@ -1,6 +1,6 @@ use crate::*; -#[near_bindgen] +#[near] impl Contract { // FEES CONFIG #[payable] diff --git a/contracts/campaigns/src/campaigns.rs b/contracts/campaigns/src/campaigns.rs index 1c59ee4..cb685ac 100644 --- a/contracts/campaigns/src/campaigns.rs +++ b/contracts/campaigns/src/campaigns.rs @@ -2,8 +2,8 @@ use crate::*; pub type CampaignId = u64; -#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[borsh, json])] +#[derive(Clone)] pub struct Campaign { // indexed at ID so don't need to include here pub owner: AccountId, @@ -26,7 +26,8 @@ pub struct Campaign { pub allow_fee_avoidance: bool, } -#[derive(BorshSerialize, BorshDeserialize)] +#[near(serializers=[borsh])] +#[derive(Clone)] pub enum VersionedCampaign { Current(Campaign), } @@ -39,8 +40,8 @@ impl From for Campaign { } } -#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[borsh, json])] +#[derive(Clone)] pub struct CampaignExternal { pub id: CampaignId, pub owner: AccountId, @@ -74,18 +75,18 @@ pub(crate) fn format_campaign(campaign_id: &CampaignId, campaign: &Campaign) -> end_ms: campaign.end_ms, created_ms: campaign.created_ms, ft_id: campaign.ft_id.clone(), - target_amount: U128::from(campaign.target_amount), + target_amount: campaign.target_amount.into(), min_amount: campaign.min_amount.map(U128::from), max_amount: campaign.max_amount.map(U128::from), - total_raised_amount: U128::from(campaign.total_raised_amount), - net_raised_amount: U128::from(campaign.net_raised_amount), - escrow_balance: U128::from(campaign.escrow_balance), + total_raised_amount: campaign.total_raised_amount.into(), + net_raised_amount: campaign.net_raised_amount.into(), + escrow_balance: campaign.escrow_balance.into(), referral_fee_basis_points: campaign.referral_fee_basis_points, creator_fee_basis_points: campaign.creator_fee_basis_points, } } -#[near_bindgen] +#[near] impl Contract { #[payable] pub fn create_campaign( @@ -104,6 +105,23 @@ impl Contract { creator_fee_basis_points: Option, allow_fee_avoidance: Option, ) -> CampaignExternal { + // check that start_ms is in the future and that end_ms is after start_ms + assert!( + start_ms >= env::block_timestamp_ms(), + "start_ms must be in the future" + ); + env::log_str( + format!( + "mesage the timer, {} : {}", + start_ms, + env::block_timestamp_ms() + ) + .as_str(), + ); + assert!( + end_ms.unwrap_or(u64::MAX) > start_ms, + "end_ms must be after start_ms" + ); let initial_storage_usage = env::storage_usage(); let campaign_id = self.next_campaign_id; let campaign = Campaign { @@ -133,6 +151,7 @@ impl Contract { allow_fee_avoidance: allow_fee_avoidance.unwrap_or(false), }; self.internal_insert_new_campaign_record(&campaign_id, &campaign); + self.next_campaign_id += 1; refund_deposit(initial_storage_usage); let formatted = format_campaign(&campaign_id, &campaign); log_campaign_create_event(&formatted); @@ -205,19 +224,20 @@ impl Contract { start_ms: Option, end_ms: Option, ft_id: Option, - target_amount: Option, - max_amount: Option, + target_amount: Option, + max_amount: Option, min_amount: Option, // Can only be provided if campaign has not started yet allow_fee_avoidance: Option, // NB: recipient cannot be updated. If incorrect recipient is specified, campaign should be deleted and recreated ) -> CampaignExternal { self.assert_campaign_owner(&campaign_id); let initial_storage_usage = env::storage_usage(); - let mut campaign = Campaign::from( - self.campaigns_by_id - .get(&campaign_id) - .expect("Campaign not found"), - ); + let versioned_campaign = self + .campaigns_by_id + .get(&campaign_id) + .expect("Campaign not found") + .clone(); + let mut campaign = Campaign::from(versioned_campaign); // Owner can change name, description, cover_image_url at any time if let Some(name) = name { campaign.name = name; @@ -259,7 +279,7 @@ impl Contract { ); assert!( campaign.min_amount.is_none() - || campaign.net_raised_amount >= campaign.min_amount.unwrap(), + || campaign.net_raised_amount <= campaign.min_amount.unwrap(), "Cannot edit end_ms after min_amount has been reached" ); campaign.end_ms = Some(end_ms); @@ -274,7 +294,7 @@ impl Contract { campaign.end_ms.unwrap_or(u64::MAX) > env::block_timestamp_ms(), "Cannot edit target_amount after end_ms has been reached" ); - campaign.target_amount = target_amount; + campaign.target_amount = target_amount.into(); } // Owner can change max_amount until it is reached, or until end_ms is reached (whichever comes first) if let Some(max_amount) = max_amount { @@ -286,7 +306,7 @@ impl Contract { campaign.end_ms.unwrap_or(u64::MAX) > env::block_timestamp_ms(), "Cannot edit max_amount after end_ms has been reached" ); - campaign.max_amount = Some(max_amount); + campaign.max_amount = Some(max_amount.into()); } // Owner can change min_amount before campaign starts if let Some(min_amount) = min_amount { @@ -303,7 +323,8 @@ impl Contract { } self.campaigns_by_id - .insert(&campaign_id, &VersionedCampaign::Current(campaign.clone())); + .insert(campaign_id, VersionedCampaign::Current(campaign.clone())); + self.campaigns_by_id.flush(); refund_deposit(initial_storage_usage); let formatted = format_campaign(&campaign_id, &campaign); log_campaign_update_event(&formatted); @@ -322,11 +343,12 @@ impl Contract { // VIEW METHODS pub fn get_campaign(&self, campaign_id: CampaignId) -> CampaignExternal { - let campaign = Campaign::from( - self.campaigns_by_id - .get(&campaign_id) - .expect("Campaign not found"), - ); + let v_campaign = self + .campaigns_by_id + .get(&campaign_id) + .expect("Campaign not found") + .clone(); + let campaign = Campaign::from(v_campaign); format_campaign(&campaign_id, &campaign) } @@ -346,7 +368,25 @@ impl Contract { .iter() .skip(start_index as usize) .take(limit) - .map(|(id, v)| format_campaign(&id, &Campaign::from(v))) + .map(|(id, v)| format_campaign(&id, &Campaign::from(v.clone()))) + .collect() + } + + fn take_limit( + &self, + data: Vec, + start_index: u128, + limit: usize, + ) -> Vec { + data.iter() + .skip(start_index as usize) + .take(limit) + .map(|campaign_id| { + format_campaign( + &campaign_id, + &Campaign::from(self.campaigns_by_id.get(&campaign_id).unwrap().clone()), + ) + }) .collect() } @@ -358,10 +398,9 @@ impl Contract { ) -> Vec { let start_index: u128 = from_index.unwrap_or_default(); let campaigns_for_owner_set = self.campaign_ids_by_owner.get(&owner_id); - let campaigns_for_owner = if campaigns_for_owner_set.is_none() { - vec![] - } else { - campaigns_for_owner_set.unwrap().to_vec() + let campaigns_for_owner = match campaigns_for_owner_set { + Some(set) => set.iter().cloned().collect(), + None => vec![], }; assert!( (campaigns_for_owner.len() as u128) >= start_index, @@ -369,17 +408,7 @@ impl Contract { ); let limit = limit.map(|v| v as usize).unwrap_or(usize::MAX); assert_ne!(limit, 0, "Cannot provide limit of 0."); - campaigns_for_owner - .iter() - .skip(start_index as usize) - .take(limit) - .map(|campaign_id| { - format_campaign( - &campaign_id, - &Campaign::from(self.campaigns_by_id.get(&campaign_id).unwrap()), - ) - }) - .collect() + self.take_limit(campaigns_for_owner, start_index, limit) } pub fn get_campaigns_by_recipient( @@ -390,27 +419,17 @@ impl Contract { ) -> Vec { let start_index: u128 = from_index.unwrap_or_default(); let campaigns_for_recipient_set = self.campaign_ids_by_recipient.get(&recipient_id); - let campaigns_for_recipient = if campaigns_for_recipient_set.is_none() { - vec![] - } else { - campaigns_for_recipient_set.unwrap().to_vec() + let campaigns_for_recipient = match campaigns_for_recipient_set { + Some(set) => set.iter().cloned().collect(), + None => vec![], }; + assert!( (campaigns_for_recipient.len() as u128) >= start_index, "Out of bounds, please use a smaller from_index." ); let limit = limit.map(|v| v as usize).unwrap_or(usize::MAX); assert_ne!(limit, 0, "Cannot provide limit of 0."); - campaigns_for_recipient - .iter() - .skip(start_index as usize) - .take(limit) - .map(|campaign_id| { - format_campaign( - &campaign_id, - &Campaign::from(self.campaigns_by_id.get(&campaign_id).unwrap()), - ) - }) - .collect() + self.take_limit(campaigns_for_recipient, start_index, limit) } } diff --git a/contracts/campaigns/src/constants.rs b/contracts/campaigns/src/constants.rs index 575189e..fcc927b 100644 --- a/contracts/campaigns/src/constants.rs +++ b/contracts/campaigns/src/constants.rs @@ -7,8 +7,8 @@ pub const MAX_CREATOR_FEE_BASIS_POINTS: u32 = 1000; // TODO: implement pub const EVENT_JSON_PREFIX: &str = "EVENT_JSON:"; pub const TGAS: u64 = 1_000_000_000_000; // 1 TGAS -pub const XCC_GAS_DEFAULT: u64 = TGAS * 10; // 10 TGAS -pub const MAX_TGAS: u64 = 300 * TGAS; // 300 TGAS +pub const XCC_GAS_DEFAULT: u64 = 10; // 10 TGAS +pub const MAX_TGAS: u64 = 300; // 300 TGAS pub const NO_DEPOSIT: Balance = 0; pub const ONE_YOCTO: Balance = 1; diff --git a/contracts/campaigns/src/donations.rs b/contracts/campaigns/src/donations.rs index 016e342..15926a6 100644 --- a/contracts/campaigns/src/donations.rs +++ b/contracts/campaigns/src/donations.rs @@ -2,8 +2,8 @@ use crate::*; /// * `Donation` is the data structure that is stored within the contract. /// * *NB: recipient & ft_id are stored in the Campaign struct.* -#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone, Debug)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[borsh, json])] +#[derive(Clone, Debug)] pub struct Donation { /// Unique identifier for the donation pub id: DonationId, @@ -32,7 +32,8 @@ pub struct Donation { // TODO: add paid_at_ms? } -#[derive(BorshSerialize, BorshDeserialize)] +#[near(serializers=[borsh])] +#[derive(Clone)] pub enum VersionedDonation { Current(Donation), } @@ -46,8 +47,8 @@ impl From for Donation { } /// Ephemeral-only (used in views) -#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[json])] +#[derive(Clone)] pub struct DonationExternal { /// Unique identifier for the donation pub id: DonationId, @@ -81,8 +82,8 @@ pub struct DonationExternal { pub recipient_id: AccountId, } -#[derive(Debug, Deserialize, Serialize)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[json])] +#[derive(Debug)] pub struct FtReceiverMsg { pub campaign_id: CampaignId, pub referrer_id: Option, @@ -91,8 +92,8 @@ pub struct FtReceiverMsg { pub bypass_creator_fee: Option, } -#[derive(Debug, Deserialize, Serialize, PartialEq)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[json])] +#[derive(Debug, PartialEq)] pub enum FundsReceiver { Recipient, Protocol, @@ -100,7 +101,7 @@ pub enum FundsReceiver { Creator, } -#[near_bindgen] +#[near] impl Contract { /// FT equivalent of donate, for use with FTs that implement NEP-144 pub fn ft_on_transfer( @@ -112,18 +113,19 @@ impl Contract { let ft_id = env::predecessor_account_id(); let msg_json: FtReceiverMsg = near_sdk::serde_json::from_str(&msg) .expect("Invalid msg string. Must implement FtReceiverMsg."); - log!(format!( + log!("{}", format!( "Campaign ID {:?}, Referrer ID {:?}, Amount {}, Message {:?}, ByPass Protocol Fee {:?}, ByPass Creator Fee {:?}", msg_json.campaign_id, msg_json.referrer_id, amount.0, msg_json.message, msg_json.bypass_protocol_fee, msg_json.bypass_creator_fee )); self.assert_campaign_live(&msg_json.campaign_id); // fetch campaign - let campaign = Campaign::from( - self.campaigns_by_id - .get(&msg_json.campaign_id) - .expect("Campaign not found"), - ); + let versioned_cp = self + .campaigns_by_id + .get(&msg_json.campaign_id) + .expect("Campaign not found") + .clone(); + let campaign = Campaign::from(versioned_cp); // verify that ft_id is correct for this campaign assert_eq!( @@ -131,9 +133,7 @@ impl Contract { Some(ft_id.clone()), "FT ID {} is not allowed for this campaign. Expected {}.", ft_id, - campaign - .ft_id - .unwrap_or(AccountId::new_unchecked("near".to_string())) + campaign.ft_id.unwrap_or("near".parse().unwrap()) ); // calculate amounts @@ -183,16 +183,17 @@ impl Contract { 3. Campaign is live, no min_amount or min_amount has been reached, donation is accepted and paid out */ self.assert_campaign_live(&campaign_id); - let campaign = Campaign::from( - self.campaigns_by_id - .get(&campaign_id) - .expect("Campaign not found"), - ); + let v_campaign = self + .campaigns_by_id + .get(&campaign_id) + .expect("Campaign not found") + .clone(); + let campaign = Campaign::from(v_campaign); // calculate amounts let amount = env::attached_deposit(); let (protocol_fee, referrer_fee, creator_fee, amount_after_fees) = self .calculate_fees_and_remainder( - amount.clone(), + amount.as_yoctonear(), &campaign, referrer_id.clone(), bypass_protocol_fee, @@ -204,7 +205,7 @@ impl Contract { id: self.next_donation_id, campaign_id, donor_id: env::predecessor_account_id(), - total_amount: amount, + total_amount: amount.as_yoctonear(), net_amount: amount_after_fees, message, donated_at_ms: env::block_timestamp_ms(), @@ -249,32 +250,44 @@ impl Contract { // update net_amount with storage taken out donation.net_amount = donation.net_amount - required_deposit; self.donations_by_id - .insert(&donation.id, &VersionedDonation::Current(donation.clone())); + .insert(donation.id, VersionedDonation::Current(donation.clone())); } if should_escrow { - log!(format!( - "Donation {} (ft_id {:?}) accepted but not paid out (escrowed) for campaign {}", - donation.net_amount, campaign.ft_id, donation.campaign_id - )); + log!( + "{}", + format!( + "Donation {} (ft_id {:?}) accepted but not paid out (escrowed) for campaign {}", + donation.net_amount, campaign.ft_id, donation.campaign_id + ) + ); // update campaign (raised_amount & escrow_balance) campaign.total_raised_amount += donation.total_amount; campaign.net_raised_amount += donation.net_amount; campaign.escrow_balance += donation.net_amount; self.campaigns_by_id.insert( - &donation.campaign_id, - &VersionedCampaign::Current(campaign.clone()), + donation.campaign_id, + VersionedCampaign::Current(campaign.clone()), ); + self.campaigns_by_id.flush(); // log event log_escrow_insert_event(&self.format_donation(&donation)); } else { // transfer donation - log!(format!( - "Transferring donation {} to {}", - donation.net_amount, - campaign.recipient.clone() - )); - self.handle_transfer_recipient_amount(self.format_donation(&donation)); + log!( + "{}", + format!( + "Transferring donation {} to {}", + donation.net_amount, + campaign.recipient.clone() + ) + ); + self.handle_transfer( + self.format_donation(&donation), + FundsReceiver::Recipient, + donation.net_amount.into(), + campaign.recipient.clone(), + ); // * NB: fees will be transferred in transfer_funds_callback after successful transfer to recipient } } @@ -282,84 +295,82 @@ impl Contract { pub(crate) fn internal_insert_donation_record(&mut self, donation: &Donation, escrow: bool) { // add to donations-by-id mapping self.donations_by_id - .insert(&donation.id, &VersionedDonation::Current(donation.clone())); + .insert(donation.id, VersionedDonation::Current(donation.clone())); + + self.donations_by_id.flush(); // insert into appropriate donations-by-campaign mapping, according to whether donation is escrowed or not if escrow { // insert into escrowed set - self.escrowed_donation_ids_by_campaign_id - .get(&donation.campaign_id) - .map(|mut v| v.insert(&donation.id)); + + if let Some(escrowed_set) = self.escrowed_donation_ids_by_campaign_id.get_mut(&donation.campaign_id) { + escrowed_set.insert(donation.id); + escrowed_set.flush(); + } + // ensure that donation is not in unescrowed or returned sets - self.unescrowed_donation_ids_by_campaign_id - .get(&donation.campaign_id) - .map(|mut v| v.remove(&donation.id)); - self.returned_donation_ids_by_campaign_id - .get(&donation.campaign_id) - .map(|mut v| v.remove(&donation.id)); + if let Some(unescrowed_set) = self.unescrowed_donation_ids_by_campaign_id.get_mut(&donation.campaign_id) { + unescrowed_set.remove(&donation.id); + unescrowed_set.flush(); + } + + if let Some(returned_donations) = self.returned_donation_ids_by_campaign_id.get_mut(&donation.campaign_id) { + returned_donations.insert(donation.id); + returned_donations.flush(); + } } else { - // insert into unescrowed set - self.unescrowed_donation_ids_by_campaign_id - .get(&donation.campaign_id) - .map(|mut v| v.insert(&donation.id)); - // ensure that donation is not in escrowed or returned sets - self.escrowed_donation_ids_by_campaign_id - .get(&donation.campaign_id) - .map(|mut v| v.remove(&donation.id)); - self.returned_donation_ids_by_campaign_id - .get(&donation.campaign_id) - .map(|mut v| v.remove(&donation.id)); + if let Some(unescrowed_set) = self.unescrowed_donation_ids_by_campaign_id.get_mut(&donation.campaign_id) { + unescrowed_set.insert(donation.id); + unescrowed_set.flush(); // Flush the unescrowed set + } + if let Some(escrowed_set) = self.escrowed_donation_ids_by_campaign_id.get_mut(&donation.campaign_id) { + escrowed_set.remove(&donation.id); + escrowed_set.flush(); + } + if let Some(returned_set) = self.returned_donation_ids_by_campaign_id.get_mut(&donation.campaign_id) { + returned_set.remove(&donation.id); + returned_set.flush(); + } } // insert into donations-by-donor mapping - let mut donation_ids_by_donor_set = if let Some(donation_ids_by_donor_set) = - self.donation_ids_by_donor_id.get(&donation.donor_id) - { - donation_ids_by_donor_set + if let Some(donation_ids) = self.donation_ids_by_donor_id.get_mut(&donation.donor_id) { + donation_ids.insert(donation.id); + donation_ids.flush(); } else { - UnorderedSet::new(StorageKey::DonationIdsByDonorIdInner { + let mut new_set = IterableSet::new(StorageKey::DonationIdsByDonorIdInner { donor_id: donation.donor_id.clone(), - }) - }; - donation_ids_by_donor_set.insert(&donation.id); - self.donation_ids_by_donor_id - .insert(&donation.donor_id, &donation_ids_by_donor_set); + }); + new_set.insert(donation.id); + new_set.flush(); + self.donation_ids_by_donor_id.insert(donation.donor_id.clone(), new_set); + self.donation_ids_by_donor_id.flush(); + } } pub(crate) fn internal_remove_donation_record(&mut self, donation: &Donation) { - // remove from donations-by-id mapping + // Remove from donations-by-id mapping self.donations_by_id.remove(&donation.id); - - // remove from donations-by-campaign mappings - let mut escrowed_donation_ids_by_campaign_set = self - .escrowed_donation_ids_by_campaign_id - .get(&donation.campaign_id) - .expect("Campaign not found"); - escrowed_donation_ids_by_campaign_set.remove(&donation.id); - self.escrowed_donation_ids_by_campaign_id.insert( - &donation.campaign_id, - &escrowed_donation_ids_by_campaign_set, - ); - - let mut unescrowed_donation_ids_by_campaign_set = self - .unescrowed_donation_ids_by_campaign_id - .get(&donation.campaign_id) - .expect("Campaign not found"); - unescrowed_donation_ids_by_campaign_set.remove(&donation.id); - self.unescrowed_donation_ids_by_campaign_id.insert( - &donation.campaign_id, - &unescrowed_donation_ids_by_campaign_set, - ); - - // remove from donations-by-donor mapping - let mut donation_ids_by_donor_set = self - .donation_ids_by_donor_id - .get(&donation.donor_id) - .expect("Donor not found"); - donation_ids_by_donor_set.remove(&donation.id); - self.donation_ids_by_donor_id - .insert(&donation.donor_id, &donation_ids_by_donor_set); + self.donations_by_id.flush(); + + // Remove from donations-by-campaign mappings + if let Some(escrowed_set) = self.escrowed_donation_ids_by_campaign_id.get_mut(&donation.campaign_id) { + escrowed_set.remove(&donation.id); + escrowed_set.flush(); // Flush the escrowed set + } + + if let Some(unescrowed_set) = self.unescrowed_donation_ids_by_campaign_id.get_mut(&donation.campaign_id) { + unescrowed_set.remove(&donation.id); + unescrowed_set.flush(); // Flush the unescrowed set + } + + // Remove from donations-by-donor mapping + if let Some(donor_set) = self.donation_ids_by_donor_id.get_mut(&donation.donor_id) { + donor_set.remove(&donation.id); + donor_set.flush(); // Flush the donor set + } } + // GETTERS @@ -379,14 +390,24 @@ impl Contract { .iter() .skip(start_index as usize) .take(limit) - .map(|(_, v)| self.format_donation(&Donation::from(v))) + .map(|(_, v)| self.format_donation(&Donation::from(v.clone()))) .collect() } pub fn get_donation_by_id(&self, donation_id: DonationId) -> Option { self.donations_by_id .get(&donation_id) - .map(|v| self.format_donation(&Donation::from(v))) + .map(|v| self.format_donation(&Donation::from(v.clone()))) + } + + pub fn get_donatio(&self, campaign_id: CampaignId) -> Vec { + // self.escrowed_donation_ids_by_campaign_id.len() + let es_set = self + .escrowed_donation_ids_by_campaign_id + .get(&campaign_id) + .expect("go home.."); + + es_set.iter().cloned().collect() } pub fn get_donations_for_campaign( @@ -404,20 +425,35 @@ impl Contract { assert_ne!(limit, 0, "Cannot provide limit of 0."); let escrowed_donation_ids_by_campaign_set = self.escrowed_donation_ids_by_campaign_id.get(&campaign_id); - let escrowed_donation_ids_vec = if let Some(escrowed_donation_ids_by_campaign_set) = + let escrowed_donation_ids_vec = if let Some(ref escrowed_donation_ids_by_campaign_set) = escrowed_donation_ids_by_campaign_set { - escrowed_donation_ids_by_campaign_set.to_vec() + escrowed_donation_ids_by_campaign_set + .iter() + .cloned() + .collect() } else { vec![] }; + + log!( + "{}", + format!( + "Escrowed donations for campaign {:?}: {:?}", + escrowed_donation_ids_by_campaign_set, escrowed_donation_ids_vec + ) + ); + let unescrowed_donation_ids_by_campaign_set = self .unescrowed_donation_ids_by_campaign_id .get(&campaign_id); let unescrowed_donation_ids_vec = if let Some(unescrowed_donation_ids_by_campaign_set) = unescrowed_donation_ids_by_campaign_set { - unescrowed_donation_ids_by_campaign_set.to_vec() + unescrowed_donation_ids_by_campaign_set + .iter() + .cloned() + .collect() } else { vec![] }; @@ -433,7 +469,7 @@ impl Contract { .take(limit) .map(|donation_id| { self.format_donation(&Donation::from( - self.donations_by_id.get(&donation_id).unwrap(), + self.donations_by_id.get(&donation_id).unwrap().clone(), )) }) .collect() @@ -444,8 +480,8 @@ impl Contract { donor_id: AccountId, from_index: Option, limit: Option, - ) -> Vec { - let start_index: u128 = from_index.unwrap_or_default(); + ) -> u32 { + // let start_index: u128 = from_index.unwrap_or_default(); // TODO: ADD BELOW BACK IN // assert!( // (self.donations_by_id.len() as u128) >= start_index, @@ -454,28 +490,30 @@ impl Contract { let limit = limit.map(|v| v as usize).unwrap_or(usize::MAX); assert_ne!(limit, 0, "Cannot provide limit of 0."); let donation_ids_by_donor_set = self.donation_ids_by_donor_id.get(&donor_id); - if let Some(donation_ids_by_donor_set) = donation_ids_by_donor_set { - donation_ids_by_donor_set - .iter() - .skip(start_index as usize) - .take(limit) - .map(|donation_id| { - self.format_donation(&Donation::from( - self.donations_by_id.get(&donation_id).unwrap(), - )) - }) - .collect() - } else { - vec![] - } + donation_ids_by_donor_set.unwrap().len() + // if let Some(donation_ids_by_donor_set) = donation_ids_by_donor_set { + // donation_ids_by_donor_set + // .iter() + // .skip(start_index as usize) + // .take(limit) + // .map(|donation_id| { + // self.format_donation(&Donation::from( + // self.donations_by_id.get(&donation_id).unwrap().clone(), + // )) + // }) + // .collect() + // } else { + // vec![] + // } } pub(crate) fn format_donation(&self, donation: &Donation) -> DonationExternal { - let campaign = Campaign::from( - self.campaigns_by_id - .get(&donation.campaign_id) - .expect("Campaign not found"), - ); + let cp_donation = self + .campaigns_by_id + .get(&donation.campaign_id) + .expect("Campaign not found") + .clone(); + let campaign = Campaign::from(cp_donation); DonationExternal { id: donation.id, campaign_id: donation.campaign_id.clone(), @@ -505,7 +543,7 @@ impl Contract { campaign_id: donation.campaign_id.clone(), donor_id: donation.donor_id.clone(), total_amount: donation.total_amount.0, - net_amount: 0, + net_amount: donation.net_amount.into(), message: donation.message.clone(), donated_at_ms: donation.donated_at_ms, protocol_fee: donation.protocol_fee.0, diff --git a/contracts/campaigns/src/escrow.rs b/contracts/campaigns/src/escrow.rs index b28ea71..b902dbb 100644 --- a/contracts/campaigns/src/escrow.rs +++ b/contracts/campaigns/src/escrow.rs @@ -1,42 +1,46 @@ use crate::*; /// Temporary record for refunding donations in batches. Includes an amount which may represent many donations. -#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[borsh, json])] +#[derive(Clone)] pub struct TempRefundRecord { pub amount: Balance, + pub escrow_balance: Balance, pub donations: Vec, } pub type ReferrerPayouts = HashMap; -#[near_bindgen] +#[near] impl Contract { /// * Process (aka move out of escrow) a batch of escrowed donations for a campaign /// * Can be called by anyone willing to pay the gas (max gas to avoid hitting gas limits) /// * Will return void without panicking if min_amount has not been reached + + #[payable] pub fn process_escrowed_donations_batch(&mut self, campaign_id: CampaignId) { assert!( - env::prepaid_gas() >= Gas(MAX_TGAS), + env::prepaid_gas() >= Gas::from_tgas(MAX_TGAS), "Must attach max gas to process donations" ); - let campaign = Campaign::from( - self.campaigns_by_id - .get(&campaign_id) - .expect("Campaign not found"), - ); + let cp_to_process = self + .campaigns_by_id + .get(&campaign_id) + .expect("Campaign not found") + .clone(); + let campaign = Campaign::from(cp_to_process); assert!( campaign.total_raised_amount >= campaign.min_amount.unwrap_or(u128::MAX), "Cannot process donations until min_amount has been reached" ); // Proceed with processing donations - let mut escrowed_donation_ids = self + let escrowed_donation_ids = self .escrowed_donation_ids_by_campaign_id - .get(&campaign_id) + .get_mut(&campaign_id) .expect("No escrowed donations set found for campaign"); - let mut unescrowed_donation_ids = self + let unescrowed_donation_ids = self .unescrowed_donation_ids_by_campaign_id - .get(&campaign_id) + .get_mut(&campaign_id) .expect("No unescrowed donations set found for campaign"); // calculate totals to pay out for recipient, protocol fee, creator fee, and referral fees let mut recipient_total: Balance = 0; // only one recipient @@ -45,30 +49,38 @@ impl Contract { let mut referrer_payouts: ReferrerPayouts = HashMap::new(); // potentially multiple referral fee recipients // get batch of escrowed donations to process - let mut escrowed_donation_ids_vec = escrowed_donation_ids.to_vec(); + let mut escrowed_donation_ids_vec: Vec = + escrowed_donation_ids.iter().cloned().collect(); let donation_ids_batch = escrowed_donation_ids_vec .drain(0..std::cmp::min(BATCH_SIZE, escrowed_donation_ids_vec.len())) .collect::>(); // process donation_ids_batch - log!(format!( - "Processing {} donations for campaign {}", - donation_ids_batch.len(), - campaign_id - )); + log!( + "{}", + format!( + "Processing {} donations for campaign {}", + donation_ids_batch.len(), + campaign_id + ) + ); for donation_id in donation_ids_batch.iter() { let donation = Donation::from( self.donations_by_id .get(&donation_id) - .expect("Donation not found"), + .expect("Donation not found") + .clone(), ); // verify that donation has not been refunded (should not be in escrowed_donation_ids if it has been refunded, but just to be safe) if donation.returned_at_ms.is_some() { continue; } - log!(format!( - "Processing donation {:#?} for campaign {:#?}", - donation_id, campaign_id - )); + log!( + "{}", + format!( + "Processing donation {:#?} for campaign {:#?}", + donation_id, campaign_id + ) + ); // calculate total amount to pay out for recipient, protocol fee, creator fee, and referral fees // NB: there may be many referrers, but only one recipient, protocol fee recipient, and creator fee recipient recipient_total += donation.net_amount; @@ -81,20 +93,19 @@ impl Contract { // remove donation from escrowed_donation_ids // TODO: revert if transfer fails escrowed_donation_ids.remove(&donation.id); // add to unescrowed_donation_ids - unescrowed_donation_ids.insert(&donation.id); // TODO: revert if transfer fails + unescrowed_donation_ids.insert(donation.id); // TODO: revert if transfer fails + escrowed_donation_ids.flush(); + unescrowed_donation_ids.flush(); } - // insert updated escrowed_donation_ids - self.escrowed_donation_ids_by_campaign_id - .insert(&campaign_id, &escrowed_donation_ids); - // insert updated unescrowed_donation_ids - self.unescrowed_donation_ids_by_campaign_id - .insert(&campaign_id, &unescrowed_donation_ids); // transfer payouts to recipients if recipient_total > 0 { - log!(format!( - "Transferring {} to campaign recipient {} for campaign {}", - recipient_total, campaign.recipient, campaign_id - )); + log!( + "{}", + format!( + "Transferring {} to campaign recipient {} for campaign {}", + recipient_total, campaign.recipient, campaign_id + ) + ); self.internal_transfer_amount( recipient_total, campaign.recipient.clone(), @@ -102,7 +113,7 @@ impl Contract { ) .then( Self::ext(env::current_account_id()) - .with_static_gas(Gas(XCC_GAS_DEFAULT)) + .with_static_gas(Gas::from_tgas(XCC_GAS_DEFAULT)) .escrowed_donations_recipient_transfer_callback( recipient_total, campaign.recipient.clone(), @@ -134,49 +145,57 @@ impl Contract { // * Recipient amount transfer failed // * Revert Donation.returned_at_ms and re-insert donations into escrowed_donation_ids, remove from unescrowed_donation_ids // * NB: fees haven't been transferred yet, so no need to worry about those - log!(format!("Error transferring amount {:#?} to recipient {:#?} for donations {:#?} in campaign {:#?}", amount, recipient, donation_ids, campaign_id)); - let mut escrowed_donation_ids = self + log!("{}", format!("Error transferring amount {:#?} to recipient {:#?} for donations {:#?} in campaign {:#?}", amount, recipient, donation_ids, campaign_id)); + let escrowed_donation_ids = self .escrowed_donation_ids_by_campaign_id - .get(&campaign_id) + .get_mut(&campaign_id) .expect("No escrowed donations found for campaign"); - let mut unescrowed_donation_ids = self + let unescrowed_donation_ids = self .unescrowed_donation_ids_by_campaign_id - .get(&campaign_id) + .get_mut(&campaign_id) .expect("No unescrowed donations found for campaign"); for donation_id in donation_ids.iter() { // re-insert donations into escrowed_donation_ids - escrowed_donation_ids.insert(donation_id); + escrowed_donation_ids.insert(*donation_id); // remove donations from unescrowed_donation_ids unescrowed_donation_ids.remove(donation_id); + escrowed_donation_ids.flush(); + unescrowed_donation_ids.flush(); // revert Donation.returned_at_ms - let mut donation = Donation::from( - self.donations_by_id - .get(&donation_id) - .expect("Donation not found"), - ); + let v_donation = self + .donations_by_id + .get(&donation_id) + .expect("Donation not found") + .clone(); + let mut donation = Donation::from(v_donation); donation.returned_at_ms = None; self.donations_by_id - .insert(&donation_id.clone(), &VersionedDonation::Current(donation)); + .insert(donation_id.clone(), VersionedDonation::Current(donation)); + self.donations_by_id.flush(); } } else { // * SUCCESS HANDLING - log!(format!( + log!("{}", format!( "Successfully transferred amount {:#?} to recipient {:#?} for donations {:#?} in campaign {:#?}", amount, recipient, donation_ids, campaign_id )); // log event log_escrow_process_event(&donation_ids); // send fees - let campaign = Campaign::from( - self.campaigns_by_id - .get(&campaign_id) - .expect("Campaign not found"), - ); + let v_campaign = self + .campaigns_by_id + .get(&campaign_id) + .expect("Campaign not found") + .clone(); + let campaign = Campaign::from(v_campaign); if protocol_fee > 0 { - log!(format!( - "Transferring {} to protocol fee recipient {} for campaign {}", - protocol_fee, self.protocol_fee_recipient_account, campaign_id - )); + log!( + "{}", + format!( + "Transferring {} to protocol fee recipient {} for campaign {}", + protocol_fee, self.protocol_fee_recipient_account, campaign_id + ) + ); self.internal_transfer_amount( protocol_fee, self.protocol_fee_recipient_account.clone(), @@ -184,7 +203,7 @@ impl Contract { ) .then( Self::ext(env::current_account_id()) - .with_static_gas(Gas(XCC_GAS_DEFAULT)) + .with_static_gas(Gas::from_tgas(XCC_GAS_DEFAULT)) .escrowed_donations_fee_transfer_callback( protocol_fee, self.protocol_fee_recipient_account.clone(), @@ -195,10 +214,13 @@ impl Contract { ); } if creator_fee > 0 { - log!(format!( - "Transferring {} to campaign owner {} for campaign {}", - creator_fee, campaign.owner, campaign_id - )); + log!( + "{}", + format!( + "Transferring {} to campaign owner {} for campaign {}", + creator_fee, campaign.owner, campaign_id + ) + ); self.internal_transfer_amount( creator_fee, campaign.owner.clone(), @@ -206,7 +228,7 @@ impl Contract { ) .then( Self::ext(env::current_account_id()) - .with_static_gas(Gas(XCC_GAS_DEFAULT)) + .with_static_gas(Gas::from_tgas(XCC_GAS_DEFAULT)) .escrowed_donations_fee_transfer_callback( creator_fee, campaign.owner.clone(), @@ -217,14 +239,17 @@ impl Contract { ); } for (referrer_id, amount) in referrer_payouts.iter() { - log!(format!( - "Transferring referrer payouts for campaign {:#?}: {:#?}", - campaign_id, referrer_payouts - )); + log!( + "{}", + format!( + "Transferring referrer payouts for campaign {:#?}: {:#?}", + campaign_id, referrer_payouts + ) + ); self.internal_transfer_amount(*amount, referrer_id.clone(), campaign.ft_id.clone()) .then( Self::ext(env::current_account_id()) - .with_static_gas(Gas(XCC_GAS_DEFAULT)) + .with_static_gas(Gas::from_tgas(XCC_GAS_DEFAULT)) .escrowed_donations_fee_transfer_callback( *amount, referrer_id.clone(), @@ -252,16 +277,18 @@ impl Contract { // * Fee transfer failed // * Based on receiver_type, set relevant field on Donation (protocol_fee/referrer_fee/creator_fee) to 0 // * NB: recipient amount has already been transferred and cannot be reverted - log!(format!( + // why set to 0? + log!("{}", format!( "Error transferring fee {:#?} to {:#?} ({:#?}) for donations {:#?} in campaign {:#?}", amount, recipient, receiver_type, donation_ids, campaign_id )); for donation_id in donation_ids.iter() { - let mut donation = Donation::from( - self.donations_by_id - .get(&donation_id) - .expect("Donation not found"), - ); + let dnm = self + .donations_by_id + .get(&donation_id) + .expect("Donation not found") + .clone(); + let mut donation = Donation::from(dnm); match receiver_type { FundsReceiver::Protocol => { donation.protocol_fee = 0; @@ -275,39 +302,32 @@ impl Contract { _ => {} } self.donations_by_id - .insert(&donation_id.clone(), &VersionedDonation::Current(donation)); + .insert(donation_id.clone(), VersionedDonation::Current(donation)); } } else { // * SUCCESS HANDLING - if receiver_type == FundsReceiver::Protocol { - log!(format!( - "Successfully transferred amount {:#?} to recipient {:#?} for campaign {:#?}", - amount, recipient, campaign_id - )); - } else if receiver_type == FundsReceiver::Creator { - log!(format!( - "Successfully transferred amount {:#?} to protocol fee recipient {:#?} for campaign {:#?}", - amount, recipient, campaign_id - )); - } else if receiver_type == FundsReceiver::Referrer { - log!(format!( - "Successfully transferred amount {:#?} to referrer {:#?} for campaign {:#?}", - amount, recipient, campaign_id - )); - } + log!( + "{}", + format!( + "Successfully transferred amount {:?} to {:?} {:?} for campaign {:?}", + amount, receiver_type, recipient, campaign_id + ) + ); } } + #[payable] pub fn process_refunds_batch(&mut self, campaign_id: CampaignId) { // OBJECTIVES: // Donors must always be able to get their money out if campaign has ended and minimum amount has not been reached, and they have not been refunded yet // Refunds should be processed in batches to avoid hitting gas limits // Can be processed by anyone willing to pay the gas - let campaign = Campaign::from( - self.campaigns_by_id - .get(&campaign_id) - .expect("Campaign not found"), - ); + let cp = self + .campaigns_by_id + .get(&campaign_id) + .expect("Campaign not found") + .clone(); + let campaign = Campaign::from(cp); // Anyone can process refunds for a campaign if it has ended and min_amount has not been reached assert!( campaign.end_ms.unwrap_or(u64::MAX) < env::block_timestamp_ms(), @@ -322,7 +342,8 @@ impl Contract { .escrowed_donation_ids_by_campaign_id .get(&campaign_id) .expect("No escrowed donations found for campaign"); - let mut escrowed_donation_ids_vec = escrowed_donation_ids.to_vec(); + let mut escrowed_donation_ids_vec: Vec = + escrowed_donation_ids.iter().cloned().collect(); let mut refunds: HashMap = HashMap::new(); let batch = escrowed_donation_ids_vec .drain(0..std::cmp::min(BATCH_SIZE, escrowed_donation_ids_vec.len())) @@ -331,7 +352,8 @@ impl Contract { let mut donation = Donation::from( self.donations_by_id .get(&donation_id) - .expect("Donation not found"), + .expect("Donation not found") + .clone(), ); // verify that donation has not already been refunded (should not be the case if it is in escrowed_donation_ids, but just to be safe) if donation.returned_at_ms.is_some() { @@ -344,8 +366,8 @@ impl Contract { // temporarily remove donation record to check how much storage cost is (donation won't actually be deleted on refund) self.internal_remove_donation_record(&donation); let storage_after = env::storage_usage(); - refund_amount -= - Balance::from(storage_after - storage_before) * env::storage_byte_cost(); + refund_amount -= Balance::from(storage_before - storage_after) + * env::storage_byte_cost().as_yoctonear(); // add donation record back (as an escrowed donation) self.internal_insert_donation_record(&donation, true); // add refund amount to current balance for donor, or create new entry. Include donation IDs for use in callback @@ -354,9 +376,11 @@ impl Contract { .entry(donation.donor_id.clone()) .or_insert(TempRefundRecord { amount: 0, + escrow_balance: 0, donations: vec![], }); temp_refund_record.amount += refund_amount; + temp_refund_record.escrow_balance += donation.net_amount; temp_refund_record.donations.push(donation); // TODO: also remove donation from escrowed_donation_ids? (or just leave it there and update Donation.returned_at_ms) } @@ -369,7 +393,7 @@ impl Contract { ) .then( Self::ext(env::current_account_id()) - .with_static_gas(Gas(XCC_GAS_DEFAULT)) + .with_static_gas(Gas::from_tgas(XCC_GAS_DEFAULT)) .transfer_refund_callback(donor_id.clone(), refund_record.clone(), campaign_id), ); } @@ -388,7 +412,7 @@ impl Contract { // * Refund failed // * Log failure // * Revert Donation.returned_at_ms for each donation, and re-insert into escrowed_donation_ids - log!(format!( + log!("{}", format!( "Error transferring refund amount {:#?} to donor {:#?} for donations {:#?} in campaign {:#?}", temp_refund_record.amount, donor_id, temp_refund_record.donations, campaign_id )); @@ -398,7 +422,7 @@ impl Contract { } } else { // * Refund successful - log!(format!( + log!("{}", format!( "Successfully transferred refund amount {:#?} to donor {:#?} for donations {:#?} in campaign {:#?}", temp_refund_record.amount, donor_id, temp_refund_record.donations, campaign_id )); @@ -410,14 +434,47 @@ impl Contract { let mut campaign = Campaign::from( self.campaigns_by_id .get(&campaign_id) - .expect("Campaign not found"), + .expect("Campaign not found") + .clone(), ); - campaign.escrow_balance -= temp_refund_record.amount; + campaign.escrow_balance -= temp_refund_record.escrow_balance; self.campaigns_by_id - .insert(&campaign_id, &VersionedCampaign::Current(campaign)); + .insert(campaign_id, VersionedCampaign::Current(campaign)); // NB: keeping Campaign.total_raised_amount and Campaign.net_raised_amount the same (use these as record of total donations to campaign) // log event - log_escrow_refund_event(&temp_refund_record); + log_escrow_refund_event(&temp_refund_record, &campaign_id); + } + } + + /// Returns true if there are escrowed donations to process and campaign has met its minimum amount + pub fn has_escrowed_donations_to_process(&self, campaign_id: CampaignId) -> bool { + if let Some(campaign) = self.campaigns_by_id.get(&campaign_id) { + let campaign = Campaign::from(campaign.clone()); + let min_amount = campaign.min_amount.unwrap_or(u128::MAX); + if campaign.total_raised_amount >= min_amount { + return self.escrowed_donation_ids_by_campaign_id + .get(&campaign_id) + .map(|set| !set.is_empty()) + .unwrap_or(false); + } + } + false + } + + /// Returns true if refunds can be processed (campaign ended, below min amount, and has escrowed donations) + pub fn can_process_refunds(&self, campaign_id: CampaignId) -> bool { + if let Some(campaign) = self.campaigns_by_id.get(&campaign_id) { + let campaign = Campaign::from(campaign.clone()); + let current_time = env::block_timestamp_ms(); + let has_ended = campaign.end_ms.unwrap_or(u64::MAX) < current_time; + let below_min = campaign.total_raised_amount < campaign.min_amount.unwrap_or(u128::MAX); + let has_escrowed = self.escrowed_donation_ids_by_campaign_id + .get(&campaign_id) + .map(|set| !set.is_empty()) + .unwrap_or(false); + + return has_ended && below_min && has_escrowed; } + false } } diff --git a/contracts/campaigns/src/events.rs b/contracts/campaigns/src/events.rs index 9c350c1..c0ddf25 100644 --- a/contracts/campaigns/src/events.rs +++ b/contracts/campaigns/src/events.rs @@ -128,7 +128,7 @@ pub(crate) fn log_escrow_insert_event(donation: &DonationExternal) { } /// escrowed donation refund -pub(crate) fn log_escrow_refund_event(temp_refund_record: &TempRefundRecord) { +pub(crate) fn log_escrow_refund_event(temp_refund_record: &TempRefundRecord, campaign_id: &CampaignId) { env::log_str( format!( "{}{}", @@ -139,8 +139,10 @@ pub(crate) fn log_escrow_refund_event(temp_refund_record: &TempRefundRecord) { "event": "escrow_refund", "data": [ { - "amount": temp_refund_record.amount, - "donations": temp_refund_record.donations, + "campaign_id": campaign_id, + "amount": temp_refund_record.amount.to_string(), // total amount refunded + "escrow_balance": temp_refund_record.escrow_balance.to_string(), // escrow balance after refund + "donations": temp_refund_record.donations.iter().map(|d| d.id).collect::>() } ] }) diff --git a/contracts/campaigns/src/internal.rs b/contracts/campaigns/src/internal.rs index b682fec..5e3e2c5 100644 --- a/contracts/campaigns/src/internal.rs +++ b/contracts/campaigns/src/internal.rs @@ -1,10 +1,10 @@ use crate::*; -#[near_bindgen] +#[near] impl Contract { pub(crate) fn assert_at_least_one_yocto(&self) { assert!( - env::attached_deposit() >= 1, + env::attached_deposit().as_yoctonear() >= 1, "At least one yoctoNEAR must be attached" ); } @@ -29,11 +29,11 @@ impl Contract { } pub(crate) fn assert_campaign_owner(&self, campaign_id: &CampaignId) { - let campaign = Campaign::from( - self.campaigns_by_id - .get(campaign_id) - .expect("Campaign not found"), - ); + let bc = self + .campaigns_by_id + .get(campaign_id) + .expect("campaign notfound"); + let campaign = Campaign::from(bc.clone()); assert_eq!( env::predecessor_account_id(), campaign.owner, @@ -46,7 +46,8 @@ impl Contract { let campaign = Campaign::from( self.campaigns_by_id .get(campaign_id) - .expect("Campaign not found"), + .expect("Campaign not found") + .clone(), ); assert!( campaign.start_ms <= env::block_timestamp_ms(), @@ -82,11 +83,11 @@ impl Contract { Promise::new(ft_id).function_call( "ft_transfer".to_string(), ft_transfer_args, - ONE_YOCTO, - Gas(XCC_GAS_DEFAULT), + NearToken::from_yoctonear(ONE_YOCTO), + Gas::from_tgas(XCC_GAS_DEFAULT), ) } else { - Promise::new(recipient).transfer(amount) + Promise::new(recipient).transfer(NearToken::from_yoctonear(amount)) } } @@ -97,47 +98,65 @@ impl Contract { ) { // Insert campaign record self.campaigns_by_id - .insert(&campaign_id, &VersionedCampaign::Current(campaign.clone())); - - // Insert campaign ID into owner's and recipient's lists - let mut campaign_ids_for_owner = - self.campaign_ids_by_owner - .get(&campaign.owner) - .unwrap_or(UnorderedSet::new(StorageKey::CampaignIdsByOwnerInner { - owner_id: campaign.owner.clone(), - })); - campaign_ids_for_owner.insert(&campaign_id); + .insert(*campaign_id, VersionedCampaign::Current(campaign.clone())); + + // flush keys + self.campaigns_by_id.flush(); + + let campaign_by_owner_set: &mut IterableSet = self.campaign_ids_by_owner - .insert(&campaign.owner, &campaign_ids_for_owner); - let mut campaign_ids_for_recipient = self - .campaign_ids_by_recipient - .get(&campaign.recipient) - .unwrap_or(UnorderedSet::new(StorageKey::CampaignIdsByRecipientInner { - recipient_id: campaign.recipient.clone(), + .entry(campaign.owner.clone()) + .or_insert_with(|| IterableSet::new(StorageKey::CampaignIdsByOwnerInner { + owner_id: campaign.owner.clone(), })); - campaign_ids_for_recipient.insert(&campaign_id); + campaign_by_owner_set.insert(*campaign_id); + campaign_by_owner_set.flush(); // Flush the inner IterableSet + self.campaign_ids_by_owner.flush(); // Flush the outer mapping + + let campaign_by_recipient_set: &mut IterableSet = self.campaign_ids_by_recipient - .insert(&campaign.recipient, &campaign_ids_for_recipient); - - // Insert empty donation ID lists for campaign - self.escrowed_donation_ids_by_campaign_id.insert( - &campaign_id, - &UnorderedSet::new(StorageKey::EscrowedDonationIdsByCampaignIdInner { - campaign_id: campaign_id.clone(), - }), - ); + .entry(campaign.recipient.clone()) + .or_insert_with(|| IterableSet::new(StorageKey::CampaignIdsByRecipientInner { + recipient_id: campaign.recipient.clone(), + })); + campaign_by_recipient_set.insert(*campaign_id); + campaign_by_recipient_set.flush(); // Flush the inner IterableSet + self.campaign_ids_by_recipient.flush(); // Flush the outer mapping + + + let mut escrowed_by_camp_id = IterableSet::new(StorageKey::EscrowedDonationIdsByCampaignIdInner { + campaign_id: campaign_id.clone(), + }); + escrowed_by_camp_id.flush(); + self.escrowed_donation_ids_by_campaign_id + .insert(*campaign_id, escrowed_by_camp_id); + self.escrowed_donation_ids_by_campaign_id.flush(); + + let mut unescrowed_camp_id = IterableSet::new(StorageKey::UnescrowedDonationIdsByCampaignIdInner { + campaign_id: campaign_id.clone(), + }); + + unescrowed_camp_id.flush(); + self.unescrowed_donation_ids_by_campaign_id.insert( - &campaign_id, - &UnorderedSet::new(StorageKey::UnescrowedDonationIdsByCampaignIdInner { - campaign_id: campaign_id.clone(), - }), + *campaign_id, + unescrowed_camp_id, ); + + self.unescrowed_donation_ids_by_campaign_id.flush(); + + let mut returned_dona_id_set = IterableSet::new(StorageKey::ReturnedDonationIdsByCampaignIdInner { + campaign_id: campaign_id.clone(), + }); + + returned_dona_id_set.flush(); + self.returned_donation_ids_by_campaign_id.insert( - &campaign_id, - &UnorderedSet::new(StorageKey::ReturnedDonationIdsByCampaignIdInner { - campaign_id: campaign_id.clone(), - }), + *campaign_id, + returned_dona_id_set, ); + + self.returned_donation_ids_by_campaign_id.flush(); } /// * Removes a campaign and all records of its ID from storage @@ -146,45 +165,47 @@ impl Contract { let campaign = Campaign::from( self.campaigns_by_id .get(&campaign_id) - .expect("Campaign not found"), + .expect("Campaign not found") + .clone(), ); + // Cannot delete campaign if it has started assert!( campaign.start_ms > env::block_timestamp_ms(), "Cannot delete campaign once it has started" ); + // Cannot delete campaign if it has donations let donations_for_campaign = self.get_donations_for_campaign(campaign_id, None, None); assert!( donations_for_campaign.is_empty(), "Cannot delete campaign with donations" ); - + // Remove campaign record self.campaigns_by_id.remove(&campaign_id); - + self.campaigns_by_id.flush(); // Flush after removing campaign + // Remove campaign ID from owner's and recipient's lists - let mut campaign_ids_for_owner = self - .campaign_ids_by_owner - .get(&campaign.owner) - .expect("Campaign owner not found"); - campaign_ids_for_owner.remove(&campaign_id); - self.campaign_ids_by_owner - .insert(&campaign.owner, &campaign_ids_for_owner); - let mut campaign_ids_for_recipient = self - .campaign_ids_by_recipient - .get(&campaign.recipient) - .expect("Campaign recipient not found"); - campaign_ids_for_recipient.remove(&campaign_id); - + if let Some(owner_campaigns) = self.campaign_ids_by_owner.get_mut(&campaign.owner) { + owner_campaigns.remove(&campaign_id); + owner_campaigns.flush(); // Flush owner's campaigns list + } + + if let Some(recipient_campaigns) = self.campaign_ids_by_recipient.get_mut(&campaign.recipient) { + recipient_campaigns.remove(&campaign_id); + recipient_campaigns.flush(); // Flush recipient's campaigns list + } + // Remove donation ID lists for campaign - self.campaign_ids_by_recipient - .insert(&campaign.recipient, &campaign_ids_for_recipient); - self.escrowed_donation_ids_by_campaign_id - .remove(&campaign_id); - self.unescrowed_donation_ids_by_campaign_id - .remove(&campaign_id); - self.returned_donation_ids_by_campaign_id - .remove(&campaign_id); + self.escrowed_donation_ids_by_campaign_id.remove(&campaign_id); + self.escrowed_donation_ids_by_campaign_id.flush(); // Flush escrowed donations list + + self.unescrowed_donation_ids_by_campaign_id.remove(&campaign_id); + self.unescrowed_donation_ids_by_campaign_id.flush(); // Flush unescrowed donations list + + self.returned_donation_ids_by_campaign_id.remove(&campaign_id); + self.returned_donation_ids_by_campaign_id.flush(); // Flush returned donations list } + } diff --git a/contracts/campaigns/src/lib.rs b/contracts/campaigns/src/lib.rs index d334b12..2c288b6 100644 --- a/contracts/campaigns/src/lib.rs +++ b/contracts/campaigns/src/lib.rs @@ -1,9 +1,7 @@ -use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; -use near_sdk::collections::{LazyOption, LookupMap, UnorderedMap, UnorderedSet}; -use near_sdk::json_types::{U128, U64}; -use near_sdk::serde::{Deserialize, Serialize}; +use near_sdk::json_types::U128; +use near_sdk::store::{IterableMap, IterableSet, LazyOption}; use near_sdk::{ - env, log, near_bindgen, require, serde_json::json, AccountId, Balance, BorshStorageKey, Gas, + env, log, near, require, serde_json::json, AccountId, BorshStorageKey, Gas, NearToken, PanicOnDefault, Promise, PromiseError, PromiseOrValue, }; use std::collections::HashMap; @@ -18,7 +16,6 @@ pub mod internal; pub mod owner; pub mod source; pub mod storage; -pub mod tests; pub mod transfer; pub mod utils; pub mod validation; @@ -32,7 +29,6 @@ pub use crate::internal::*; pub use crate::owner::*; pub use crate::source::*; pub use crate::storage::*; -pub use crate::tests::*; pub use crate::transfer::*; pub use crate::utils::*; pub use crate::validation::*; @@ -40,35 +36,37 @@ pub use crate::validation::*; type DonationId = u64; type TimestampMs = u64; +pub type Balance = u128; + /// CURRENT Campaigns Contract -#[near_bindgen] -#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)] +#[near(contract_state)] +#[derive(PanicOnDefault)] pub struct Contract { /// Contract "source" metadata, as specified in NEP 0330 (https://github.com/near/NEPs/blob/master/neps/nep-0330.md), with addition of `commit_hash` contract_source_metadata: LazyOption, owner: AccountId, - admins: UnorderedSet, + admins: IterableSet, protocol_fee_basis_points: u32, protocol_fee_recipient_account: AccountId, default_referral_fee_basis_points: u32, default_creator_fee_basis_points: u32, // TODO: add batch_size rather than storing as constant, so that we can adjust dynamically after contract is locked next_campaign_id: CampaignId, - campaigns_by_id: UnorderedMap, - campaign_ids_by_owner: UnorderedMap>, - campaign_ids_by_recipient: UnorderedMap>, + campaigns_by_id: IterableMap, + campaign_ids_by_owner: IterableMap>, + campaign_ids_by_recipient: IterableMap>, next_donation_id: DonationId, - donations_by_id: UnorderedMap, - escrowed_donation_ids_by_campaign_id: UnorderedMap>, - unescrowed_donation_ids_by_campaign_id: UnorderedMap>, - returned_donation_ids_by_campaign_id: UnorderedMap>, - donation_ids_by_donor_id: UnorderedMap>, - storage_deposits: UnorderedMap, // Add storage_deposits to track storage deposits for FTs + donations_by_id: IterableMap, + escrowed_donation_ids_by_campaign_id: IterableMap>, + unescrowed_donation_ids_by_campaign_id: IterableMap>, + returned_donation_ids_by_campaign_id: IterableMap>, + donation_ids_by_donor_id: IterableMap>, + storage_deposits: IterableMap, // Add storage_deposits to track storage deposits for FTs } /// NOT stored in contract storage; only used for get_config response -#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers = [json, borsh])] +#[derive(Clone)] pub struct Config { pub owner: AccountId, pub admins: Vec, @@ -76,11 +74,12 @@ pub struct Config { pub protocol_fee_recipient_account: AccountId, pub default_referral_fee_basis_points: u32, pub default_creator_fee_basis_points: u32, - pub total_campaigns_count: u64, - pub total_donations_count: u64, + pub total_campaigns_count: u32, + pub total_donations_count: u32, } -#[derive(BorshSerialize, BorshStorageKey)] +#[near(serializers = [borsh])] +#[derive(BorshStorageKey)] pub enum StorageKey { Admins, CampaignsById, @@ -101,7 +100,7 @@ pub enum StorageKey { StorageDeposits, } -#[near_bindgen] +#[near] impl Contract { /// For testing purposes only #[init] @@ -132,40 +131,41 @@ impl Contract { assert!(!env::state_exists(), "Already initialized"); Self { owner, - admins: UnorderedSet::new(StorageKey::Admins), + admins: IterableSet::new(StorageKey::Admins), protocol_fee_basis_points, protocol_fee_recipient_account, default_referral_fee_basis_points, default_creator_fee_basis_points, next_campaign_id: 1, - campaigns_by_id: UnorderedMap::new(StorageKey::CampaignsById), - campaign_ids_by_owner: UnorderedMap::new(StorageKey::CampaignIdsByOwner), - campaign_ids_by_recipient: UnorderedMap::new(StorageKey::CampaignIdsByRecipient), + campaigns_by_id: IterableMap::new(StorageKey::CampaignsById), + campaign_ids_by_owner: IterableMap::new(StorageKey::CampaignIdsByOwner), + campaign_ids_by_recipient: IterableMap::new(StorageKey::CampaignIdsByRecipient), next_donation_id: 1, - donations_by_id: UnorderedMap::new(StorageKey::DonationsById), - // donation_ids_by_campaign_id: UnorderedMap::new(StorageKey::DonationIdsByCampaignId), - escrowed_donation_ids_by_campaign_id: UnorderedMap::new( + donations_by_id: IterableMap::new(StorageKey::DonationsById), + // donation_ids_by_campaign_id: IterableMap::new(StorageKey::DonationIdsByCampaignId), + escrowed_donation_ids_by_campaign_id: IterableMap::new( StorageKey::EscrowedDonationIdsByCampaignId, ), - unescrowed_donation_ids_by_campaign_id: UnorderedMap::new( + unescrowed_donation_ids_by_campaign_id: IterableMap::new( StorageKey::UnescrowedDonationIdsByCampaignId, ), - returned_donation_ids_by_campaign_id: UnorderedMap::new( + returned_donation_ids_by_campaign_id: IterableMap::new( StorageKey::ReturnedDonationIdsByCampaignId, ), - donation_ids_by_donor_id: UnorderedMap::new(StorageKey::DonationIdsByDonorId), + donation_ids_by_donor_id: IterableMap::new(StorageKey::DonationIdsByDonorId), contract_source_metadata: LazyOption::new( StorageKey::SourceMetadata, - Some(&VersionedContractSourceMetadata::Current(source_metadata)), + Some(VersionedContractSourceMetadata::Current(source_metadata)), ), - storage_deposits: UnorderedMap::new(StorageKey::StorageDeposits), + storage_deposits: IterableMap::new(StorageKey::StorageDeposits), } } pub fn get_config(&self) -> Config { + let nm = self.admins.iter().cloned().collect(); Config { owner: self.owner.clone(), - admins: self.admins.to_vec(), + admins: nm, protocol_fee_basis_points: self.protocol_fee_basis_points, protocol_fee_recipient_account: self.protocol_fee_recipient_account.clone(), default_referral_fee_basis_points: self.default_referral_fee_basis_points, diff --git a/contracts/campaigns/src/owner.rs b/contracts/campaigns/src/owner.rs index f02bc7f..941de19 100644 --- a/contracts/campaigns/src/owner.rs +++ b/contracts/campaigns/src/owner.rs @@ -1,6 +1,6 @@ use crate::*; -#[near_bindgen] +#[near] impl Contract { // OWNER #[payable] @@ -22,7 +22,7 @@ impl Contract { self.assert_contract_owner(); let initial_storage_usage = env::storage_usage(); for account_id in admins { - self.admins.insert(&account_id); + self.admins.insert(account_id); } refund_deposit(initial_storage_usage); log_config_update_event(&self.get_config()); @@ -45,6 +45,7 @@ impl Contract { let initial_storage_usage = env::storage_usage(); self.admins.clear(); refund_deposit(initial_storage_usage); - log_config_update_event(&self.get_config()); + let config = self.get_config(); + log_config_update_event(&config); } } diff --git a/contracts/campaigns/src/source.rs b/contracts/campaigns/src/source.rs index 3ec38ac..efbecec 100644 --- a/contracts/campaigns/src/source.rs +++ b/contracts/campaigns/src/source.rs @@ -1,8 +1,8 @@ use crate::*; /// CONTRACT SOURCE METADATA - as per NEP 0330 (https://github.com/near/NEPs/blob/master/neps/nep-0330.md), with addition of `commit_hash` -#[derive(Clone, Serialize, Deserialize, BorshDeserialize, BorshSerialize, PanicOnDefault)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[borsh, json])] +#[derive(Clone)] pub struct ContractSourceMetadata { /// Version of source code, e.g. "v1.0.0", could correspond to Git tag pub version: String, @@ -12,8 +12,8 @@ pub struct ContractSourceMetadata { pub link: String, } -#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize)] -#[serde(crate = "near_sdk::serde")] +#[near(serializers=[borsh, json])] +#[derive(Clone)] pub enum VersionedContractSourceMetadata { Current(ContractSourceMetadata), } @@ -27,7 +27,7 @@ impl From for ContractSourceMetadata { } } -#[near_bindgen] +#[near] impl Contract { #[payable] pub fn self_set_source_metadata(&mut self, source_metadata: ContractSourceMetadata) { @@ -37,9 +37,9 @@ impl Contract { "Only contract account can call this method" ); self.contract_source_metadata - .set(&VersionedContractSourceMetadata::from( + .set(Some(VersionedContractSourceMetadata::from( VersionedContractSourceMetadata::Current(source_metadata.clone()), - )); + ))); // emit event log_set_source_metadata_event(&source_metadata); } @@ -47,7 +47,9 @@ impl Contract { pub fn get_contract_source_metadata(&self) -> Option { let source_metadata = self.contract_source_metadata.get(); if source_metadata.is_some() { - Some(ContractSourceMetadata::from(source_metadata.unwrap())) + Some(ContractSourceMetadata::from( + source_metadata.clone().unwrap(), + )) } else { None } diff --git a/contracts/campaigns/src/storage.rs b/contracts/campaigns/src/storage.rs index e5e1b96..0c3d5c2 100644 --- a/contracts/campaigns/src/storage.rs +++ b/contracts/campaigns/src/storage.rs @@ -1,18 +1,18 @@ use crate::*; -#[near_bindgen] +#[near] impl Contract { #[payable] pub fn storage_deposit(&mut self) -> U128 { - let mut deposit = env::attached_deposit(); + let mut deposit = env::attached_deposit().as_yoctonear(); let initial_storage_usage = env::storage_usage(); let existing_mapping = self.storage_deposits.get(&env::predecessor_account_id()); if existing_mapping.is_none() { // insert record here and check how much storage was used, then subtract that cost from the deposit self.storage_deposits - .insert(&env::predecessor_account_id(), &0); + .insert(env::predecessor_account_id(), 0); let storage_usage = env::storage_usage() - initial_storage_usage; - let required_deposit = storage_usage as u128 * env::storage_byte_cost(); + let required_deposit = storage_usage as u128 * env::storage_byte_cost().as_yoctonear(); assert!( deposit >= required_deposit, "The deposit is less than the required storage amount." @@ -23,7 +23,7 @@ impl Contract { let storage_balance = self.storage_balance_of(&account_id); let new_storage_balance = storage_balance.0 + deposit; self.storage_deposits - .insert(&account_id, &new_storage_balance); + .insert(account_id, new_storage_balance); new_storage_balance.into() } @@ -37,21 +37,25 @@ impl Contract { ); let remainder = storage_balance.0 - amount; if remainder > 0 { - self.storage_deposits.insert(&account_id, &remainder); - Promise::new(account_id).transfer(amount); + self.storage_deposits.insert(account_id.clone(), remainder); + Promise::new(account_id).transfer(NearToken::from_yoctonear(amount)); } else { // remove mapping and refund user for freed storage let initial_storage_usage = env::storage_usage(); self.storage_deposits.remove(&account_id); let storage_usage = initial_storage_usage - env::storage_usage(); - let refund = storage_usage as u128 * env::storage_byte_cost(); - Promise::new(account_id).transfer(refund); + let refund = storage_usage as u128 * env::storage_byte_cost().as_yoctonear(); + Promise::new(account_id).transfer(NearToken::from_yoctonear(refund)); } remainder.into() } pub fn storage_balance_of(&self, account_id: &AccountId) -> U128 { - self.storage_deposits.get(account_id).unwrap_or(0).into() + self.storage_deposits + .get(account_id) + .unwrap_or(&0) + .clone() + .into() } /// Calculates currently used storage & determines whether caller has sufficient storage balance to cover storage costs @@ -74,11 +78,14 @@ impl Contract { // deduct storage deposit from user's balance let new_storage_balance = storage_balance.0 - required_deposit; self.storage_deposits - .insert(&sender_id, &new_storage_balance); + .insert(sender_id.clone(), new_storage_balance); log!("New storage balance: {}", new_storage_balance); - log!(format!( - "Deducted {} yoctoNEAR from {}'s storage balance to cover storage", - required_deposit, sender_id - )); + log!( + "{}", + format!( + "Deducted {} yoctoNEAR from {}'s storage balance to cover storage", + required_deposit, sender_id + ) + ); } } diff --git a/contracts/campaigns/src/tests.rs b/contracts/campaigns/src/tests.rs deleted file mode 100644 index d1d9042..0000000 --- a/contracts/campaigns/src/tests.rs +++ /dev/null @@ -1,227 +0,0 @@ -#[cfg(test)] -mod tests { - use super::*; - use crate::*; - use anyhow::Result; - use env_logger; - use log::info; - use near_sdk::json_types::U128; - use near_sdk::serde_json; - use near_workspaces::operations::Function; - use near_workspaces::result::{ExecutionFinalResult, ValueOrReceiptId}; - use near_workspaces::{ - sandbox, types::NearToken, Account, AccountId, Contract, DevNetwork, Worker, - }; - use std::sync::Once; - - const ONE_YOCTO: NearToken = NearToken::from_yoctonear(1); - - // Initialize logger only once for all tests - static INIT: Once = Once::new(); - - fn init_logger() { - INIT.call_once(|| { - let _ = env_logger::builder().is_test(true).try_init(); - println!("Logger initialized"); - info!("Logger initialized"); // Log to confirm initialization - }); - } - - async fn create_campaign( - contract: &Contract, - name: String, - description: Option, - cover_image_url: Option, - recipient: AccountId, - start_ms: TimestampMs, - end_ms: Option, - ft_id: Option, - target_amount: U128, - min_amount: Option, - max_amount: Option, - referral_fee_basis_points: Option, - creator_fee_basis_points: Option, - allow_fee_avoidance: Option, - ) -> Result { - let res = contract - .call("create_campaign") - .args_json(( - name, - description, - cover_image_url, - recipient, - start_ms, - end_ms, - ft_id, - target_amount, - min_amount, - max_amount, - referral_fee_basis_points, - creator_fee_basis_points, - allow_fee_avoidance, - )) - .max_gas() - // .deposit(near_sdk::env::storage_byte_cost().saturating_mul(125)) - .deposit(NearToken::from_near(1)) - .transact() - .await; - return res; - } - - async fn init(worker: &Worker) -> Result<(Contract, Account, Account)> { - let campaigns_contract = worker - .dev_deploy(include_bytes!("../out/main.wasm")) - .await?; - - let res = campaigns_contract - .call("new_default_meta") - .args_json((campaigns_contract.id(),)) - .max_gas() - .transact() - .await?; - info!("res: {:?}", res); - assert!(res.is_success()); - - let alice = campaigns_contract - .as_account() - .create_subaccount("alice") - .initial_balance(NearToken::from_near(10)) - .transact() - .await? - .into_result()?; - - let bob = campaigns_contract - .as_account() - .create_subaccount("bob") - .initial_balance(NearToken::from_near(10)) - .transact() - .await? - .into_result()?; - - return Ok((campaigns_contract, alice, bob)); - } - - #[tokio::test] - async fn test_create_campaign() -> Result<()> { - init_logger(); - // let initial_balance = U128::from(NearToken::from_near(10000).as_yoctonear()); - let worker = sandbox().await?; - let (contract, _alice, bob) = init(&worker).await?; - - let name = "Test Campaign".to_string(); - let description = Some("Test Description".to_string()); - let cover_image_url = Some("https://example.com/image.jpg".to_string()); - let recipient = bob.id().clone(); - let start_ms = near_sdk::env::block_timestamp() + 1000; - let end_ms = Some(start_ms + 10_000); - let ft_id = None; - let target_amount = U128::from(100); - let min_amount = Some(U128::from(10)); - let max_amount = Some(U128::from(200)); - let referral_fee_basis_points = Some(100); - let creator_fee_basis_points = Some(100); - let allow_fee_avoidance = Some(true); - - let res = create_campaign( - &contract, - name.clone(), - description.clone(), - cover_image_url.clone(), - recipient.clone(), - start_ms, - end_ms, - ft_id, - target_amount, - min_amount, - max_amount, - referral_fee_basis_points, - creator_fee_basis_points, - allow_fee_avoidance, - ) - .await?; - // Ensure the transaction succeeded - assert!(res.is_success()); - - // Extract the execution outcome - let logs = res.logs(); - let campaign_create_log = logs - .iter() - .find(|log| log.contains("campaign_create")) - .expect("Campaign creation log not found"); - let event_json_start = - campaign_create_log.find("EVENT_JSON:").unwrap() + "EVENT_JSON:".len(); - let event_json_str = &campaign_create_log[event_json_start..]; - let event_json: serde_json::Value = serde_json::from_str(event_json_str)?; - - // Verify that the details of the new campaign match the input - let campaign_data = &event_json["data"][0]["campaign"]; - assert_eq!(campaign_data["name"], name); - match description { - Some(description_value) => assert_eq!(campaign_data["description"], description_value), - None => assert!(campaign_data.get("description").is_none()), - } - match cover_image_url { - Some(cover_image_url_value) => { - assert_eq!(campaign_data["cover_image_url"], cover_image_url_value) - } - None => assert!(campaign_data.get("cover_image_url").is_none()), - } - assert_eq!(campaign_data["recipient"], recipient.to_string()); - assert_eq!(campaign_data["start_ms"], start_ms); - match end_ms { - Some(end_ms_value) => assert_eq!(campaign_data["end_ms"], end_ms_value), - None => assert!(campaign_data.get("end_ms").is_none()), - } - let target_amount_str = campaign_data["target_amount"] - .as_str() - .expect("target_amount should be a string"); - let target_amount_json = U128::from( - target_amount_str - .parse::() - .expect("Invalid U128 string"), - ); - assert_eq!(target_amount_json, target_amount); - match min_amount { - Some(min_amount_value) => { - let min_amount_str = campaign_data["min_amount"] - .as_str() - .expect("min_amount should be a string"); - let min_amount_json = - U128::from(min_amount_str.parse::().expect("Invalid U128 string")); - assert_eq!(min_amount_json, min_amount_value); - } - None => assert!(campaign_data.get("min_amount").is_none()), - } - match max_amount { - Some(max_amount_value) => { - let max_amount_str = campaign_data["max_amount"] - .as_str() - .expect("max_amount should be a string"); - let max_amount_json = - U128::from(max_amount_str.parse::().expect("Invalid U128 string")); - assert_eq!(max_amount_json, max_amount_value); - } - None => assert!(campaign_data.get("max_amount").is_none()), - } - match referral_fee_basis_points { - Some(referral_fee_basis_points_value) => { - assert_eq!( - campaign_data["referral_fee_basis_points"], - referral_fee_basis_points_value - ) - } - None => assert!(campaign_data.get("referral_fee_basis_points").is_none()), - } - match creator_fee_basis_points { - Some(creator_fee_basis_points_value) => { - assert_eq!( - campaign_data["creator_fee_basis_points"], - creator_fee_basis_points_value - ) - } - None => assert!(campaign_data.get("creator_fee_basis_points").is_none()), - } - - Ok(()) - } -} diff --git a/contracts/campaigns/src/transfer.rs b/contracts/campaigns/src/transfer.rs index ea07eb7..439b9c5 100644 --- a/contracts/campaigns/src/transfer.rs +++ b/contracts/campaigns/src/transfer.rs @@ -1,66 +1,49 @@ use crate::*; -#[near_bindgen] +#[near] impl Contract { - pub(crate) fn handle_transfer_recipient_amount( - &self, - donation: DonationExternal, - ) -> PromiseOrValue { - self.handle_transfer(donation, FundsReceiver::Recipient) - } + // pub(crate) fn handle_transfer_recipient_amount( + // &self, + // donation: DonationExternal, + // ) -> PromiseOrValue { + // self.handle_transfer(donation, FundsReceiver::Recipient, donation.net_amount, ) + // } - pub(crate) fn handle_transfer_protocol_fee( - &self, - donation: DonationExternal, - ) -> PromiseOrValue { - self.handle_transfer(donation, FundsReceiver::Protocol) - } + // pub(crate) fn handle_transfer_protocol_fee( + // &self, + // donation: DonationExternal, + // ) -> PromiseOrValue { + // self.handle_transfer(donation, FundsReceiver::Protocol) + // } - pub(crate) fn handle_transfer_referrer_fee( - &self, - donation: DonationExternal, - ) -> PromiseOrValue { - self.handle_transfer(donation, FundsReceiver::Referrer) - } + // pub(crate) fn handle_transfer_referrer_fee( + // &self, + // donation: DonationExternal, + // ) -> PromiseOrValue { + // self.handle_transfer(donation, FundsReceiver::Referrer) + // } - pub(crate) fn handle_transfer_creator_fee( - &self, - donation: DonationExternal, - ) -> PromiseOrValue { - self.handle_transfer(donation, FundsReceiver::Creator) - } + // pub(crate) fn handle_transfer_creator_fee( + // &self, + // donation: DonationExternal, + // ) -> PromiseOrValue { + // self.handle_transfer(donation, FundsReceiver::Creator) + // } /// Handles transfer of one component (e.g. recipient amount, protocol fee, referrer fee or creator fee) of a single donation pub(crate) fn handle_transfer( &self, donation: DonationExternal, receiver_type: FundsReceiver, + amount: U128, + recipient_id: AccountId, ) -> PromiseOrValue { - let recipient_id = match receiver_type { - FundsReceiver::Recipient => donation.recipient_id.clone(), - FundsReceiver::Protocol => self.protocol_fee_recipient_account.clone(), - FundsReceiver::Referrer => donation.referrer_id.clone().unwrap(), - FundsReceiver::Creator => { - let campaign = Campaign::from( - self.campaigns_by_id - .get(&donation.campaign_id) - .expect("Campaign not found"), - ); - campaign.owner.clone() - } - }; - let amount = match receiver_type { - FundsReceiver::Recipient => donation.net_amount.0, - FundsReceiver::Protocol => donation.protocol_fee.0, - FundsReceiver::Referrer => donation.referrer_fee.unwrap_or(U128(0)).0, - FundsReceiver::Creator => donation.creator_fee.0, - }; PromiseOrValue::Promise( - self.internal_transfer_amount(amount, recipient_id, donation.ft_id.clone()) + self.internal_transfer_amount(amount.into(), recipient_id, donation.ft_id.clone()) .then( Self::ext(env::current_account_id()) - .with_static_gas(Gas(XCC_GAS_DEFAULT)) - .transfer_funds_callback(amount, donation.clone(), receiver_type), + .with_static_gas(Gas::from_tgas(20)) + .transfer_funds_callback(amount.into(), donation.clone(), receiver_type), ), ) } @@ -80,10 +63,13 @@ impl Contract { FundsReceiver::Recipient => { // Campain recipient transfer failed // Remove donation record & transfer full donation amount back to donor - log!(format!( - "Error transferring donation {:?} to {}. Returning funds to donor.", - donation.total_amount, donation.recipient_id - )); + log!( + "{}", + format!( + "Error transferring donation {:?} to {}. Returning funds to donor.", + donation.total_amount, donation.recipient_id + ) + ); // return funds to donor self.internal_transfer_amount( donation.total_amount.0, @@ -95,17 +81,21 @@ impl Contract { self.internal_remove_donation_record(&self.unformat_donation(&donation)); // Refund cost of storage freed directly to donor. (No need to keep it in user's storage_deposit balance, this just creates an extra step for them to withdraw it.) let storage_freed = initial_storage_usage - env::storage_usage(); - let cost_freed = env::storage_byte_cost() * Balance::from(storage_freed); + let cost_freed = + env::storage_byte_cost().as_yoctonear() * Balance::from(storage_freed); self.internal_transfer_amount(cost_freed, donation.donor_id.clone(), None); None } FundsReceiver::Protocol => { // Protocol fee transfer failed // Return protocol fee to donor & update donation record to indicate protocol fee of 0 - log!(format!( - "Error transferring protocol fee {:?} to {}. Returning funds to donor.", - donation.protocol_fee, self.protocol_fee_recipient_account - )); + log!( + "{}", + format!( + "Error transferring protocol fee {:?} to {}. Returning funds to donor.", + donation.protocol_fee, self.protocol_fee_recipient_account + ) + ); // return funds to donor self.internal_transfer_amount( donation.protocol_fee.0, @@ -115,16 +105,19 @@ impl Contract { // update protocol fee on Donation record to indicate error transferring funds donation.protocol_fee = U128(0); self.donations_by_id.insert( - &donation.id.clone(), - &VersionedDonation::Current(self.unformat_donation(&donation)), + donation.id.clone(), + VersionedDonation::Current(self.unformat_donation(&donation)), ); Some(donation) } FundsReceiver::Referrer => { - log!(format!( + log!( + "{}", + format!( "Error transferring referrer fee {:?} to {:?}. Returning funds to donor.", donation.referrer_fee, donation.referrer_id - )); + ) + ); // return funds to donor self.internal_transfer_amount( donation.referrer_fee.unwrap().0, @@ -134,16 +127,19 @@ impl Contract { // update referrer fee on Donation record to indicate error transferring funds donation.referrer_fee = Some(U128(0)); self.donations_by_id.insert( - &donation.id.clone(), - &VersionedDonation::Current(self.unformat_donation(&donation)), + donation.id.clone(), + VersionedDonation::Current(self.unformat_donation(&donation)), ); Some(donation) } FundsReceiver::Creator => { - log!(format!( - "Error transferring creator fee {:?} to {}. Returning funds to donor.", - donation.creator_fee, donation.recipient_id - )); + log!( + "{}", + format!( + "Error transferring creator fee {:?} to {}. Returning funds to donor.", + donation.creator_fee, donation.recipient_id + ) + ); // return funds to donor self.internal_transfer_amount( donation.creator_fee.0, @@ -153,8 +149,8 @@ impl Contract { // update fee on Donation record to indicate error transferring funds donation.creator_fee = U128(0); self.donations_by_id.insert( - &donation.id.clone(), - &VersionedDonation::Current(self.unformat_donation(&donation)), + donation.id.clone(), + VersionedDonation::Current(self.unformat_donation(&donation)), ); Some(donation) } @@ -163,18 +159,40 @@ impl Contract { // * SUCCESS CASE HANDLING // NB: escrow transfers are handled in transfer_escrowed_donations_callback, which is written to handle multiple donations if receiver_type == FundsReceiver::Recipient { - log!(format!( - "Successfully transferred donation {} to {}!", - amount, donation.recipient_id - )); - + log!( + "{}", + format!( + "Successfully transferred donation {} to {}!", + amount, donation.recipient_id + ) + ); + let mut campaign = Campaign::from( + self.campaigns_by_id + .get_mut(&donation.campaign_id) + .expect("Campaign not found") + .clone(), + ); + campaign.total_raised_amount += donation.total_amount.0; + campaign.net_raised_amount += donation.net_amount.0; + self.campaigns_by_id.insert( + donation.campaign_id.clone(), + VersionedCampaign::Current(campaign), + ); // transfer protocol fee if donation.protocol_fee.0 > 0 { - log!(format!( - "Transferring protocol fee {:?} to {}", - donation.protocol_fee, self.protocol_fee_recipient_account - )); - self.handle_transfer_protocol_fee(donation.clone()); + log!( + "{}", + format!( + "Transferring protocol fee {:?} to {}", + donation.protocol_fee, self.protocol_fee_recipient_account + ) + ); + self.handle_transfer( + donation.clone(), + FundsReceiver::Protocol, + donation.protocol_fee, + self.protocol_fee_recipient_account.clone(), + ); } // transfer referrer fee @@ -182,21 +200,44 @@ impl Contract { (donation.referrer_fee.clone(), donation.referrer_id.clone()) { if referrer_fee.0 > 0 { - log!(format!( - "Transferring referrer fee {:?} to {}", - referrer_fee, referrer_id - )); - self.handle_transfer_referrer_fee(donation.clone()); + log!( + "{}", + format!( + "Transferring referrer fee {:?} to {}", + referrer_fee, referrer_id + ) + ); + self.handle_transfer( + donation.clone(), + FundsReceiver::Referrer, + referrer_fee, + referrer_id, + ); } } // transfer creator fee if donation.creator_fee.0 > 0 { - log!(format!( - "Transferring creator fee {:?} to {}", - donation.creator_fee, donation.recipient_id - )); - self.handle_transfer_creator_fee(donation.clone()); + let campaign = Campaign::from( + self.campaigns_by_id + .get(&donation.campaign_id) + .expect("Campaign not found") + .clone(), + ); + let recipient_id = campaign.owner; + log!( + "{}", + format!( + "Transferring creator fee {:?} to {}", + donation.creator_fee, recipient_id + ) + ); + self.handle_transfer( + donation.clone(), + FundsReceiver::Creator, + donation.creator_fee, + recipient_id, + ); } // log event indicating successful donation/transfer! diff --git a/contracts/campaigns/src/utils.rs b/contracts/campaigns/src/utils.rs index 51f4d69..373c63e 100644 --- a/contracts/campaigns/src/utils.rs +++ b/contracts/campaigns/src/utils.rs @@ -1,26 +1,16 @@ use crate::*; -pub(crate) fn account_vec_to_set( - account_vec: Vec, - storage_key: StorageKey, -) -> UnorderedSet { - let mut set = UnorderedSet::new(storage_key); - for element in account_vec.iter() { - set.insert(element); - } - set -} - pub fn calculate_required_storage_deposit(initial_storage_usage: u64) -> Balance { let storage_used = env::storage_usage() - initial_storage_usage; log!("Storage used: {} bytes", storage_used); - let required_cost = env::storage_byte_cost() * Balance::from(storage_used); + let required_cost = env::storage_byte_cost().as_yoctonear() * Balance::from(storage_used); required_cost } pub fn refund_deposit(initial_storage_usage: u64) { - let attached_deposit = env::attached_deposit(); + let attached_deposit = env::attached_deposit().as_yoctonear(); let mut refund = attached_deposit; + log!("Guaging used stuffs: {} in bytes", refund); if env::storage_usage() > initial_storage_usage { // caller should pay for the extra storage they used and be refunded for the rest // let storage_used = env::storage_usage() - initial_storage_usage; @@ -37,11 +27,11 @@ pub fn refund_deposit(initial_storage_usage: u64) { } else { // storage was freed up; caller should be refunded for what they freed up, in addition to the deposit they sent let storage_freed = initial_storage_usage - env::storage_usage(); - let cost_freed = env::storage_byte_cost() * Balance::from(storage_freed); + let cost_freed = env::storage_byte_cost().as_yoctonear() * Balance::from(storage_freed); refund += cost_freed; } if refund > 1 { - Promise::new(env::predecessor_account_id()).transfer(refund); + Promise::new(env::predecessor_account_id()).transfer(NearToken::from_yoctonear(refund)); } } @@ -52,7 +42,7 @@ pub(crate) fn calculate_fee(amount: u128, basis_points: u32) -> u128 { fee_amount / total_basis_points } -#[near_bindgen] +#[near] impl Contract { pub(crate) fn calculate_protocol_fee(&self, amount: u128) -> u128 { calculate_fee(amount, self.protocol_fee_basis_points) diff --git a/contracts/campaigns/tests/campaign.rs b/contracts/campaigns/tests/campaign.rs new file mode 100644 index 0000000..fefb9fe --- /dev/null +++ b/contracts/campaigns/tests/campaign.rs @@ -0,0 +1,1102 @@ +mod test_envs; + +use anyhow::Result; +use log::info; +use near_sdk::env::{block_timestamp, block_timestamp_ms}; +use near_sdk::json_types::U128; +use near_sdk::serde_json; +use near_workspaces::result::ExecutionFinalResult; + +use chrono::Utc; +use serde_json::json; +use test_envs::{init, init_logger}; + +use near_workspaces::{sandbox, types::NearToken, Account, AccountId, Block, Contract}; + +type TimestampMs = u64; +const ONE_NEAR: NearToken = NearToken::from_near(1); + +async fn create_campaign( + contract: &Contract, + caller: Account, + name: String, + description: Option, + cover_image_url: Option, + recipient: AccountId, + start_ms: TimestampMs, + end_ms: Option, + ft_id: Option, + target_amount: U128, + min_amount: Option, + max_amount: Option, + referral_fee_basis_points: Option, + creator_fee_basis_points: Option, + allow_fee_avoidance: Option, +) -> Result { + let res = caller + .call(contract.id(), "create_campaign") + .args_json(( + name, + description, + cover_image_url, + recipient, + start_ms, + end_ms, + ft_id, + target_amount, + min_amount, + max_amount, + referral_fee_basis_points, + creator_fee_basis_points, + allow_fee_avoidance, + )) + .max_gas() + // .deposit(near_sdk::env::storage_byte_cost().saturating_mul(125)) + .deposit(ONE_NEAR.into()) + .transact() + .await; + return res; +} + +// make an update_campaign function that takes contract and params and calls the update_campaign function + +async fn update_campaign( + contract: &Contract, + campaign_id: Option, + name: Option, + description: Option, + cover_image_url: Option, + recipient: Option, + start_ms: Option, + end_ms: Option, + ft_id: Option, + target_amount: Option, + min_amount: Option, + max_amount: Option, + referral_fee_basis_points: Option, + creator_fee_basis_points: Option, + allow_fee_avoidance: Option, +) -> Result { + let res = contract + .call("update_campaign") + .args_json(json!({ + "campaign_id": campaign_id, + "name": name, + "description": description, + "cover_image_url": cover_image_url, + "recipient": recipient, + "start_ms": start_ms, + "end_ms": end_ms, + "ft_id": ft_id, + "target_amount": target_amount, + "min_amount": min_amount, + "max_amount": max_amount, + "referral_fee_basis_points": referral_fee_basis_points, + "creator_fee_basis_points": creator_fee_basis_points, + "allow_fee_avoidance": allow_fee_avoidance, + } + )) + .max_gas() + // .deposit(near_sdk::env::storage_byte_cost().saturating_mul(125)) + .deposit(ONE_NEAR) + .transact() + .await; + return res; +} + +#[tokio::test] +async fn test_create_campaigns() -> Result<()> { + init_logger(); + let worker = sandbox().await?; + let (contract, alice, bob) = init(&worker).await?; + + // let _ = contract.as_account().transfer_near(alice.id(), NearToken::from_yoctonear(99999481833998144000000000)).await?; + + let state_p_funds = contract.view_account().await?; + println!( + "state before creation of election.... : {:?}", + state_p_funds + ); + + // Create first campaign + let name1 = "Test Campaign 1".to_string(); + let description1 = Some("Test Description 1".to_string()); + let cover_image_url1 = Some("https://example.com/image1.jpg".to_string()); + let recipient = bob.id().clone(); + let now = Utc::now().timestamp_millis(); + let start_ms = (now + 1000_000) as u64; + let end_ms = Some(start_ms + 10_000_000); + let target_amount1 = U128::from(100); + + // Create second campaign + let name2 = "Test Campaign 2".to_string(); + let description2 = Some("Test Description 2".to_string()); + let cover_image_url2 = Some("https://example.com/image2.jpg".to_string()); + let target_amount2 = U128::from(200); + + // Create third campaign + let name3 = "Test Campaign 3".to_string(); + let description3 = Some("Test Description 3".to_string()); + let cover_image_url3 = Some("https://example.com/image3.jpg".to_string()); + let target_amount3 = U128::from(300); + + // Create all three campaigns + let campaigns = vec![ + (name1, description1, cover_image_url1, target_amount1), + (name2, description2, cover_image_url2, target_amount2), + (name3, description3, cover_image_url3, target_amount3), + ]; + + for (name, description, cover_image_url, target_amount) in campaigns { + let res = create_campaign( + &contract, + alice.clone(), + name, + description, + cover_image_url, + recipient.clone(), + start_ms, + end_ms, + None, // ft_id + target_amount, + Some(U128::from(10)), + Some(U128::from(1000)), + Some(100), + Some(100), + Some(true), + ) + .await?; + println!("multui creator.. {:?}", res); + assert!(res.is_success()); + } + + // Get all campaigns for alice + let owner_campaigns: serde_json::Value = alice + .view(contract.id(), "get_campaigns_by_owner") + .args_json(json!({ + "owner_id": alice.id(), + "from_index": 0, + "limit": 10 + })) + .await? + .json()?; + + println!("Owner campaigns: {:?}", owner_campaigns); + + // Assert we got all three campaigns + assert_eq!( + owner_campaigns.as_array().unwrap().len(), + 3, + "Expected 3 campaigns, got {}", + owner_campaigns.as_array().unwrap().len() + ); + + // Verify each campaign has unique details + let campaigns = owner_campaigns.as_array().unwrap(); + assert!(campaigns + .iter() + .any(|c| c["name"].as_str().unwrap().contains("1"))); + assert!(campaigns + .iter() + .any(|c| c["name"].as_str().unwrap().contains("2"))); + assert!(campaigns + .iter() + .any(|c| c["name"].as_str().unwrap().contains("3"))); + + Ok(()) +} + +#[tokio::test] +async fn test_create_campaign() -> Result<()> { + init_logger(); + // let initial_balance = U128::from(NearToken::from_near(10000).as_yoctonear()); + let worker = sandbox().await?; + let (contract, alice, bob) = init(&worker).await?; + + let name = "Test Campaign".to_string(); + let description = Some("Test Description".to_string()); + let cover_image_url = Some("https://example.com/image.jpg".to_string()); + let recipient = bob.id().clone(); + let now = Utc::now().timestamp_millis(); + let start_ms = (now + 10000) as u64; + let end_ms = Some(start_ms + 10_0000); + let ft_id = None; + let target_amount = U128::from(100); + let min_amount = Some(U128::from(10)); + let max_amount = Some(U128::from(200)); + let referral_fee_basis_points = Some(100); + let creator_fee_basis_points = Some(100); + let allow_fee_avoidance = Some(true); + + // let _ = contract.as_account().transfer_near(alice.id(), NearToken::from_yoctonear(95736646527937956500000000)).await?; + + let state_p_funds = contract.view_account().await?; + println!( + "state before creation of campaign.... : {:?}", + state_p_funds + ); + + let res = create_campaign( + &contract, + alice.clone(), + name.clone(), + description.clone(), + cover_image_url.clone(), + recipient.clone(), + start_ms, + end_ms, + ft_id.clone(), + target_amount, + min_amount, + max_amount, + referral_fee_basis_points, + creator_fee_basis_points, + allow_fee_avoidance, + ) + .await?; + + println!("created camoaing... {:?}", res); + // Ensure the transaction succeeded + assert!(res.is_success()); + + let state = contract.view_account().await?; + + println!("state after creating of campaign.... : {:?}", state); + + let storage_used = state.storage_usage - state_p_funds.storage_usage; + + println!("total used.... : {}", storage_used); + + // Extract the execution outcome + let logs = res.logs(); + let campaign_create_log = logs + .iter() + .find(|log| log.contains("campaign_create")) + .expect("Campaign creation log not found"); + let event_json_start = campaign_create_log.find("EVENT_JSON:").unwrap() + "EVENT_JSON:".len(); + let event_json_str = &campaign_create_log[event_json_start..]; + let event_json: serde_json::Value = serde_json::from_str(event_json_str)?; + + // Verify that the details of the new campaign match the input + let campaign_data = &event_json["data"][0]["campaign"]; + assert_eq!(campaign_data["name"], name); + match description { + Some(description_value) => assert_eq!(campaign_data["description"], description_value), + None => assert!(campaign_data.get("description").is_none()), + } + match cover_image_url { + Some(cover_image_url_value) => { + assert_eq!(campaign_data["cover_image_url"], cover_image_url_value) + } + None => assert!(campaign_data.get("cover_image_url").is_none()), + } + assert_eq!(campaign_data["recipient"], recipient.to_string()); + assert_eq!(campaign_data["start_ms"], start_ms); + match end_ms { + Some(end_ms_value) => assert_eq!(campaign_data["end_ms"], end_ms_value), + None => assert!(campaign_data.get("end_ms").is_none()), + } + let target_amount_str = campaign_data["target_amount"] + .as_str() + .expect("target_amount should be a string"); + let target_amount_json = U128::from( + target_amount_str + .parse::() + .expect("Invalid U128 string"), + ); + assert_eq!(target_amount_json, target_amount); + match min_amount { + Some(min_amount_value) => { + let min_amount_str = campaign_data["min_amount"] + .as_str() + .expect("min_amount should be a string"); + let min_amount_json = + U128::from(min_amount_str.parse::().expect("Invalid U128 string")); + assert_eq!(min_amount_json, min_amount_value); + } + None => assert!(campaign_data.get("min_amount").is_none()), + } + match max_amount { + Some(max_amount_value) => { + let max_amount_str = campaign_data["max_amount"] + .as_str() + .expect("max_amount should be a string"); + let max_amount_json = + U128::from(max_amount_str.parse::().expect("Invalid U128 string")); + assert_eq!(max_amount_json, max_amount_value); + } + None => assert!(campaign_data.get("max_amount").is_none()), + } + match referral_fee_basis_points { + Some(referral_fee_basis_points_value) => { + assert_eq!( + campaign_data["referral_fee_basis_points"], + referral_fee_basis_points_value + ) + } + None => assert!(campaign_data.get("referral_fee_basis_points").is_none()), + } + match creator_fee_basis_points { + Some(creator_fee_basis_points_value) => { + assert_eq!( + campaign_data["creator_fee_basis_points"], + creator_fee_basis_points_value + ) + } + None => assert!(campaign_data.get("creator_fee_basis_points").is_none()), + } + + let vcp = alice + .view(contract.id(), "get_campaigns_by_recipient") + .args_json(json!({ + "recipient_id": recipient.clone(), + })) + .await?; + println!("campaign viewed: {:?}", vcp.json::()?); + + // test update_campaign name and dexcription + + let new_name = "New Test Campaign".to_string(); + // let new_description = Some("New Test Description".to_string()); + // let new_cover_image_url = Some("https://example.com/new_image.jpg".to_string()); + // let new_recipient = bob.id().clone(); + // let new_start_ms = near_sdk::env::block_timestamp() + 1000; + // let new_end_ms = Some(new_start_ms + 10_000); + // let new_ft_id = None; + // let new_target_amount = U128::from(100); + // let new_min_amount = Some(U128::from(10)); + // let new_max_amount = Some(U128::from(200)); + // let new_referral_fee_basis_points = Some(100); + // let new_creator_fee_basis_points = Some(100); + // let new_allow_fee_avoidance = Some(true); + + let campaign_id = campaign_data["id"].as_u64().unwrap(); + + // Update campaign + let update_result = alice + .call(contract.id(), "update_campaign") + .args_json(json!({"campaign_id": 1,"name": "Updated Test Campaign","description": "Updated Test Description", "cover_image_url": "https://fifi.png", "max_amount": "100000000000", "target_amount": "1000000000"})) + .max_gas() + .deposit(ONE_NEAR) + .transact() + .await?; + // Ensure the transaction succeeded + println!("Update.. sucess >>> {:?}", update_result); + assert!(update_result.is_success()); + println!("Update.. sucess >>>"); + + // Verify update + let updated_campaign: serde_json::Value = contract + .call("get_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + assert_eq!(updated_campaign["name"], "Updated Test Campaign"); + assert_eq!(updated_campaign["description"], "Updated Test Description"); + + let state3 = contract.view_account().await?; + + println!("state after creating of all.... : {:?}", state); + + let storage_used = state3.storage_usage - state_p_funds.storage_usage; + + println!("total used all2geda.... : {}", storage_used); + + Ok(()) +} + +#[tokio::test] +async fn test_donate_to_campaign_with_target() -> Result<()> { + let worker = sandbox().await?; + let (contract, alice, bob) = init(&worker).await?; + + let now = Utc::now().timestamp_millis(); + let start_ms = (now + 1000) as u64; + let end_ms = Some(start_ms + 10_0000); + + // Create campaign with target + println!( + "check bob bal.... {:?}, >> {:?}", + bob.view_account().await?.balance, + now + ); + let name = "Test Campaign".to_string(); + let description = Some("Test Description".to_string()); + let cover_image_url = Some("https://example.com/image.jpg".to_string()); + let recipient = bob.id().clone(); + let ft_id = None; + let target_amount = U128::from(3000000000000000000000000); + let min_amount = Some(U128::from(3000000000000000000000000)); + let max_amount = Some(U128::from(5000000000000000000000000)); + let referral_fee_basis_points = Some(100); + let creator_fee_basis_points = Some(100); + let allow_fee_avoidance = Some(true); + + let stateA = contract.view_account().await?; + + println!("state before first donation.... : {:?}", stateA); + let res = create_campaign( + &contract, + alice.clone(), + name.clone(), + description.clone(), + cover_image_url.clone(), + recipient.clone(), + start_ms, + end_ms, + ft_id, + target_amount, + min_amount, + max_amount, + referral_fee_basis_points, + creator_fee_basis_points, + allow_fee_avoidance, + ) + .await?; + + println!("get whole res {:?}", res); + + let logs = res.logs(); + let campaign_create_log = logs + .iter() + .find(|log| log.contains("campaign_create")) + .expect("Campaign creation log not found"); + let event_json_start = campaign_create_log.find("EVENT_JSON:").unwrap() + "EVENT_JSON:".len(); + let event_json_str = &campaign_create_log[event_json_start..]; + let event_json: serde_json::Value = serde_json::from_str(event_json_str)?; + + // Verify that the details of the new campaign match the input + let campaign_data = &event_json["data"][0]["campaign"]; + let campaign_id = campaign_data["id"].as_u64().unwrap(); + println!("campaign_id: {:?}", campaign_data); + + // Donate to campaign + let donation_amount = NearToken::from_near(2); + + donate_to_campaign(&alice, &contract, campaign_id, donation_amount).await?; + + // Verify donation + let campaign: serde_json::Value = contract + .call("get_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + + assert_eq!( + campaign["total_raised_amount"], + donation_amount.as_yoctonear().to_string() + ); + // assert!(campaign["status"] == "ONGOING" || campaign["status"] == "COMPLETED"); + + let donate_result2 = bob + .call(contract.id(), "donate") + .args_json(json!({ + "campaign_id": campaign_id, + })) + .max_gas() + .deposit(donation_amount) + .transact() + .await?; + + println!("Result 2.. {:?}", donate_result2); + assert!(donate_result2.is_success()); + + // println!("check bob bal after finsali.... {:?}, >> {:?}", bob.view_account().await?.balance, alice.view_account().await?.balance); + + let campaign2: serde_json::Value = bob + .call(contract.id(), "get_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + + println!( + "campaign campana: {:?}, {}", + campaign2["min_amount"], campaign2["total_raised_amount"] + ); + + assert_eq!( + campaign2["total_raised_amount"], + donation_amount + .checked_add(donation_amount) + .unwrap() + .as_yoctonear() + .to_string() + ); + // get donations for campaign + let campaign_donations: serde_json::Value = contract + .call("get_donations_for_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + + assert_eq!(campaign_donations.as_array().unwrap().len(), 2); + + // processescrowed donations by calling the `process_escrowed_donations_batch` function + + let process_escrowed_donations_batch_result = contract + .call("process_escrowed_donations_batch") // call with campaign id + .args_json(json!({ "campaign_id": campaign_id })) + .max_gas() + .transact() + .await?; + + println!( + "Go berserk.... {:?}", + process_escrowed_donations_batch_result + ); + assert!(process_escrowed_donations_batch_result.is_success()); + + let stateB = contract.view_account().await?; + + println!("state after all donation.... : {:?}", stateB); + + let storage_used = stateB.storage_usage - stateA.storage_usage; + + println!("total used all2geda.... : {}", storage_used); + + let campaign_donations2: serde_json::Value = contract + .call("get_donations_for_donor") + .args_json(json!({ "donor_id": alice.id() })) + .view() + .await? + .json()?; + + println!( + "campaign donations 22lejo: {:?}, {}", + campaign_donations2, campaign_id + ); + + Ok(()) +} + +#[tokio::test] +async fn test_donate_to_campaign_with_target_without_min_amount() -> Result<()> { + let worker = sandbox().await?; + let (contract, alice, bob) = init(&worker).await?; + + let now = Utc::now().timestamp_millis(); + let start_ms = (now + 1000) as u64; + let end_ms = Some(start_ms + 10_000); + + // Create campaign with target + println!( + "check bob bal.... {:?}, >> {:?}", + bob.view_account().await?.balance, + now + ); + let name = "Test Campaign".to_string(); + let description = Some("Test Description".to_string()); + let cover_image_url = Some("https://example.com/image.jpg".to_string()); + let recipient = bob.id().clone(); + let ft_id = None; + let target_amount = U128::from(3000000000000000000000000); + let max_amount = Some(U128::from(5000000000000000000000000)); + let referral_fee_basis_points = Some(100); + let creator_fee_basis_points = Some(100); + let allow_fee_avoidance = Some(true); + + let stateA = contract.view_account().await?; + + println!("state before first donation.... : {:?}", stateA); + let res = create_campaign( + &contract, + alice.clone(), + name.clone(), + description.clone(), + cover_image_url.clone(), + recipient.clone(), + start_ms, + end_ms, + ft_id, + target_amount, + None, + max_amount, + referral_fee_basis_points, + creator_fee_basis_points, + allow_fee_avoidance, + ) + .await?; + + println!("get whole res {:?}", res); + + let logs = res.logs(); + let campaign_create_log = logs + .iter() + .find(|log| log.contains("campaign_create")) + .expect("Campaign creation log not found"); + let event_json_start = campaign_create_log.find("EVENT_JSON:").unwrap() + "EVENT_JSON:".len(); + let event_json_str = &campaign_create_log[event_json_start..]; + let event_json: serde_json::Value = serde_json::from_str(event_json_str)?; + + // Verify that the details of the new campaign match the input + let campaign_data = &event_json["data"][0]["campaign"]; + let campaign_id = campaign_data["id"].as_u64().unwrap(); + println!("campaign_id: {:?}", campaign_data); + + // Donate to campaign + let donation_amount = NearToken::from_near(2); + + donate_to_campaign(&alice, &contract, campaign_id, donation_amount).await?; + + // Verify donation + let campaign: serde_json::Value = contract + .call("get_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + + assert_eq!( + campaign["total_raised_amount"], + donation_amount.as_yoctonear().to_string() + ); + // assert!(campaign["status"] == "ONGOING" || campaign["status"] == "COMPLETED"); + + let donate_result2 = bob + .call(contract.id(), "donate") + .args_json(json!({ + "campaign_id": campaign_id, + })) + .max_gas() + .deposit(donation_amount) + .transact() + .await?; + + assert!(donate_result2.is_success()); + + // println!("check bob bal after finsali.... {:?}, >> {:?}", bob.view_account().await?.balance, alice.view_account().await?.balance); + + let campaign2: serde_json::Value = bob + .call(contract.id(), "get_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + + println!( + "campaign campana: {:?}, {}", + campaign2["min_amount"], campaign2["total_raised_amount"] + ); + + assert_eq!( + campaign2["total_raised_amount"], + donation_amount + .checked_add(donation_amount) + .unwrap() + .as_yoctonear() + .to_string() + ); + // get donations for campaign + let campaign_donations: serde_json::Value = contract + .call("get_donations_for_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + + assert_eq!(campaign_donations.as_array().unwrap().len(), 2); + + let stateB = contract.view_account().await?; + + println!("state after all donation.... : {:?}", stateB); + + let storage_used = stateB.storage_usage - stateA.storage_usage; + + println!("total used all2geda.... : {}", storage_used); + + let campaign_donations2: serde_json::Value = contract + .call("get_donations_for_donor") + .args_json(json!({ "donor_id": alice.id() })) + .view() + .await? + .json()?; + + println!( + "campaign donations 22lejo: {:?}, {}", + campaign_donations2, campaign_id + ); + + Ok(()) +} + +#[tokio::test] +async fn test_campaign_refunds_when_target_not_met() -> Result<()> { + let worker = sandbox().await?; + let (contract, alice, bob) = init(&worker).await?; + + // Create a campaign with a target that won't be met + let now = Utc::now().timestamp_millis(); + let start_ms = (now + 1000) as u64; + let end_ms = Some(start_ms + 10_000); + println!("SHOYUT PLSSS... {}", now); + let campaign_duration = 10_000; // 10 seconds + let campaign_id = create_test_campaign( + &contract, + &alice, + start_ms, + end_ms, + U128::from(10_000_000_000_000_000_000_000_000), + ) + .await?; + + // Make donations from Alice and Bob + let alice_donation = NearToken::from_near(1); + let bob_donation = NearToken::from_near(2); + + let alice_initial_balance = alice.view_account().await?.balance; + let bob_initial_balance = bob.view_account().await?.balance; + + donate_to_campaign(&alice, &contract, campaign_id, alice_donation).await?; + donate_to_campaign(&bob, &contract, campaign_id, bob_donation).await?; + donate_to_campaign(&alice, &contract, campaign_id, alice_donation).await?; + donate_to_campaign(&alice, &contract, campaign_id, alice_donation).await?; + + // Verify donations were made + let campaign: serde_json::Value = get_campaign(&contract, campaign_id).await?; + let total_donations = alice_donation + .saturating_mul(3) + .saturating_add(bob_donation); + assert_eq!( + campaign["total_raised_amount"], + total_donations.as_yoctonear().to_string() + ); + + // Wait for the campaign to end + worker.fast_forward(100).await?; + + // Process refunds + process_refunds(&contract, campaign_id).await?; + + // Verify refunds were processed + let alice_final_balance = alice.view_account().await?.balance; + let bob_final_balance = bob.view_account().await?.balance; + + // Check if Alice and Bob received their refunds (minus gas fees) + assert!(alice_final_balance > alice_initial_balance.saturating_sub(NearToken::from_near(1))); + assert!(bob_final_balance > bob_initial_balance.saturating_sub(NearToken::from_near(1))); + + // Verify campaign state after refunds + let campaign_after_refund: serde_json::Value = get_campaign(&contract, campaign_id).await?; + println!( + "unescroed baalnce campaign..... {:?}", + campaign_after_refund + ); + assert_eq!(campaign_after_refund["escrow_balance"], "0"); + + // Check if donations are marked as refunded + let campaign_donations: Vec = + get_campaign_donations(&contract, campaign_id).await?; + // for donation in campaign_donations { + // assert!(donation["returned_at_ms"].is_string()); + // } + + Ok(()) +} + +#[tokio::test] +async fn test_referral_fee_distribution() -> Result<()> { + let worker = sandbox().await?; + let (contract, alice, bob) = init(&worker).await?; + + // Create another account to be the referrer + let referrer = worker.dev_create_account().await?; + + let now = Utc::now().timestamp_millis() as u64; + + // Record initial balances + let referrer_initial_balance = referrer.view_account().await?.balance; + + // Create campaign with specific referral fee (500 basis points = 5%) + let res = create_campaign( + &contract, + alice.clone(), + "Test Referral Campaign".to_string(), + Some("Testing referral fees".to_string()), + None, + bob.id().clone(), // bob is the recipient + now + 1000, + Some(now + 10000), + None, // No FT + U128::from(10_000_000_000_000_000_000_000_000), // 10 NEAR target + None, // No min amount + None, // No max amount + Some(500), // 5% referral fee + Some(100), // 1% creator fee + Some(false), // Don't allow fee avoidance + ) + .await?; + + assert!(res.is_success()); + let campaign_id = extract_campaign_id_from_logs(&res)?; + + // Make a donation with referrer + let donation_amount = NearToken::from_near(10); // 10 NEAR + let donate_result = alice + .call(contract.id(), "donate") + .args_json(json!({ + "campaign_id": campaign_id, + "referrer_id": referrer.id(), + "message": "Donation with referral" + })) + .deposit(donation_amount) + .max_gas() + .transact() + .await?; + + assert!(donate_result.is_success()); + + // Get the donation details + let donations: Vec = contract + .call("get_donations_for_campaign") + .args_json(json!({ + "campaign_id": campaign_id, + "from_index": 0, + "limit": 10 + })) + .view() + .await? + .json()?; + + assert_eq!(donations.len(), 1); + + let donation = &donations[0]; + + // Calculate expected referral fee (5% of donation amount) + let expected_referral_fee = donation_amount.as_yoctonear() * 500 / 10000; + + // Verify referral fee in donation record + let actual_referral_fee = donation["referrer_fee"] + .as_str() + .unwrap() + .parse::() + .unwrap(); + assert_eq!(actual_referral_fee, expected_referral_fee); + + // Verify referrer_id in donation record + assert_eq!( + donation["referrer_id"].as_str().unwrap(), + referrer.id().to_string() + ); + + // Wait a bit and check referrer's balance + worker.fast_forward(5).await?; + let referrer_final_balance = referrer.view_account().await?.balance; + + // Verify referrer received the fee + // Note: We check if the balance increased by at least 90% of expected fee + // to account for gas fees and rounding + let balance_increase = referrer_final_balance.saturating_sub(referrer_initial_balance); + assert!( + balance_increase.as_yoctonear() >= expected_referral_fee * 90 / 100, + "Referrer didn't receive the expected fee. Expected around {} yoctoNEAR, got {} yoctoNEAR", + expected_referral_fee, + balance_increase.as_yoctonear() + ); + + // Also test a donation without referrer + let donate_without_referral = alice + .call(contract.id(), "donate") + .args_json(json!({ + "campaign_id": campaign_id, + "message": "Donation without referral" + })) + .deposit(donation_amount) + .max_gas() + .transact() + .await?; + + assert!(donate_without_referral.is_success()); + + // Verify the donation without referral + let all_donations: Vec = contract + .call("get_donations_for_campaign") + .args_json(json!({ + "campaign_id": campaign_id, + "from_index": 0, + "limit": 10 + })) + .view() + .await? + .json()?; + + let donation_without_referral = &all_donations[1]; + assert!(donation_without_referral["referrer_id"].is_null()); + assert!(donation_without_referral["referrer_fee"].is_null()); + + Ok(()) +} + +#[tokio::test] +async fn test_referral_fee_edge_cases() -> Result<()> { + let worker = sandbox().await?; + let (contract, alice, bob) = init(&worker).await?; + let referrer = worker.dev_create_account().await?; + + let now = Utc::now().timestamp_millis() as u64; + + // Test with maximum allowed referral fee (10%) + let res = create_campaign( + &contract, + alice.clone(), + "Max Referral Fee Campaign".to_string(), + None, + None, + bob.id().clone(), + now + 1000, + Some(now + 10000), + None, + U128::from(10_000_000_000_000_000_000_000_000), + None, + None, + Some(1000), // 10% - maximum allowed + None, + None, + ) + .await?; + + assert!(res.is_success()); + let campaign_id = extract_campaign_id_from_logs(&res)?; + + // Test with very small donation amount + let small_donation = NearToken::from_near(1); + let small_donate_result = alice + .call(contract.id(), "donate") + .args_json(json!({ + "campaign_id": campaign_id, + "referrer_id": referrer.id(), + })) + .deposit(small_donation) + .max_gas() + .transact() + .await?; + + assert!(small_donate_result.is_success()); + + // Try to create campaign with above maximum referral fee (should fail) + let invalid_res = create_campaign( + &contract, + alice.clone(), + "Invalid Referral Fee Campaign".to_string(), + None, + None, + bob.id().clone(), + now + 1000, + Some(now + 10000), + None, + U128::from(100), + None, + None, + Some(1100), // 11% - above maximum + None, + None, + ) + .await; + + assert!(invalid_res.is_err() || !invalid_res.unwrap().is_success()); + + Ok(()) +} + +async fn create_test_campaign( + contract: &Contract, + creator: &Account, + start_ms: u64, + end: Option, + target_amount: U128, +) -> Result { + let res = create_campaign( + contract, + creator.clone(), + "Test Refund Campaign".to_string(), + Some("Campaign for testing refunds".to_string()), + None, + creator.id().clone(), + start_ms, + end, + None, + target_amount, + Some(target_amount), + None, + Some(100), + Some(100), + Some(true), + ) + .await?; + + let campaign_id = extract_campaign_id_from_logs(&res)?; + Ok(campaign_id) +} + +async fn donate_to_campaign( + donor: &Account, + contract: &Contract, + campaign_id: u64, + amount: NearToken, +) -> Result<()> { + let donate_result = donor + .call(contract.id(), "donate") + .args_json(json!({ + "campaign_id": campaign_id, + })) + .max_gas() + .deposit(amount) + .transact() + .await?; + println!("less DONAT SUMMON!... {:?}", donate_result); + assert!(donate_result.is_success()); + Ok(()) +} + +async fn process_refunds(contract: &Contract, campaign_id: u64) -> Result<()> { + let process_refunds_result = contract + .call("process_refunds_batch") + .args_json(json!({ "campaign_id": campaign_id })) + .max_gas() + .transact() + .await?; + println!("less havit... {:?}", process_refunds_result); + assert!(process_refunds_result.is_success()); + Ok(()) +} + +async fn get_campaign(contract: &Contract, campaign_id: u64) -> Result { + let campaign: serde_json::Value = contract + .call("get_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + Ok(campaign) +} + +async fn get_campaign_donations( + contract: &Contract, + campaign_id: u64, +) -> Result> { + let campaign_donations: Vec = contract + .call("get_donations_for_campaign") + .args_json(json!({ "campaign_id": campaign_id })) + .view() + .await? + .json()?; + Ok(campaign_donations) +} + +fn extract_campaign_id_from_logs(res: &ExecutionFinalResult) -> Result { + let logs = res.logs(); + let campaign_create_log = logs + .iter() + .find(|log| log.contains("campaign_create")) + .expect("Campaign creation log not found"); + let event_json_start = campaign_create_log.find("EVENT_JSON:").unwrap() + "EVENT_JSON:".len(); + let event_json_str = &campaign_create_log[event_json_start..]; + let event_json: serde_json::Value = serde_json::from_str(event_json_str)?; + let campaign_id = event_json["data"][0]["campaign"]["id"] + .as_u64() + .expect("Failed to extract campaign ID"); + Ok(campaign_id) +} diff --git a/contracts/campaigns/tests/test_envs.rs b/contracts/campaigns/tests/test_envs.rs new file mode 100644 index 0000000..893cb76 --- /dev/null +++ b/contracts/campaigns/tests/test_envs.rs @@ -0,0 +1,38 @@ +use anyhow::Result; +use log::info; +use near_workspaces::{types::NearToken, Account, Contract, DevNetwork, Worker}; + +use std::sync::Once; + +// Initialize logger only once for all tests +static INIT: Once = Once::new(); + +pub fn init_logger() { + INIT.call_once(|| { + let _ = env_logger::builder().is_test(true).try_init(); + println!("Logger initialized"); + info!("Logger initialized"); // Log to confirm initialization + }); +} + +pub async fn init(worker: &Worker) -> Result<(Contract, Account, Account)> { + let campaigns_contract = worker + .dev_deploy(include_bytes!( + "../out/main.wasm" + )) + .await?; + + let res = campaigns_contract + .call("new_default_meta") + .args_json((campaigns_contract.id(),)) + .max_gas() + .transact() + .await?; + println!("dep jon.. {:?}", res); + assert!(res.is_success()); + + let alice = worker.dev_create_account().await?; + let bob = worker.dev_create_account().await?; + + return Ok((campaigns_contract, alice, bob)); +} diff --git a/contracts/lists/out/main.wasm b/contracts/lists/out/main.wasm index 2b14f86..4fcf9f4 100755 Binary files a/contracts/lists/out/main.wasm and b/contracts/lists/out/main.wasm differ