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..e059c58 100644 --- a/contracts/campaigns/README.md +++ b/contracts/campaigns/README.md @@ -1,73 +1,85 @@ -# Campaign Contract +# NEAR Campaigns Contract + +A decentralized crowdfunding platform built on the NEAR Protocol that enables users to create campaigns, donate to them, and manage funds through an escrow system. + +## Table of Contents +1. [Overview](#overview) +2. [Purpose](#purpose) +3. [Architecture](#architecture) +4. [Core Components](#core-components) +5. [State Management](#state-management) +6. [Operations](#operations) +7. [Security Considerations](#security-considerations) +8. [Error Handling](#error-handling) +9. [Events](#events) +10. [Contract Methods](#contract-methods) + +## Overview + +The NEAR Campaigns Contract provides a way to raise funds, either for yourself as an organization or on behalf of an organization, through donations. Campaigns can function as an escrow with minimum target amounts, refunding donors if the target is not met. Campaigns can be time-based and support both native NEAR and fungible token donations. + +```mermaid +graph TD + A[User] -->|Create| B[Campaign] + A -->|Donate| C[Donation] + C -->|Escrow| D[Escrow System] + D -->|Success| E[Recipient] + D -->|Failure| F[Refund] +``` ## Purpose -Provide a way to raise funds, for yourself as an organization, or on behalf of an organization, through donations, raising on behalf of organizations has an approval process to indicate whether the campaign is "official". -Contract can also function as an escrow with minimum target amounts, refunding donors if the target is not met. Campaigns can be time-based. - -The typical flow / lifetime of a camapign is as follows: +The typical flow / lifetime of a campaign is as follows: - Campaign is **created** via Campaign contract's `create_campaign` function call - Creator (e.g. user that calls `create_campaign` on contract) is, by default, the "owner" of the campaign -- After creation, some Campaign details can be updated by owner. +- After creation, some Campaign details can be updated by owner - A **recipient** account will be set during campaign creation, it defines who/what the campaign is for -- During the **campaign**(between `campaign.start_ms` and `campaign.end_ms`), end users may donate to the campaign. A `campaign_id` must be specified during donations. -- Donations are either held in escrow(until minimum target is reached) or transfered to the recipient. -- once rthe campaign is over, donations are processed in batch, sent to recipient and fees sent to the appropriate channels - -## Contract Structure +- During the **campaign** (between `campaign.start_ms` and `campaign.end_ms`), end users may donate to the campaign +- Donations are either held in escrow (until minimum target is reached) or transferred to the recipient +- Once the campaign is over, donations are processed in batch, sent to recipient and fees sent to the appropriate channels + +## Architecture + +### Contract Structure + +```mermaid +classDiagram + class Contract { + +owner: AccountId + +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: IterableMap + +campaign_ids_by_owner: IterableMap> + +campaign_ids_by_recipient: IterableMap> + +next_donation_id: DonationId + +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 + } +``` ### General Types -```rs +```rust type CampaignId = u64; type DonationId = u64; type TimestampMs = u64; type ReferrerPayouts = HashMap; ``` -### Contract +## Core Components -```rs -pub struct Contract { - contract_source_metadata: LazyOption, - owner: AccountId, - admins: UnorderedSet, - 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>, - 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, -} +### Campaign -/// NOT stored in contract storage; only used for get_config response -pub struct Config { - pub owner: AccountId, - pub admins: Vec, - pub protocol_fee_basis_points: u32, - 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, -} -``` - -### Campaigns - -_NB: Campaigns can be created on behalf of others, hence the recipient field. - -```rs +```rust pub struct Campaign { pub owner: AccountId, pub name: String, @@ -90,231 +102,266 @@ pub struct Campaign { } ``` -### Storage +### Donation + +```rust +pub struct Donation { + pub id: DonationId, + pub campaign_id: CampaignId, + pub donor_id: AccountId, + pub total_amount: u128, + pub net_amount: u128, + pub message: Option, + pub donated_at_ms: TimestampMs, + pub protocol_fee: u128, + pub referrer_id: Option, + pub referrer_fee: Option, + pub creator_fee: u128, + pub returned_at_ms: Option, +} +``` -The storage-related methods (`storage_deposit`, `storage_withdraw` and `storage_balance_of`) are utilized for fungible token (FT) donations, where the user must prepay storage on this Campaign contract - to cover the storage of the Donation data - before calling `ft_transfer_call` on the FT contract. +## State Management -This is a simplified version of the [Storage Management standard](https://nomicon.io/Standards/StorageManagement). +### Campaign Lifecycle -### Contract Source Metadata +```mermaid +stateDiagram-v2 + [*] --> Created + Created --> Active: Start Time Reached + Active --> Ended: End Time Reached + Active --> Failed: Min Amount Not Met + Active --> Successful: Target Reached + Ended --> Failed: Min Amount Not Met + Ended --> Successful: Min Amount Met +``` -_NB: Below implemented as per NEP 0330 (https://github.com/near/NEPs/blob/master/neps/nep-0330.md), with addition of `commit_hash`_ +### Donation Flow -```rs -pub struct ContractSourceMetadata { - /// Version of source code, e.g. "v1.0.0", could correspond to Git tag - pub version: String, - /// Git commit hash of currently deployed contract code - pub commit_hash: String, - /// GitHub repo url for currently deployed contract code - pub link: String, -} +```mermaid +sequenceDiagram + participant D as Donor + participant C as Contract + participant E as Escrow + participant R as Recipient + + D->>C: Donate + C->>E: Escrow Funds + alt Min Amount Reached + E->>R: Transfer Funds + E->>C: Update State + else Campaign Failed + E->>D: Refund + C->>C: Update State + end ``` -## Methods +## Operations + +### Campaign Management + +1. **Create Campaign** + - Input validation + - State initialization + - Storage setup + - Event emission + +2. **Update Campaign** + - Owner validation + - Parameter validation + - State updates + - Event emission + +3. **Delete Campaign** + - Preconditions check + - State cleanup + - Storage cleanup + - Event emission + +### Donation Management + +1. **Make Donation** + - Campaign validation + - Fee calculation + - State updates + - Escrow management + - Event emission + +2. **Process Escrowed Donations** + - Batch processing + - Transfer execution + - Fee distribution + - State updates + - Event emission + +3. **Process Refunds** + - Batch processing + - Refund calculation + - Transfer execution + - State updates + - Event emission + +## Security Considerations + +### Access Control +- Owner-only operations +- Admin privileges +- Campaign owner rights +- Donor permissions + +### Fee Management +- Protocol fees +- Creator fees +- Referral fees +- Fee avoidance controls + +### Storage Management +- Storage deposits +- Storage refunds +- Storage optimization + +## Error Handling + +### Error Types +1. **Validation Errors** + - Invalid parameters + - Invalid state + - Invalid timing + +2. **Permission Errors** + - Unauthorized access + - Invalid permissions + - Role violations + +3. **Transfer Errors** + - Failed transfers + - Insufficient funds + - Gas errors + +4. **State Errors** + - Invalid state transitions + - State conflicts + - State corruption + +## Events + +### Event Types +1. **Campaign Events** + - CampaignCreated + - CampaignUpdated + - CampaignDeleted + - CampaignEnded + +2. **Donation Events** + - DonationReceived + - DonationProcessed + - DonationRefunded + - DonationFailed + +3. **Fee Events** + - FeeCollected + - FeeDistributed + - FeeRefunded + +4. **System Events** + - StorageDeposited + - StorageRefunded + - StateUpdated + +## Contract Methods ### Write Methods **NB: ALL privileged write methods (those beginning with `admin_*` or `owner_*`) require an attached deposit of at least one yoctoNEAR, for security purposes.** -```rs +```rust // INIT - pub fn new( - owner: AccountId, - protocol_fee_basis_points: u32, - protocol_fee_recipient_account: AccountId, - default_referral_fee_basis_points: u32, - default_creator_fee_basis_points: u32, - source_metadata: ContractSourceMetadata, - ) -> Self { - + owner: AccountId, + protocol_fee_basis_points: u32, + protocol_fee_recipient_account: AccountId, + default_referral_fee_basis_points: u32, + default_creator_fee_basis_points: u32, + source_metadata: ContractSourceMetadata, +) -> Self // Campaign - #[payable] pub fn create_campaign( - &mut self, - 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, - ) -> CampaignExternal - + &mut self, + 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, +) -> CampaignExternal #[payable] pub fn update_campaign( - &mut self, - campaign_id: CampaignId, - name: Option, - description: Option, - cover_image_url: Option, - start_ms: Option, - end_ms: Option, - ft_id: 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 { - + &mut self, + campaign_id: CampaignId, + name: Option, + description: Option, + cover_image_url: Option, + start_ms: Option, + end_ms: Option, + ft_id: Option, + target_amount: Option, + max_amount: Option, + min_amount: Option, + allow_fee_avoidance: Option, +) -> CampaignExternal pub fn delete_campaign(&mut self, campaign_id: CampaignId) -// Donation +// Donation #[payable] pub fn donate( - &mut self, - campaign_id: CampaignId, - message: Option, - referrer_id: Option, - bypass_protocol_fee: Option, - bypass_creator_fee: Option, - ) -> PromiseOrValue { - - -// STORAGE - + &mut self, + campaign_id: CampaignId, + message: Option, + referrer_id: Option, + bypass_protocol_fee: Option, + bypass_creator_fee: Option, +) -> PromiseOrValue + +// Storage pub fn storage_deposit(&mut self) -> U128 - pub fn storage_withdraw(&mut self, amount: Option) -> U128 - -// OWNER - +// Owner #[payable] pub fn owner_change_owner(&mut self, owner: AccountId) - pub fn owner_add_admins(&mut self, admins: Vec) pub fn owner_remove_admins(&mut self, admins: Vec) pub fn owner_clear_admins(&mut self) -// SOURCE METADATA - -pub fn self_set_source_metadata(&mut self, source_metadata: ContractSourceMetadata) // only callable by the contract account (reasoning is that this should be able to be updated by the same account that can deploy code to the account) - +// Source Metadata +pub fn self_set_source_metadata(&mut self, source_metadata: ContractSourceMetadata) ``` ### Read Methods -```rs -// CONFIG - +```rust +// Config pub fn get_config(&self) -> Config -// CAMPAIGNS -get_campaign(&self, campaign_id: CampaignId) -> CampaignExternal - -get_campaigns( - &self, - from_index: Option, - limit: Option, - ) -> Vec - - -pub fn get_campaigns_by_owner( - &self, - owner_id: AccountId, - from_index: Option, - limit: Option, - ) -> Vec - -pub fn get_campaigns_by_recipient( - &self, - recipient_id: AccountId, - from_index: Option, - limit: Option, - ) -> Vec +// Campaigns +pub fn get_campaign(&self, campaign_id: CampaignId) -> CampaignExternal +pub fn get_campaigns(&self, from_index: Option, limit: Option) -> Vec +pub fn get_campaigns_by_owner(&self, owner_id: AccountId, from_index: Option, limit: Option) -> Vec +pub fn get_campaigns_by_recipient(&self, recipient_id: AccountId, from_index: Option, limit: Option) -> Vec - - -// DONATIONS +// Donations pub fn get_donations(&self, from_index: Option, limit: Option) -> Vec - pub fn get_donation_by_id(&self, donation_id: DonationId) -> Option - -pub fn get_donations_for_campaign( - &self, - campaign_id: CampaignId, - from_index: Option, - limit: Option, - ) -> Vec - -pub fn get_donations_for_donor( - &self, - donor_id: AccountId, - from_index: Option, - limit: Option, - ) -> Vec - - -// STORAGE - -pub fn storage_balance_of(&self, account_id: &AccountId) -> U128 - - -// OWNER - -pub fn get_owner(&self) -> AccountId - - -// SOURCE METADATA - -pub fn get_contract_source_metadata(&self) -> Option -``` - -## Events - -### `campaign` - -Indicates that a `Campaign` object has been created. - -**Example:** - -```json -{ - "standard": "potlock", - "version": "1.0.0", - "event": "campaign_create", - "data": [ - { - "campaign": { - "owner": "" - } - } - ] -} -``` - -### `set_source_metadata` - -Indicates that `ContractSourceMetadata` object has been set/updated. - -**Example:** - -```json -{ - "standard": "potlock", - "version": "1.0.0", - "event": "set_source_metadata", - "data": [ - { - "source_metadata": { - "commit_hash": "ec02294253b22c2d4c50a75331df23ada9eb04db", - "link": "https://github.com/PotLock/core", - "version": "0.1.0" - } - } - ] -} +pub fn get_donations_for_campaign(&self, campaign_id: CampaignId, from_index: Option, limit: Option) -> Vec ``` diff --git a/contracts/campaigns/out/main.wasm b/contracts/campaigns/out/main.wasm index e1d7007..6cab821 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..ebd803b 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,15 @@ 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" + ); + 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 +143,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 +216,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; @@ -254,12 +266,12 @@ impl Contract { if let Some(end_ms) = end_ms { assert!(campaign.start_ms < end_ms, "end_ms must be after start_ms"); assert!( - campaign.net_raised_amount <= campaign.max_amount.unwrap_or(u128::MAX), + campaign.net_raised_amount < campaign.max_amount.unwrap_or(u128::MAX), "Cannot edit end_ms after max_amount has been reached" ); 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); @@ -267,26 +279,26 @@ impl Contract { // Owner can change target_amount until max_amount or end_ms is reached if let Some(target_amount) = target_amount { assert!( - campaign.net_raised_amount <= campaign.max_amount.unwrap_or(u128::MAX), + campaign.net_raised_amount < campaign.max_amount.unwrap_or(u128::MAX), "Cannot edit target_amount after max_amount has been reached" ); assert!( 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 { assert!( - campaign.net_raised_amount <= campaign.max_amount.unwrap_or(u128::MAX), + campaign.net_raised_amount < campaign.max_amount.unwrap_or(u128::MAX), "Cannot edit max_amount after it has been reached" ); assert!( 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 +315,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 +335,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) } @@ -342,11 +356,61 @@ impl Contract { ); let limit = limit.map(|v| v as usize).unwrap_or(usize::MAX); assert_ne!(limit, 0, "Cannot provide limit of 0."); - self.campaigns_by_id + + // Collect all campaigns into a vector + let mut campaigns: Vec<(CampaignId, Campaign)> = self + .campaigns_by_id .iter() + .map(|(id, v)| (*id, Campaign::from(v.clone()))) + .collect(); + + // Sort campaigns by created_ms in descending order + campaigns.sort_by(|a, b| b.1.created_ms.cmp(&a.1.created_ms)); + + // Apply from_index and limit + campaigns + .into_iter() .skip(start_index as usize) .take(limit) - .map(|(id, v)| format_campaign(&id, &Campaign::from(v))) + .map(|(id, campaign)| format_campaign(&id, &campaign)) + .collect() + } + + // pub fn get_campaigns( + // &self, + // from_index: Option, + // limit: Option, + // ) -> Vec { + // let start_index: u128 = from_index.unwrap_or_default(); + // assert!( + // (self.campaigns_by_id.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."); + // self.campaigns_by_id + // .iter() + // .skip(start_index as usize) + // .take(limit) + // .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 +422,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 +432,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 +443,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..a90d424 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.remove(&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..0017136 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,70 @@ 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( + let mut campaign = Campaign::from( self.campaigns_by_id .get(&campaign_id) - .expect("Campaign not found"), + .expect("Campaign not found") + .clone(), ); + + // Reduce escrow balance by the transferred amount + campaign.escrow_balance -= amount; + + // Save updated campaign + self.campaigns_by_id + .insert(campaign_id, VersionedCampaign::Current(campaign.clone())); + // log event + log_escrow_process_event(&donation_ids); + // send fees + // 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 +216,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 +227,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 +241,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 +252,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 +290,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 +315,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 +355,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 +365,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 +379,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 +389,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,14 +406,14 @@ 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), ); } } /// Verifies whether refund was successful and updates escrowed_donation_ids and Donation.returned accordingly for each donation refunded for this donor - #[private] // Public - but only callable by env::current_account_id() + #[private] pub fn transfer_refund_callback( &mut self, donor_id: AccountId, @@ -388,7 +425,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 +435,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 +447,49 @@ 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