diff --git a/.deny.toml b/.deny.toml index 9121ae29..1cb3879c 100644 --- a/.deny.toml +++ b/.deny.toml @@ -1,8 +1,8 @@ # Config file reference can be found at https://embarkstudios.github.io/cargo-deny/checks/cfg.html. [graph] -all-features = true -exclude-dev = true +all-features = true +exclude-dev = true no-default-features = true [advisories] @@ -18,7 +18,7 @@ unused-ignored-advisory = "deny" [bans] allow-wildcard-paths = false -multiple-versions = "allow" +multiple-versions = "allow" [licenses] allow = [ diff --git a/Cargo.lock b/Cargo.lock index 72e408c3..e154a5d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,7 +73,7 @@ dependencies = [ "bitflags 2.10.0", "bytes", "bytestring", - "derive_more 2.1.1", + "derive_more 2.1.0", "encoding_rs", "foldhash", "futures-core", @@ -102,7 +102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -215,7 +215,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -226,7 +226,7 @@ checksum = "b6ac1e58cded18cb28ddc17143c4dea5345b3ad575e14f32f66e4054a56eb271" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -270,7 +270,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.16", "once_cell", "version_check", ] @@ -447,7 +447,7 @@ checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -545,7 +545,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -571,7 +571,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -717,7 +717,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -801,7 +801,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -812,7 +812,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -855,10 +855,9 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tower 0.5.3", + "tower", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -879,7 +878,6 @@ dependencies = [ "sync_wrapper", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -918,9 +916,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.3" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "bedrock_client" @@ -961,7 +959,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1043,7 +1041,7 @@ dependencies = [ "maybe-async", "reqwest", "serde", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -1066,7 +1064,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1086,9 +1084,9 @@ checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] @@ -1101,7 +1099,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1167,7 +1165,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -1178,22 +1176,22 @@ checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" dependencies = [ "clap", "heck", - "indexmap 2.13.0", + "indexmap 2.12.1", "log", "proc-macro2", "quote", "serde", "serde_json", - "syn 2.0.114", + "syn 2.0.111", "tempfile", - "toml 0.9.11+spec-1.1.0", + "toml 0.9.9+spec-1.0.0", ] [[package]] name = "cc" -version = "1.2.55" +version = "1.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ "find-msvc-tools", "jobserver", @@ -1236,7 +1234,7 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1252,9 +1250,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.43" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "js-sys", @@ -1287,9 +1285,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.56" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", "clap_derive", @@ -1297,9 +1295,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.56" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstream", "anstyle", @@ -1309,21 +1307,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.55" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] name = "clap_lex" -version = "0.7.7" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cobs" @@ -1331,7 +1329,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -1366,7 +1364,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror 2.0.18", + "thiserror 2.0.17", "url", ] @@ -1564,7 +1562,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1598,7 +1596,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1612,7 +1610,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1623,7 +1621,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1634,20 +1632,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.114", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", + "syn 2.0.111", ] [[package]] @@ -1726,7 +1711,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1736,7 +1721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1749,29 +1734,29 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] name = "derive_more" -version = "2.1.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" dependencies = [ "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version", - "syn 2.0.114", + "syn 2.0.111", "unicode-xid", ] @@ -1816,7 +1801,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1897,7 +1882,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -1977,7 +1962,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -2050,9 +2035,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "fnv" @@ -2093,7 +2078,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -2117,16 +2102,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "forwarded-header-value" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" -dependencies = [ - "nonempty", - "thiserror 1.0.69", -] - [[package]] name = "futures" version = "0.3.31" @@ -2183,7 +2158,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -2250,9 +2225,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", @@ -2337,26 +2312,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "governor" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" -dependencies = [ - "cfg-if", - "dashmap", - "futures", - "futures-timer", - "no-std-compat", - "nonzero_ext", - "parking_lot", - "portable-atomic", - "quanta", - "rand 0.8.5", - "smallvec", - "spinning_top", -] - [[package]] name = "group" version = "0.13.0" @@ -2380,7 +2335,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.13.0", + "indexmap 2.12.1", "slab", "tokio", "tokio-util", @@ -2399,7 +2354,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.4.0", - "indexmap 2.13.0", + "indexmap 2.12.1", "slab", "tokio", "tokio-util", @@ -2421,12 +2376,6 @@ dependencies = [ "ahash 0.8.12", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashbrown" version = "0.15.5" @@ -2511,9 +2460,9 @@ dependencies = [ [[package]] name = "hmac-sha512" -version = "1.1.8" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c4d256181c136fe596b5e8cf23adf99c58f71bb54e98058cfa976caf8cc5c2" +checksum = "e89e8d20b3799fa526152a5301a771eaaad80857f83e01b23216ceaafb2d9280" [[package]] name = "http" @@ -2652,7 +2601,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.2", + "socket2 0.6.1", "system-configuration", "tokio", "tower-service", @@ -2662,9 +2611,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.65" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2840,7 +2789,7 @@ dependencies = [ "common", "nssa", "nssa_core", - "schemars 1.2.0", + "schemars 1.2.1", "serde", ] @@ -2850,7 +2799,7 @@ version = "0.1.0" dependencies = [ "indexer_service_protocol", "jsonrpsee", - "schemars 1.2.0", + "schemars 1.2.1", "serde_json", ] @@ -2867,9 +2816,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -2921,6 +2870,7 @@ dependencies = [ "sequencer_runner", "serde_json", "tempfile", + "token_core", "tokio", "url", "wallet", @@ -2935,9 +2885,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.10" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -2989,9 +2939,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jf-crhf" @@ -3052,9 +3002,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -3095,7 +3045,7 @@ dependencies = [ "rustls-pki-types", "rustls-platform-verifier", "soketto", - "thiserror 2.0.18", + "thiserror 2.0.17", "tokio", "tokio-rustls", "tokio-util", @@ -3123,10 +3073,10 @@ dependencies = [ "rustc-hash", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", "tokio", "tokio-stream", - "tower 0.5.3", + "tower", "tracing", "wasm-bindgen-futures", ] @@ -3148,9 +3098,9 @@ dependencies = [ "rustls-platform-verifier", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", "tokio", - "tower 0.5.3", + "tower", "url", ] @@ -3164,7 +3114,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -3186,11 +3136,11 @@ dependencies = [ "serde", "serde_json", "soketto", - "thiserror 2.0.18", + "thiserror 2.0.17", "tokio", "tokio-stream", "tokio-util", - "tower 0.5.3", + "tower", "tracing", ] @@ -3203,7 +3153,7 @@ dependencies = [ "http 1.4.0", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3215,7 +3165,7 @@ dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", - "tower 0.5.3", + "tower", ] [[package]] @@ -3228,7 +3178,7 @@ dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", - "tower 0.5.3", + "tower", "url", ] @@ -3274,7 +3224,7 @@ dependencies = [ "rand 0.8.5", "serde", "sha2", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3285,9 +3235,9 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] name = "lazy-regex" -version = "3.5.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5c13b6857ade4c8ee05c3c3dc97d2ab5415d691213825b90d3211c425c1f907" +checksum = "191898e17ddee19e60bccb3945aa02339e81edd4a8c50e21fd4d48cdecda7b29" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -3296,14 +3246,14 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.5.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a95c68db5d41694cea563c86a4ba4dc02141c16ef64814108cb23def4d5438" +checksum = "c35dc8b0da83d1a9507e12122c80dea71a9c7c613014347392483a83ea593e04" dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -3317,9 +3267,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.180" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libloading" @@ -3333,9 +3283,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libp2p-identity" @@ -3347,15 +3297,15 @@ dependencies = [ "hkdf", "multihash", "sha2", - "thiserror 2.0.18", + "thiserror 2.0.17", "tracing", ] [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" dependencies = [ "bitflags 2.10.0", "libc", @@ -3444,7 +3394,7 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "logos-blockchain-blend-crypto" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "blake2", "logos-blockchain-groth16", @@ -3458,7 +3408,7 @@ dependencies = [ [[package]] name = "logos-blockchain-blend-message" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "blake2", "derivative", @@ -3480,7 +3430,7 @@ dependencies = [ [[package]] name = "logos-blockchain-blend-proofs" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "ed25519-dalek", "generic-array 1.3.5", @@ -3495,7 +3445,7 @@ dependencies = [ [[package]] name = "logos-blockchain-chain-broadcast-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "derivative", @@ -3511,7 +3461,7 @@ dependencies = [ [[package]] name = "logos-blockchain-chain-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "bytes", @@ -3541,7 +3491,7 @@ dependencies = [ [[package]] name = "logos-blockchain-circuits-prover" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "logos-blockchain-circuits-utils", "tempfile", @@ -3550,7 +3500,7 @@ dependencies = [ [[package]] name = "logos-blockchain-circuits-utils" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "dirs", ] @@ -3558,7 +3508,7 @@ dependencies = [ [[package]] name = "logos-blockchain-common-http-client" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "futures", "logos-blockchain-chain-broadcast-service", @@ -3575,7 +3525,7 @@ dependencies = [ [[package]] name = "logos-blockchain-core" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "ark-ff 0.4.2", "bincode", @@ -3605,7 +3555,7 @@ dependencies = [ [[package]] name = "logos-blockchain-cryptarchia-engine" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "cfg_eval", "logos-blockchain-utils", @@ -3620,7 +3570,7 @@ dependencies = [ [[package]] name = "logos-blockchain-cryptarchia-sync" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "bytes", "futures", @@ -3637,7 +3587,7 @@ dependencies = [ [[package]] name = "logos-blockchain-groth16" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "ark-bn254 0.4.0", "ark-ec 0.4.2", @@ -3649,34 +3599,31 @@ dependencies = [ "num-bigint", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "logos-blockchain-http-api-common" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "axum", - "governor", "logos-blockchain-core", "logos-blockchain-key-management-system-keys", "serde", "serde_json", "serde_with", - "tower_governor", ] [[package]] name = "logos-blockchain-key-management-system-keys" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "bytes", "ed25519-dalek", "generic-array 1.3.5", - "logos-blockchain-blend-proofs", "logos-blockchain-groth16", "logos-blockchain-key-management-system-macros", "logos-blockchain-poseidon2", @@ -3686,7 +3633,7 @@ dependencies = [ "rand_core 0.6.4", "serde", "subtle", - "thiserror 2.0.18", + "thiserror 2.0.17", "tokio", "tracing", "x25519-dalek", @@ -3696,24 +3643,41 @@ dependencies = [ [[package]] name = "logos-blockchain-key-management-system-macros" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", +] + +[[package]] +name = "logos-blockchain-key-management-system-operators" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" +dependencies = [ + "async-trait", + "logos-blockchain-blend-proofs", + "logos-blockchain-core", + "logos-blockchain-groth16", + "logos-blockchain-key-management-system-keys", + "logos-blockchain-poseidon2", + "logos-blockchain-utxotree", + "tokio", + "tracing", ] [[package]] name = "logos-blockchain-key-management-system-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "log", "logos-blockchain-key-management-system-keys", + "logos-blockchain-key-management-system-operators", "overwatch", "serde", - "thiserror 2.0.18", + "thiserror 2.0.17", "tokio", "tracing", ] @@ -3721,7 +3685,7 @@ dependencies = [ [[package]] name = "logos-blockchain-ledger" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "derivative", "logos-blockchain-blend-crypto", @@ -3745,7 +3709,7 @@ dependencies = [ [[package]] name = "logos-blockchain-network-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "futures", @@ -3761,7 +3725,7 @@ dependencies = [ [[package]] name = "logos-blockchain-poc" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "logos-blockchain-circuits-prover", "logos-blockchain-circuits-utils", @@ -3770,13 +3734,13 @@ dependencies = [ "num-bigint", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "logos-blockchain-pol" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "logos-blockchain-circuits-prover", "logos-blockchain-circuits-utils", @@ -3786,13 +3750,13 @@ dependencies = [ "num-traits", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "logos-blockchain-poq" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "logos-blockchain-circuits-prover", "logos-blockchain-circuits-utils", @@ -3802,13 +3766,13 @@ dependencies = [ "num-bigint", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "logos-blockchain-poseidon2" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", @@ -3819,7 +3783,7 @@ dependencies = [ [[package]] name = "logos-blockchain-services-utils" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "futures", @@ -3834,7 +3798,7 @@ dependencies = [ [[package]] name = "logos-blockchain-storage-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "bytes", @@ -3851,7 +3815,7 @@ dependencies = [ [[package]] name = "logos-blockchain-time-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "futures", @@ -3859,7 +3823,7 @@ dependencies = [ "logos-blockchain-cryptarchia-engine", "overwatch", "sntpc", - "thiserror 2.0.18", + "thiserror 2.0.17", "time", "tokio", "tokio-stream", @@ -3869,7 +3833,7 @@ dependencies = [ [[package]] name = "logos-blockchain-utils" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "async-trait", "blake2", @@ -3886,7 +3850,7 @@ dependencies = [ [[package]] name = "logos-blockchain-utxotree" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "ark-ff 0.4.2", "logos-blockchain-groth16", @@ -3900,7 +3864,7 @@ dependencies = [ [[package]] name = "logos-blockchain-witness-generator" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "tempfile", ] @@ -3908,7 +3872,7 @@ dependencies = [ [[package]] name = "logos-blockchain-zksign" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#ea98ac1ad09ac29fe8350614a260c20d8de12bfe" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#271a97ebd03f21a13e9ca72ef8411fd478960296" dependencies = [ "logos-blockchain-circuits-prover", "logos-blockchain-circuits-utils", @@ -3918,7 +3882,7 @@ dependencies = [ "num-bigint", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3944,7 +3908,7 @@ checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -3961,7 +3925,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -4103,12 +4067,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "no-std-compat" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" - [[package]] name = "no_std_strings" version = "0.1.3" @@ -4134,18 +4092,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "nonempty" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" - -[[package]] -name = "nonzero_ext" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" - [[package]] name = "nssa" version = "0.1.0" @@ -4166,7 +4112,8 @@ dependencies = [ "sha2", "test-case", "test_program_methods", - "thiserror 2.0.18", + "thiserror 2.0.17", + "token_core", ] [[package]] @@ -4182,7 +4129,7 @@ dependencies = [ "risc0-zkvm", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -4213,9 +4160,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.0" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" @@ -4265,7 +4212,7 @@ checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -4318,7 +4265,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -4353,7 +4300,7 @@ checksum = "969ccca8ffc4fb105bd131a228107d5c9dd89d9d627edf3295cbe979156f9712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -4370,7 +4317,7 @@ dependencies = [ "async-trait", "futures", "overwatch-derive", - "thiserror 2.0.18", + "thiserror 2.0.17", "tokio", "tokio-stream", "tokio-util", @@ -4386,7 +4333,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -4450,7 +4397,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -4506,9 +4453,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "postcard" @@ -4574,14 +4521,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -4594,7 +4541,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", "version_check", ] @@ -4623,6 +4570,8 @@ dependencies = [ "nssa_core", "risc0-zkvm", "serde", + "token_core", + "token_program", ] [[package]] @@ -4659,22 +4608,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.114", -] - -[[package]] -name = "quanta" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" -dependencies = [ - "crossbeam-utils", - "libc", - "once_cell", - "raw-cpuid", - "wasi", - "web-sys", - "winapi", + "syn 2.0.111", ] [[package]] @@ -4690,8 +4624,8 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.2", - "thiserror 2.0.18", + "socket2 0.6.1", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -4712,7 +4646,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.18", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -4727,16 +4661,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.2", + "socket2 0.6.1", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.44" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -4765,7 +4699,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.5", + "rand_core 0.9.3", ] [[package]] @@ -4785,7 +4719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.5", + "rand_core 0.9.3", ] [[package]] @@ -4794,14 +4728,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.16", ] [[package]] name = "rand_core" -version = "0.9.5" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.4", ] @@ -4812,16 +4746,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.5", -] - -[[package]] -name = "raw-cpuid" -version = "11.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" -dependencies = [ - "bitflags 2.10.0", + "rand_core 0.9.3", ] [[package]] @@ -4839,9 +4764,9 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.16", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -4861,7 +4786,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -4901,9 +4826,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.28" +version = "0.12.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" dependencies = [ "base64", "bytes", @@ -4936,7 +4861,7 @@ dependencies = [ "tokio-native-tls", "tokio-rustls", "tokio-util", - "tower 0.5.3", + "tower", "tower-http", "tower-service", "url", @@ -4965,7 +4890,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.17", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -4980,7 +4905,7 @@ dependencies = [ "anyhow", "borsh", "bytemuck", - "derive_more 2.1.1", + "derive_more 2.1.0", "elf", "lazy_static", "postcard", @@ -5057,7 +4982,7 @@ dependencies = [ "anyhow", "bit-vec", "bytemuck", - "derive_more 2.1.1", + "derive_more 2.1.0", "paste", "risc0-binfmt", "risc0-core", @@ -5073,7 +4998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80f2723fedace48c6c5a505bd8f97ac4e1712bc4cb769083e10536d862b66987" dependencies = [ "bytemuck", - "rand_core 0.9.5", + "rand_core 0.9.3", ] [[package]] @@ -5124,7 +5049,7 @@ dependencies = [ "hex-literal 0.4.1", "metal", "paste", - "rand_core 0.9.5", + "rand_core 0.9.3", "risc0-core", "risc0-zkvm-platform", "serde", @@ -5145,7 +5070,7 @@ dependencies = [ "borsh", "bytemuck", "bytes", - "derive_more 2.1.1", + "derive_more 2.1.0", "hex", "lazy-regex", "prost", @@ -5177,7 +5102,7 @@ checksum = "cfaa10feba15828c788837ddde84b994393936d8f5715228627cfe8625122a40" dependencies = [ "bytemuck", "cfg-if", - "getrandom 0.2.17", + "getrandom 0.2.16", "getrandom 0.3.4", "libm", "num_enum", @@ -5235,16 +5160,16 @@ dependencies = [ "quote", "rand 0.9.2", "syn 1.0.109", - "thiserror 2.0.18", + "thiserror 2.0.17", "tiny-keccak", "tokio", ] [[package]] name = "rsa" -version = "0.9.10" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" dependencies = [ "const-oid", "digest", @@ -5299,9 +5224,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags 2.10.0", "errno", @@ -5312,9 +5237,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "log", "once_cell", @@ -5339,9 +5264,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" dependencies = [ "web-time", "zeroize", @@ -5365,7 +5290,7 @@ dependencies = [ "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs 0.26.11", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5376,9 +5301,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -5393,9 +5318,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "rzup" @@ -5411,7 +5336,7 @@ dependencies = [ "sha2", "strum", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.17", "toml 0.8.23", "yaml-rust2", ] @@ -5448,9 +5373,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ "dyn-clone", "ref-cast", @@ -5461,14 +5386,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4908ad288c5035a8eb12cfdf0d49270def0a268ee162b75eeee0f85d155a7c45" +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -5666,7 +5591,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -5677,20 +5602,20 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", + "ryu", "serde", "serde_core", - "zmij", ] [[package]] @@ -5744,9 +5669,9 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.0", + "indexmap 2.12.1", "schemars 0.9.0", - "schemars 1.2.0", + "schemars 1.2.1", "serde_core", "serde_json", "serde_with_macros", @@ -5762,7 +5687,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -5805,11 +5730,10 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.8" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ - "errno", "libc", ] @@ -5825,9 +5749,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.12" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -5867,9 +5791,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", "windows-sys 0.60.2", @@ -5897,15 +5821,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spinning_top" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" -dependencies = [ - "lock_api", -] - [[package]] name = "spki" version = "0.7.3" @@ -5923,7 +5838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" dependencies = [ "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -5946,7 +5861,7 @@ dependencies = [ "common", "nssa", "rocksdb", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -5973,7 +5888,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -5995,9 +5910,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -6021,25 +5936,25 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "bitflags 2.10.0", + "bitflags 1.3.2", "core-foundation 0.9.4", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.6.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" dependencies = [ "core-foundation-sys", "libc", @@ -6047,9 +5962,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.24.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.4", @@ -6085,7 +6000,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -6096,7 +6011,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", "test-case-core", ] @@ -6126,11 +6041,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.17", ] [[package]] @@ -6141,46 +6056,46 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] name = "time" -version = "0.3.46" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde_core", + "serde", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.26" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -6220,11 +6135,28 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "token_core" +version = "0.1.0" +dependencies = [ + "borsh", + "nssa_core", + "serde", +] + +[[package]] +name = "token_program" +version = "0.1.0" +dependencies = [ + "nssa_core", + "token_core", +] + [[package]] name = "tokio" -version = "1.49.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ "bytes", "libc", @@ -6232,7 +6164,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.2", + "socket2 0.6.1", "tokio-macros", "windows-sys 0.61.2", ] @@ -6245,7 +6177,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -6319,14 +6251,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.11+spec-1.1.0" +version = "0.9.9+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +checksum = "eb5238e643fc34a1d5d7e753e1532a91912d74b63b92b3ea51fde8d1b7bc79dd" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.12.1", "serde_core", "serde_spanned 1.0.4", - "toml_datetime 0.7.5+spec-1.1.0", + "toml_datetime 0.7.4+spec-1.0.0", "toml_parser", "toml_writer", "winnow", @@ -6343,9 +6275,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "0.7.4+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "fe3cea6b2aa3b910092f6abd4053ea464fab5f9c170ba5e9a6aead16ec4af2b6" dependencies = [ "serde_core", ] @@ -6356,7 +6288,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.12.1", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -6370,17 +6302,17 @@ version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ - "indexmap 2.13.0", - "toml_datetime 0.7.5+spec-1.1.0", + "indexmap 2.12.1", + "toml_datetime 0.7.4+spec-1.0.0", "toml_parser", "winnow", ] [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.5+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "4c03bee5ce3696f31250db0bbaff18bc43301ce0e8db2ed1f07cbb2acf89984c" dependencies = [ "winnow", ] @@ -6399,20 +6331,9 @@ checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "tower" -version = "0.4.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", @@ -6421,7 +6342,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -6437,7 +6357,7 @@ dependencies = [ "http-body", "iri-string", "pin-project-lite", - "tower 0.5.3", + "tower", "tower-layer", "tower-service", ] @@ -6454,27 +6374,11 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" -[[package]] -name = "tower_governor" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3790eac6ad3fb8d9d96c2b040ae06e2517aa24b067545d1078b96ae72f7bb9a7" -dependencies = [ - "axum", - "forwarded-header-value", - "governor", - "http 1.4.0", - "pin-project", - "thiserror 1.0.69", - "tower 0.4.13", - "tracing", -] - [[package]] name = "tracing" -version = "0.1.44" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ "log", "pin-project-lite", @@ -6490,14 +6394,14 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] name = "tracing-core" -version = "0.1.36" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", "valuable", @@ -6609,15 +6513,14 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.8" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", - "serde_derive", ] [[package]] @@ -6687,6 +6590,7 @@ dependencies = [ "serde", "serde_json", "sha2", + "token_core", "tokio", "url", ] @@ -6721,18 +6625,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -6743,12 +6647,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", - "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -6757,9 +6660,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6767,22 +6670,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] @@ -6802,9 +6705,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -6826,23 +6729,23 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.5", + "webpki-root-certs 1.0.6", ] [[package]] name = "webpki-root-certs" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.5" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] @@ -6899,7 +6802,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -6910,7 +6813,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -6966,15 +6869,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -7190,9 +7084,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.51.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" @@ -7242,28 +7136,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.37" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.37" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -7283,7 +7177,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", "synstructure", ] @@ -7298,13 +7192,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] [[package]] @@ -7337,11 +7231,5 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.111", ] - -[[package]] -name = "zmij" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1966f8ac2c1f76987d69a74d0e0f929241c10e78136434e3be70ff7f58f64214" diff --git a/Cargo.toml b/Cargo.toml index 4467be14..ad2d9276 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ members = [ "indexer_service", "indexer_service/protocol", "indexer_service/rpc", + "programs/token/core", + "programs/token", "program_methods", "program_methods/guest", "test_program_methods", @@ -45,6 +47,8 @@ indexer_service_protocol = { path = "indexer_service/protocol" } indexer_service_rpc = { path = "indexer_service/rpc" } wallet = { path = "wallet" } wallet-ffi = { path = "wallet-ffi" } +token_core = { path = "programs/token/core" } +token_program = { path = "programs/token" } test_program_methods = { path = "test_program_methods" } bedrock_client = { path = "bedrock_client" } indexer_core = { path = "indexer_core" } diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index e2ed3fda..e7f89d53 100644 Binary files a/artifacts/program_methods/amm.bin and b/artifacts/program_methods/amm.bin differ diff --git a/artifacts/program_methods/authenticated_transfer.bin b/artifacts/program_methods/authenticated_transfer.bin index fa5574c5..480ea8d0 100644 Binary files a/artifacts/program_methods/authenticated_transfer.bin and b/artifacts/program_methods/authenticated_transfer.bin differ diff --git a/artifacts/program_methods/pinata.bin b/artifacts/program_methods/pinata.bin index fb1626c7..87f779f8 100644 Binary files a/artifacts/program_methods/pinata.bin and b/artifacts/program_methods/pinata.bin differ diff --git a/artifacts/program_methods/pinata_token.bin b/artifacts/program_methods/pinata_token.bin index 0368043b..460dbee0 100644 Binary files a/artifacts/program_methods/pinata_token.bin and b/artifacts/program_methods/pinata_token.bin differ diff --git a/artifacts/program_methods/privacy_preserving_circuit.bin b/artifacts/program_methods/privacy_preserving_circuit.bin index 4ad798ff..edd0f126 100644 Binary files a/artifacts/program_methods/privacy_preserving_circuit.bin and b/artifacts/program_methods/privacy_preserving_circuit.bin differ diff --git a/artifacts/program_methods/token.bin b/artifacts/program_methods/token.bin index f2a7fa15..f091c55e 100644 Binary files a/artifacts/program_methods/token.bin and b/artifacts/program_methods/token.bin differ diff --git a/artifacts/test_program_methods/burner.bin b/artifacts/test_program_methods/burner.bin index 6acb0d0c..bce7959d 100644 Binary files a/artifacts/test_program_methods/burner.bin and b/artifacts/test_program_methods/burner.bin differ diff --git a/artifacts/test_program_methods/chain_caller.bin b/artifacts/test_program_methods/chain_caller.bin index 3ddac7b4..2f35f7f8 100644 Binary files a/artifacts/test_program_methods/chain_caller.bin and b/artifacts/test_program_methods/chain_caller.bin differ diff --git a/artifacts/test_program_methods/changer_claimer.bin b/artifacts/test_program_methods/changer_claimer.bin index 9268e215..baf09a17 100644 Binary files a/artifacts/test_program_methods/changer_claimer.bin and b/artifacts/test_program_methods/changer_claimer.bin differ diff --git a/artifacts/test_program_methods/claimer.bin b/artifacts/test_program_methods/claimer.bin index 6a3b8259..37eb35d0 100644 Binary files a/artifacts/test_program_methods/claimer.bin and b/artifacts/test_program_methods/claimer.bin differ diff --git a/artifacts/test_program_methods/data_changer.bin b/artifacts/test_program_methods/data_changer.bin index 5a45951d..457e1fd1 100644 Binary files a/artifacts/test_program_methods/data_changer.bin and b/artifacts/test_program_methods/data_changer.bin differ diff --git a/artifacts/test_program_methods/extra_output.bin b/artifacts/test_program_methods/extra_output.bin index 5b8ef757..cccc75dd 100644 Binary files a/artifacts/test_program_methods/extra_output.bin and b/artifacts/test_program_methods/extra_output.bin differ diff --git a/artifacts/test_program_methods/malicious_authorization_changer.bin b/artifacts/test_program_methods/malicious_authorization_changer.bin index 5d553680..791c749f 100644 Binary files a/artifacts/test_program_methods/malicious_authorization_changer.bin and b/artifacts/test_program_methods/malicious_authorization_changer.bin differ diff --git a/artifacts/test_program_methods/minter.bin b/artifacts/test_program_methods/minter.bin index bff9c7d8..81a79926 100644 Binary files a/artifacts/test_program_methods/minter.bin and b/artifacts/test_program_methods/minter.bin differ diff --git a/artifacts/test_program_methods/missing_output.bin b/artifacts/test_program_methods/missing_output.bin index 210bb5a1..6c62c017 100644 Binary files a/artifacts/test_program_methods/missing_output.bin and b/artifacts/test_program_methods/missing_output.bin differ diff --git a/artifacts/test_program_methods/modified_transfer.bin b/artifacts/test_program_methods/modified_transfer.bin index d93e1ec9..801761d8 100644 Binary files a/artifacts/test_program_methods/modified_transfer.bin and b/artifacts/test_program_methods/modified_transfer.bin differ diff --git a/artifacts/test_program_methods/nonce_changer.bin b/artifacts/test_program_methods/nonce_changer.bin index 03a7d5f1..305a0d0e 100644 Binary files a/artifacts/test_program_methods/nonce_changer.bin and b/artifacts/test_program_methods/nonce_changer.bin differ diff --git a/artifacts/test_program_methods/noop.bin b/artifacts/test_program_methods/noop.bin index c53df415..667e575d 100644 Binary files a/artifacts/test_program_methods/noop.bin and b/artifacts/test_program_methods/noop.bin differ diff --git a/artifacts/test_program_methods/program_owner_changer.bin b/artifacts/test_program_methods/program_owner_changer.bin index d1f2617f..8c0c80b6 100644 Binary files a/artifacts/test_program_methods/program_owner_changer.bin and b/artifacts/test_program_methods/program_owner_changer.bin differ diff --git a/artifacts/test_program_methods/simple_balance_transfer.bin b/artifacts/test_program_methods/simple_balance_transfer.bin index 36d056ff..e0e1ffed 100644 Binary files a/artifacts/test_program_methods/simple_balance_transfer.bin and b/artifacts/test_program_methods/simple_balance_transfer.bin differ diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index f51486b8..142ad78d 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -13,10 +13,11 @@ wallet.workspace = true common.workspace = true key_protocol.workspace = true indexer_core.workspace = true -url.workspace = true wallet-ffi.workspace = true serde_json.workspace = true +token_core.workspace = true +url.workspace = true anyhow.workspace = true env_logger.workspace = true log.workspace = true diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 9a8b714a..2dd1d90d 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -8,6 +8,7 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::program::Program; +use token_core::{TokenDefinition, TokenHolding}; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -59,11 +60,13 @@ async fn create_and_transfer_public_token() -> Result<()> { }; // Create new token + let name = "A NAME".to_string(); + let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { definition_account_id: format_public_account_id(&definition_account_id.to_string()), supply_account_id: format_public_account_id(&supply_account_id.to_string()), - name: "A NAME".to_string(), - total_supply: 37, + name: name.clone(), + total_supply, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -76,16 +79,16 @@ async fn create_and_transfer_public_token() -> Result<()> { .get_account(definition_account_id.to_string()) .await? .account; + let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); - // The data of a token definition account has the following layout: - // [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32 bytes)] assert_eq!( - definition_acc.data.as_ref(), - &[ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] + token_definition, + TokenDefinition::Fungible { + name: name.clone(), + total_supply, + metadata_id: None + } ); // Check the status of the token holding account with the total supply @@ -97,24 +100,23 @@ async fn create_and_transfer_public_token() -> Result<()> { // The account must be owned by the token program assert_eq!(supply_acc.program_owner, Program::token().id()); - // The data of a token holding account has the following layout: - // [ 0x01 || corresponding_token_definition_id (32 bytes) || balance (little endian 16 bytes) ] - // First byte of the data equal to 1 means it's a token holding account - assert_eq!(supply_acc.data.as_ref()[0], 1); - // Bytes from 1 to 33 represent the id of the token this account is associated with + let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( - &supply_acc.data.as_ref()[1..33], - definition_account_id.to_bytes() + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply + } ); - assert_eq!(u128::from_le_bytes(supply_acc.data[33..].try_into()?), 37); // Transfer 7 tokens from supply_acc to recipient_account_id + let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { from: format_public_account_id(&supply_account_id.to_string()), to: Some(format_public_account_id(&recipient_account_id.to_string())), to_npk: None, to_ipk: None, - amount: 7, + amount: transfer_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -129,9 +131,14 @@ async fn create_and_transfer_public_token() -> Result<()> { .await? .account; assert_eq!(supply_acc.program_owner, Program::token().id()); - assert_eq!(supply_acc.data[0], 1); - assert_eq!(&supply_acc.data[1..33], definition_account_id.to_bytes()); - assert_eq!(u128::from_le_bytes(supply_acc.data[33..].try_into()?), 30); + let token_holding = TokenHolding::try_from(&supply_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply - transfer_amount + } + ); // Check the status of the recipient account after transfer let recipient_acc = ctx @@ -140,15 +147,21 @@ async fn create_and_transfer_public_token() -> Result<()> { .await? .account; assert_eq!(recipient_acc.program_owner, Program::token().id()); - assert_eq!(recipient_acc.data[0], 1); - assert_eq!(&recipient_acc.data[1..33], definition_account_id.to_bytes()); - assert_eq!(u128::from_le_bytes(recipient_acc.data[33..].try_into()?), 7); + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount + } + ); // Burn 3 tokens from recipient_acc + let burn_amount = 3; let subcommand = TokenProgramAgnosticSubcommand::Burn { definition: format_public_account_id(&definition_account_id.to_string()), holder: format_public_account_id(&recipient_account_id.to_string()), - amount: 3, + amount: burn_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -162,13 +175,15 @@ async fn create_and_transfer_public_token() -> Result<()> { .get_account(definition_account_id.to_string()) .await? .account; + let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( - definition_acc.data.as_ref(), - &[ - 0, 65, 32, 78, 65, 77, 69, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] + token_definition, + TokenDefinition::Fungible { + name: name.clone(), + total_supply: total_supply - burn_amount, + metadata_id: None + } ); // Check the status of the recipient account after burn @@ -177,16 +192,24 @@ async fn create_and_transfer_public_token() -> Result<()> { .get_account(recipient_account_id.to_string()) .await? .account; + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; - assert_eq!(u128::from_le_bytes(recipient_acc.data[33..].try_into()?), 4); + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount - burn_amount + } + ); // Mint 10 tokens at recipient_acc + let mint_amount = 10; let subcommand = TokenProgramAgnosticSubcommand::Mint { definition: format_public_account_id(&definition_account_id.to_string()), holder: Some(format_public_account_id(&recipient_account_id.to_string())), holder_npk: None, holder_ipk: None, - amount: 10, + amount: mint_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -200,13 +223,15 @@ async fn create_and_transfer_public_token() -> Result<()> { .get_account(definition_account_id.to_string()) .await? .account; + let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( - definition_acc.data.as_ref(), - &[ - 0, 65, 32, 78, 65, 77, 69, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] + token_definition, + TokenDefinition::Fungible { + name, + total_supply: total_supply - burn_amount + mint_amount, + metadata_id: None + } ); // Check the status of the recipient account after mint @@ -215,10 +240,14 @@ async fn create_and_transfer_public_token() -> Result<()> { .get_account(recipient_account_id.to_string()) .await? .account; + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( - u128::from_le_bytes(recipient_acc.data[33..].try_into()?), - 14 + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount - burn_amount + mint_amount + } ); info!("Successfully created and transferred public token"); @@ -270,11 +299,13 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { }; // Create new token + let name = "A NAME".to_string(); + let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { definition_account_id: format_public_account_id(&definition_account_id.to_string()), supply_account_id: format_private_account_id(&supply_account_id.to_string()), - name: "A NAME".to_string(), - total_supply: 37, + name: name.clone(), + total_supply, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -288,14 +319,16 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { .get_account(definition_account_id.to_string()) .await? .account; + let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); assert_eq!( - definition_acc.data.as_ref(), - &[ - 0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] + token_definition, + TokenDefinition::Fungible { + name: name.clone(), + total_supply, + metadata_id: None + } ); let new_commitment1 = ctx @@ -305,12 +338,13 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { assert!(verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client()).await); // Transfer 7 tokens from supply_acc to recipient_account_id + let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { from: format_private_account_id(&supply_account_id.to_string()), to: Some(format_private_account_id(&recipient_account_id.to_string())), to_npk: None, to_ipk: None, - amount: 7, + amount: transfer_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -331,10 +365,11 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await); // Burn 3 tokens from recipient_acc + let burn_amount = 3; let subcommand = TokenProgramAgnosticSubcommand::Burn { definition: format_public_account_id(&definition_account_id.to_string()), holder: format_private_account_id(&recipient_account_id.to_string()), - amount: 3, + amount: burn_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -348,13 +383,15 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { .get_account(definition_account_id.to_string()) .await? .account; + let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( - definition_acc.data.as_ref(), - &[ - 0, 65, 32, 78, 65, 77, 69, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] + token_definition, + TokenDefinition::Fungible { + name, + total_supply: total_supply - burn_amount, + metadata_id: None + } ); let new_commitment2 = ctx @@ -368,10 +405,14 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { .wallet() .get_account_private(&recipient_account_id) .context("Failed to get recipient account")?; + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( - u128::from_le_bytes(recipient_acc.data[33..].try_into()?), - 4 // 7 - 3 + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount - burn_amount + } ); info!("Successfully created and transferred token with private supply"); @@ -414,11 +455,13 @@ async fn create_token_with_private_definition() -> Result<()> { }; // Create token with private definition + let name = "A NAME".to_string(); + let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { definition_account_id: format_private_account_id(&definition_account_id.to_string()), supply_account_id: format_public_account_id(&supply_account_id.to_string()), - name: "A NAME".to_string(), - total_supply: 37, + name: name.clone(), + total_supply, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -441,8 +484,14 @@ async fn create_token_with_private_definition() -> Result<()> { .account; assert_eq!(supply_acc.program_owner, Program::token().id()); - assert_eq!(supply_acc.data.as_ref()[0], 1); - assert_eq!(u128::from_le_bytes(supply_acc.data[33..].try_into()?), 37); + let token_holding = TokenHolding::try_from(&supply_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply + } + ); // Create private recipient account let result = wallet::cli::execute_subcommand( @@ -471,6 +520,7 @@ async fn create_token_with_private_definition() -> Result<()> { }; // Mint to public account + let mint_amount_public = 10; let subcommand = TokenProgramAgnosticSubcommand::Mint { definition: format_private_account_id(&definition_account_id.to_string()), holder: Some(format_public_account_id( @@ -478,7 +528,7 @@ async fn create_token_with_private_definition() -> Result<()> { )), holder_npk: None, holder_ipk: None, - amount: 10, + amount: mint_amount_public, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -491,10 +541,15 @@ async fn create_token_with_private_definition() -> Result<()> { .wallet() .get_account_private(&definition_account_id) .context("Failed to get definition account")?; + let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( - u128::from_le_bytes(definition_acc.data[7..23].try_into()?), - 47 // 37 + 10 + token_definition, + TokenDefinition::Fungible { + name: name.clone(), + total_supply: total_supply + mint_amount_public, + metadata_id: None + } ); // Verify public recipient received tokens @@ -503,13 +558,18 @@ async fn create_token_with_private_definition() -> Result<()> { .get_account(recipient_account_id_public.to_string()) .await? .account; + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( - u128::from_le_bytes(recipient_acc.data[33..].try_into()?), - 10 + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: mint_amount_public + } ); // Mint to private account + let mint_amount_private = 5; let subcommand = TokenProgramAgnosticSubcommand::Mint { definition: format_private_account_id(&definition_account_id.to_string()), holder: Some(format_private_account_id( @@ -517,7 +577,7 @@ async fn create_token_with_private_definition() -> Result<()> { )), holder_npk: None, holder_ipk: None, - amount: 5, + amount: mint_amount_private, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -537,10 +597,14 @@ async fn create_token_with_private_definition() -> Result<()> { .wallet() .get_account_private(&recipient_account_id_private) .context("Failed to get private recipient account")?; + let token_holding = TokenHolding::try_from(&recipient_acc_private.data)?; assert_eq!( - u128::from_le_bytes(recipient_acc_private.data[33..].try_into()?), - 5 + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: mint_amount_private + } ); info!("Successfully created token with private definition and minted to both account types"); @@ -579,11 +643,13 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { }; // Create token with both private definition and supply + let name = "A NAME".to_string(); + let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { definition_account_id: format_private_account_id(&definition_account_id.to_string()), supply_account_id: format_private_account_id(&supply_account_id.to_string()), - name: "A NAME".to_string(), - total_supply: 37, + name, + total_supply, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -610,8 +676,15 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { .wallet() .get_account_private(&supply_account_id) .context("Failed to get supply account")?; + let token_holding = TokenHolding::try_from(&supply_acc.data)?; - assert_eq!(u128::from_le_bytes(supply_acc.data[33..].try_into()?), 37); + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply + } + ); // Create recipient account let result = wallet::cli::execute_subcommand( @@ -627,12 +700,13 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { }; // Transfer tokens + let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { from: format_private_account_id(&supply_account_id.to_string()), to: Some(format_private_account_id(&recipient_account_id.to_string())), to_npk: None, to_ipk: None, - amount: 7, + amount: transfer_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -658,13 +732,27 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { .wallet() .get_account_private(&supply_account_id) .context("Failed to get supply account")?; - assert_eq!(u128::from_le_bytes(supply_acc.data[33..].try_into()?), 30); + let token_holding = TokenHolding::try_from(&supply_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply - transfer_amount + } + ); let recipient_acc = ctx .wallet() .get_account_private(&recipient_account_id) .context("Failed to get recipient account")?; - assert_eq!(u128::from_le_bytes(recipient_acc.data[33..].try_into()?), 7); + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount + } + ); info!("Successfully created and transferred token with both private definition and supply"); @@ -715,11 +803,13 @@ async fn shielded_token_transfer() -> Result<()> { }; // Create token + let name = "A NAME".to_string(); + let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { definition_account_id: format_public_account_id(&definition_account_id.to_string()), supply_account_id: format_public_account_id(&supply_account_id.to_string()), - name: "A NAME".to_string(), - total_supply: 37, + name, + total_supply, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -728,12 +818,13 @@ async fn shielded_token_transfer() -> Result<()> { tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; // Perform shielded transfer: public supply -> private recipient + let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { from: format_public_account_id(&supply_account_id.to_string()), to: Some(format_private_account_id(&recipient_account_id.to_string())), to_npk: None, to_ipk: None, - amount: 7, + amount: transfer_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -747,7 +838,14 @@ async fn shielded_token_transfer() -> Result<()> { .get_account(supply_account_id.to_string()) .await? .account; - assert_eq!(u128::from_le_bytes(supply_acc.data[33..].try_into()?), 30); + let token_holding = TokenHolding::try_from(&supply_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply - transfer_amount + } + ); // Verify recipient commitment exists let new_commitment = ctx @@ -761,7 +859,14 @@ async fn shielded_token_transfer() -> Result<()> { .wallet() .get_account_private(&recipient_account_id) .context("Failed to get recipient account")?; - assert_eq!(u128::from_le_bytes(recipient_acc.data[33..].try_into()?), 7); + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount + } + ); info!("Successfully performed shielded token transfer"); @@ -812,11 +917,13 @@ async fn deshielded_token_transfer() -> Result<()> { }; // Create token with private supply + let name = "A NAME".to_string(); + let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { definition_account_id: format_public_account_id(&definition_account_id.to_string()), supply_account_id: format_private_account_id(&supply_account_id.to_string()), - name: "A NAME".to_string(), - total_supply: 37, + name, + total_supply, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -825,12 +932,13 @@ async fn deshielded_token_transfer() -> Result<()> { tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; // Perform deshielded transfer: private supply -> public recipient + let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { from: format_private_account_id(&supply_account_id.to_string()), to: Some(format_public_account_id(&recipient_account_id.to_string())), to_npk: None, to_ipk: None, - amount: 7, + amount: transfer_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -850,7 +958,14 @@ async fn deshielded_token_transfer() -> Result<()> { .wallet() .get_account_private(&supply_account_id) .context("Failed to get supply account")?; - assert_eq!(u128::from_le_bytes(supply_acc.data[33..].try_into()?), 30); + let token_holding = TokenHolding::try_from(&supply_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply - transfer_amount + } + ); // Verify recipient balance let recipient_acc = ctx @@ -858,7 +973,14 @@ async fn deshielded_token_transfer() -> Result<()> { .get_account(recipient_account_id.to_string()) .await? .account; - assert_eq!(u128::from_le_bytes(recipient_acc.data[33..].try_into()?), 7); + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount + } + ); info!("Successfully performed deshielded token transfer"); @@ -896,11 +1018,13 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { }; // Create token + let name = "A NAME".to_string(); + let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { definition_account_id: format_private_account_id(&definition_account_id.to_string()), supply_account_id: format_private_account_id(&supply_account_id.to_string()), - name: "A NAME".to_string(), - total_supply: 37, + name, + total_supply, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -931,12 +1055,13 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { .context("Failed to get private account keys")?; // Mint using claiming path (foreign account) + let mint_amount = 9; let subcommand = TokenProgramAgnosticSubcommand::Mint { definition: format_private_account_id(&definition_account_id.to_string()), holder: None, holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)), holder_ipk: Some(hex::encode(holder_keys.incoming_viewing_public_key.0)), - amount: 9, + amount: mint_amount, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -960,7 +1085,14 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { .wallet() .get_account_private(&recipient_account_id) .context("Failed to get recipient account")?; - assert_eq!(u128::from_le_bytes(recipient_acc.data[33..].try_into()?), 9); + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: mint_amount + } + ); info!("Successfully minted tokens using claiming path"); diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index 7c2d1ef4..e6952eee 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -24,7 +24,9 @@ risc0-build = "3.0.3" risc0-binfmt = "3.0.2" [dev-dependencies] +token_core.workspace = true test_program_methods.workspace = true + env_logger.workspace = true hex-literal = "1.0.0" test-case = "3.3.1" diff --git a/nssa/core/src/program.rs b/nssa/core/src/program.rs index 32b3e2c0..a6a04425 100644 --- a/nssa/core/src/program.rs +++ b/nssa/core/src/program.rs @@ -20,8 +20,7 @@ pub struct ProgramInput { /// Each program can derive up to `2^256` unique account IDs by choosing different /// seeds. PDAs allow programs to control namespaced account identifiers without /// collisions between programs. -#[derive(Serialize, Deserialize, Clone, Eq, PartialEq)] -#[cfg_attr(any(feature = "host", test), derive(Debug))] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct PdaSeed([u8; 32]); impl PdaSeed { @@ -65,23 +64,44 @@ impl From<(&ProgramId, &PdaSeed)> for AccountId { } } -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] -#[cfg_attr(any(feature = "host", test), derive(Debug,))] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct ChainedCall { /// The program ID of the program to execute pub program_id: ProgramId, + pub pre_states: Vec, /// The instruction data to pass pub instruction_data: InstructionData, - pub pre_states: Vec, pub pda_seeds: Vec, } +impl ChainedCall { + /// Creates a new chained call serializing the given instruction. + pub fn new( + program_id: ProgramId, + pre_states: Vec, + instruction: &I, + ) -> Self { + Self { + program_id, + pre_states, + instruction_data: risc0_zkvm::serde::to_vec(instruction) + .expect("Serialization to Vec should not fail"), + pda_seeds: Vec::new(), + } + } + + pub fn with_pda_seeds(mut self, pda_seeds: Vec) -> Self { + self.pda_seeds = pda_seeds; + self + } +} + /// Represents the final state of an `Account` after a program execution. /// A post state may optionally request that the executing program /// becomes the owner of the account (a “claim”). This is used to signal /// that the program intends to take ownership of the account. -#[derive(Serialize, Deserialize, Clone)] -#[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[cfg_attr(any(feature = "host", test), derive(PartialEq, Eq))] pub struct AccountPostState { account: Account, claim: bool, diff --git a/nssa/src/state.rs b/nssa/src/state.rs index d6bf8d60..08cc4e02 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -317,6 +317,7 @@ pub mod tests { encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar}, program::{PdaSeed, ProgramId}, }; + use token_core::{TokenDefinition, TokenHolding}; use crate::{ PublicKey, PublicTransaction, V02State, @@ -2328,53 +2329,6 @@ pub mod tests { )); } - // TODO: repeated code needs to be cleaned up - // from token.rs (also repeated in amm.rs) - const TOKEN_DEFINITION_DATA_SIZE: usize = 55; - - const TOKEN_HOLDING_DATA_SIZE: usize = 49; - - struct TokenDefinition { - account_type: u8, - name: [u8; 6], - total_supply: u128, - metadata_id: AccountId, - } - - struct TokenHolding { - account_type: u8, - definition_id: AccountId, - balance: u128, - } - impl TokenDefinition { - fn into_data(self) -> Data { - let mut bytes = Vec::::new(); - bytes.extend_from_slice(&[self.account_type]); - bytes.extend_from_slice(&self.name); - bytes.extend_from_slice(&self.total_supply.to_le_bytes()); - bytes.extend_from_slice(&self.metadata_id.to_bytes()); - - if bytes.len() != TOKEN_DEFINITION_DATA_SIZE { - panic!("Invalid Token Definition data"); - } - - Data::try_from(bytes).expect("Token definition data size must fit into data") - } - } - - impl TokenHolding { - fn into_data(self) -> Data { - let mut bytes = [0; TOKEN_HOLDING_DATA_SIZE]; - bytes[0] = self.account_type; - bytes[1..33].copy_from_slice(&self.definition_id.to_bytes()); - bytes[33..].copy_from_slice(&self.balance.to_le_bytes()); - bytes - .to_vec() - .try_into() - .expect("33 bytes should fit into Data") - } - } - // TODO repeated code should ultimately be removed; fn compute_pool_pda( amm_program_id: ProgramId, @@ -2747,8 +2701,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::user_token_a_holding_init(), }), @@ -2760,8 +2713,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::user_token_b_holding_init(), }), @@ -2793,11 +2745,10 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1u8; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), total_supply: BalanceForTests::token_a_supply(), - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, } @@ -2807,11 +2758,10 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1u8; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), total_supply: BalanceForTests::token_b_supply(), - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, } @@ -2821,11 +2771,10 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1u8; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("LP Token"), total_supply: BalanceForTests::token_lp_supply(), - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, } @@ -2835,8 +2784,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_balance_init(), }), @@ -2848,8 +2796,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_balance_init(), }), @@ -2861,8 +2808,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_lp_definition_id(), balance: BalanceForTests::user_token_lp_holding_init(), }), @@ -2874,8 +2820,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_balance_swap_1(), }), @@ -2887,8 +2832,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_balance_swap_1(), }), @@ -2920,8 +2864,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::user_token_a_holding_swap_1(), }), @@ -2933,8 +2876,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::user_token_b_holding_swap_1(), }), @@ -2946,8 +2888,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_balance_swap_2(), }), @@ -2959,8 +2900,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_balance_swap_2(), }), @@ -2992,8 +2932,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::user_token_a_holding_swap_2(), }), @@ -3005,8 +2944,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::user_token_b_holding_swap_2(), }), @@ -3018,8 +2956,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_balance_add(), }), @@ -3031,8 +2968,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_balance_add(), }), @@ -3064,8 +3000,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::user_token_a_holding_add(), }), @@ -3077,8 +3012,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::user_token_b_holding_add(), }), @@ -3090,8 +3024,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_lp_definition_id(), balance: BalanceForTests::user_token_lp_holding_add(), }), @@ -3103,11 +3036,10 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1u8; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("LP Token"), total_supply: BalanceForTests::token_lp_supply_add(), - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, } @@ -3117,8 +3049,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_balance_remove(), }), @@ -3130,8 +3061,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_balance_remove(), }), @@ -3163,8 +3093,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::user_token_a_holding_remove(), }), @@ -3176,8 +3105,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::user_token_b_holding_remove(), }), @@ -3189,8 +3117,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_lp_definition_id(), balance: BalanceForTests::user_token_lp_holding_remove(), }), @@ -3202,11 +3129,10 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1u8; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("LP Token"), total_supply: BalanceForTests::token_lp_supply_remove(), - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, } @@ -3216,11 +3142,10 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1u8; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("LP Token"), total_supply: 0, - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, } @@ -3230,8 +3155,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: 0, }), @@ -3243,8 +3167,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: 0, }), @@ -3276,8 +3199,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::user_token_a_holding_new_definition(), }), @@ -3289,8 +3211,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::user_token_b_holding_new_definition(), }), @@ -3302,8 +3223,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_lp_definition_id(), balance: BalanceForTests::user_token_a_holding_new_definition(), }), @@ -3315,11 +3235,10 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1u8; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("LP Token"), total_supply: BalanceForTests::vault_a_balance_init(), - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, } @@ -3349,8 +3268,7 @@ pub mod tests { Account { program_owner: Program::token().id(), balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_lp_definition_id(), balance: 0, }), @@ -4115,13 +4033,13 @@ pub mod tests { let pinata_token_holding_id = AccountId::from((&pinata_token.id(), &PdaSeed::new([0; 32]))); let winner_token_holding_id = AccountId::new([3; 32]); - let mut expected_winner_account_data = [0; 49]; - expected_winner_account_data[0] = 1; - expected_winner_account_data[1..33].copy_from_slice(pinata_token_definition_id.value()); - expected_winner_account_data[33..].copy_from_slice(&150u128.to_le_bytes()); + let expected_winner_account_holding = token_core::TokenHolding::Fungible { + definition_id: pinata_token_definition_id, + balance: 150, + }; let expected_winner_token_holding_post = Account { program_owner: token.id(), - data: expected_winner_account_data.to_vec().try_into().unwrap(), + data: Data::from(&expected_winner_account_holding), ..Account::default() }; @@ -4131,10 +4049,10 @@ pub mod tests { // Execution of the token program to create new token for the pinata token // definition and supply accounts let total_supply: u128 = 10_000_000; - // instruction: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] - let mut instruction = vec![0; 23]; - instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); - instruction[17..].copy_from_slice(b"PINATA"); + let instruction = token_core::Instruction::NewFungibleDefinition { + name: String::from("PINATA"), + total_supply, + }; let message = public_transaction::Message::try_new( token.id(), vec![pinata_token_definition_id, pinata_token_holding_id], @@ -4146,9 +4064,8 @@ pub mod tests { let tx = PublicTransaction::new(message, witness_set); state.transition_from_public_transaction(&tx).unwrap(); - // Execution of the token program transfer just to initialize the winner token account - let mut instruction = vec![0; 23]; - instruction[0] = 2; + // Execution of winner's token holding account initialization + let instruction = token_core::Instruction::InitializeAccount; let message = public_transaction::Message::try_new( token.id(), vec![pinata_token_definition_id, winner_token_holding_id], diff --git a/program_methods/guest/Cargo.toml b/program_methods/guest/Cargo.toml index 1b8d85f8..eda23348 100644 --- a/program_methods/guest/Cargo.toml +++ b/program_methods/guest/Cargo.toml @@ -6,6 +6,7 @@ license = { workspace = true } [dependencies] nssa_core.workspace = true - +token_core.workspace = true +token_program.workspace = true risc0-zkvm.workspace = true serde = { workspace = true, default-features = false } diff --git a/program_methods/guest/src/bin/amm.rs b/program_methods/guest/src/bin/amm.rs index 9488db13..2c7a7f8f 100644 --- a/program_methods/guest/src/bin/amm.rs +++ b/program_methods/guest/src/bin/amm.rs @@ -152,56 +152,6 @@ impl PoolDefinition { } } -// TODO: remove repeated code for Token_Definition and TokenHoldling - -const TOKEN_HOLDING_TYPE: u8 = 1; -const TOKEN_HOLDING_DATA_SIZE: usize = 49; - -struct TokenHolding { - #[cfg_attr(not(test), expect(dead_code, reason = "TODO: fix later"))] - account_type: u8, - definition_id: AccountId, - balance: u128, -} - -impl TokenHolding { - fn parse(data: &[u8]) -> Option { - if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE { - None - } else { - let account_type = data[0]; - let definition_id = AccountId::new( - data[1..33] - .try_into() - .expect("Defintion ID must be 32 bytes long"), - ); - let balance = u128::from_le_bytes( - data[33..] - .try_into() - .expect("balance must be 16 bytes little-endian"), - ); - Some(Self { - definition_id, - balance, - account_type, - }) - } - } - - #[cfg(test)] - fn into_data(self) -> Data { - let mut bytes = [0; TOKEN_HOLDING_DATA_SIZE]; - bytes[0] = self.account_type; - bytes[1..33].copy_from_slice(&self.definition_id.to_bytes()); - bytes[33..].copy_from_slice(&self.balance.to_le_bytes()); - - bytes - .to_vec() - .try_into() - .expect("49 bytes should fit into Data") - } -} - type Instruction = Vec; fn main() { let ( @@ -412,32 +362,6 @@ fn compute_liquidity_token_pda_seed(pool_id: AccountId) -> PdaSeed { ) } -const TOKEN_PROGRAM_NEW: u8 = 0; -const TOKEN_PROGRAM_TRANSFER: u8 = 1; -const TOKEN_PROGRAM_MINT: u8 = 4; -const TOKEN_PROGRAM_BURN: u8 = 3; - -fn initialize_token_transfer_chained_call( - token_program_command: u8, - sender: AccountWithMetadata, - recipient: AccountWithMetadata, - amount_to_move: u128, - pda_seed: Vec, -) -> ChainedCall { - let mut instruction_data = vec![0u8; 23]; - instruction_data[0] = token_program_command; - instruction_data[1..17].copy_from_slice(&amount_to_move.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("AMM Program expects valid token transfer instruction data"); - - ChainedCall { - program_id: sender.account.program_owner, - instruction_data, - pre_states: vec![sender, recipient], - pda_seeds: pda_seed, - } -} - fn new_definition( pre_states: &[AccountWithMetadata], balance_in: &[u128], @@ -471,12 +395,12 @@ fn new_definition( } // Verify token_a and token_b are different - let definition_token_a_id = TokenHolding::parse(&user_holding_a.account.data) + let definition_token_a_id = token_core::TokenHolding::try_from(&user_holding_a.account.data) .expect("New definition: AMM Program expects valid Token Holding account for Token A") - .definition_id; - let definition_token_b_id = TokenHolding::parse(&user_holding_b.account.data) + .definition_id(); + let definition_token_b_id = token_core::TokenHolding::try_from(&user_holding_b.account.data) .expect("New definition: AMM Program expects valid Token Holding account for Token B") - .definition_id; + .definition_id(); // both instances of the same token program let token_program = user_holding_a.account.program_owner; @@ -543,57 +467,48 @@ fn new_definition( AccountPostState::new(pool_post.clone()) }; - let mut chained_calls = Vec::::new(); + let token_program_id = user_holding_a.account.program_owner; // Chain call for Token A (user_holding_a -> Vault_A) - let call_token_a = initialize_token_transfer_chained_call( - TOKEN_PROGRAM_TRANSFER, - user_holding_a.clone(), - vault_a.clone(), - amount_a, - Vec::::new(), + let call_token_a = ChainedCall::new( + token_program_id, + vec![user_holding_a.clone(), vault_a.clone()], + &token_core::Instruction::Transfer { + amount_to_transfer: amount_a, + }, ); // Chain call for Token B (user_holding_b -> Vault_B) - let call_token_b = initialize_token_transfer_chained_call( - TOKEN_PROGRAM_TRANSFER, - user_holding_b.clone(), - vault_b.clone(), - amount_b, - Vec::::new(), + let call_token_b = ChainedCall::new( + token_program_id, + vec![user_holding_b.clone(), vault_b.clone()], + &token_core::Instruction::Transfer { + amount_to_transfer: amount_b, + }, ); // Chain call for liquidity token (TokenLP definition -> User LP Holding) - let mut instruction_data = vec![0u8; 23]; - instruction_data[0] = if pool.account == Account::default() { - TOKEN_PROGRAM_NEW + let instruction = if pool.account == Account::default() { + token_core::Instruction::NewFungibleDefinition { + name: String::from("LP Token"), + total_supply: amount_a, + } } else { - TOKEN_PROGRAM_MINT - }; //new or mint - let nme = if pool.account == Account::default() { - [1u8; 6] - } else { - [0u8; 6] + token_core::Instruction::Mint { + amount_to_mint: amount_a, + } }; - instruction_data[1..17].copy_from_slice(&amount_a.to_le_bytes()); - instruction_data[17..].copy_from_slice(&nme); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("New definition: AMM Program expects valid instruction_data"); - let mut pool_lp_auth = pool_lp.clone(); pool_lp_auth.is_authorized = true; - let token_program_id = user_holding_a.account.program_owner; - let call_token_lp = ChainedCall { - program_id: token_program_id, - instruction_data, - pre_states: vec![pool_lp_auth.clone(), user_holding_lp.clone()], - pda_seeds: vec![compute_liquidity_token_pda_seed(pool.account_id)], - }; + let call_token_lp = ChainedCall::new( + token_program_id, + vec![pool_lp_auth.clone(), user_holding_lp.clone()], + &instruction, + ) + .with_pda_seeds(vec![compute_liquidity_token_pda_seed(pool.account_id)]); - chained_calls.push(call_token_lp); - chained_calls.push(call_token_b); - chained_calls.push(call_token_a); + let chained_calls = vec![call_token_lp, call_token_b, call_token_a]; let post_states = vec![ pool_post.clone(), @@ -645,18 +560,30 @@ fn swap( // fetch pool reserves // validates reserves is at least the vaults' balances - if TokenHolding::parse(&vault_a.account.data) - .expect("Swap: AMM Program expects a valid Token Holding Account for Vault A") - .balance - < pool_def_data.reserve_a - { + let vault_a_token_holding = token_core::TokenHolding::try_from(&vault_a.account.data) + .expect("Swap: AMM Program expects a valid Token Holding Account for Vault A"); + let token_core::TokenHolding::Fungible { + definition_id: _, + balance: vault_a_balance, + } = vault_a_token_holding + else { + panic!("Swap: AMM Program expects a valid Fungible Token Holding Account for Vault A"); + }; + if vault_a_balance < pool_def_data.reserve_a { panic!("Reserve for Token A exceeds vault balance"); } - if TokenHolding::parse(&vault_b.account.data) - .expect("Swap: AMM Program expects a valid Token Holding Account for Vault B") - .balance - < pool_def_data.reserve_b - { + + let vault_b_token_holding = token_core::TokenHolding::try_from(&vault_b.account.data) + .expect("Swap: AMM Program expects a valid Token Holding Account for Vault B"); + let token_core::TokenHolding::Fungible { + definition_id: _, + balance: vault_b_balance, + } = vault_b_token_holding + else { + panic!("Swap: AMM Program expects a valid Fungible Token Holding Account for Vault B"); + }; + + if vault_b_balance < pool_def_data.reserve_b { panic!("Reserve for Token B exceeds vault balance"); } @@ -741,30 +668,37 @@ fn swap_logic( panic!("Withdraw amount should be nonzero"); } + let token_program_id = user_deposit.account.program_owner; + let mut chained_calls = Vec::new(); - chained_calls.push(initialize_token_transfer_chained_call( - TOKEN_PROGRAM_TRANSFER, - user_deposit.clone(), - vault_deposit.clone(), - deposit_amount, - Vec::::new(), + chained_calls.push(ChainedCall::new( + token_program_id, + vec![user_deposit, vault_deposit], + &token_core::Instruction::Transfer { + amount_to_transfer: deposit_amount, + }, )); let mut vault_withdraw = vault_withdraw.clone(); vault_withdraw.is_authorized = true; - chained_calls.push(initialize_token_transfer_chained_call( - TOKEN_PROGRAM_TRANSFER, - vault_withdraw.clone(), - user_withdraw.clone(), - withdraw_amount, - vec![compute_vault_pda_seed( - pool_id, - TokenHolding::parse(&vault_withdraw.account.data) - .expect("Swap Logic: AMM Program expects valid token data") - .definition_id, - )], - )); + let pda_seed = compute_vault_pda_seed( + pool_id, + token_core::TokenHolding::try_from(&vault_withdraw.account.data) + .expect("Swap Logic: AMM Program expects valid token data") + .definition_id(), + ); + + chained_calls.push( + ChainedCall::new( + token_program_id, + vec![vault_withdraw, user_withdraw], + &token_core::Instruction::Transfer { + amount_to_transfer: withdraw_amount, + }, + ) + .with_pda_seeds(vec![pda_seed]), + ); (chained_calls, deposit_amount, withdraw_amount) } @@ -816,12 +750,29 @@ fn add_liquidity( } // 2. Determine deposit amount - let vault_b_balance = TokenHolding::parse(&vault_b.account.data) - .expect("Add liquidity: AMM Program expects valid Token Holding Account for Vault B") - .balance; - let vault_a_balance = TokenHolding::parse(&vault_a.account.data) - .expect("Add liquidity: AMM Program expects valid Token Holding Account for Vault A") - .balance; + let vault_b_token_holding = token_core::TokenHolding::try_from(&vault_b.account.data) + .expect("Add liquidity: AMM Program expects valid Token Holding Account for Vault B"); + let token_core::TokenHolding::Fungible { + definition_id: _, + balance: vault_b_balance, + } = vault_b_token_holding + else { + panic!( + "Add liquidity: AMM Program expects valid Fungible Token Holding Account for Vault B" + ); + }; + + let vault_a_token_holding = token_core::TokenHolding::try_from(&vault_a.account.data) + .expect("Add liquidity: AMM Program expects valid Token Holding Account for Vault A"); + let token_core::TokenHolding::Fungible { + definition_id: _, + balance: vault_a_balance, + } = vault_a_token_holding + else { + panic!( + "Add liquidity: AMM Program expects valid Fungible Token Holding Account for Vault A" + ); + }; if pool_def_data.reserve_a == 0 || pool_def_data.reserve_b == 0 { panic!("Reserves must be nonzero"); @@ -879,38 +830,37 @@ fn add_liquidity( }; pool_post.data = pool_post_definition.into_data(); - let mut chained_call = Vec::new(); + let token_program_id = user_holding_a.account.program_owner; // Chain call for Token A (UserHoldingA -> Vault_A) - let call_token_a = initialize_token_transfer_chained_call( - TOKEN_PROGRAM_TRANSFER, - user_holding_a.clone(), - vault_a.clone(), - actual_amount_a, - Vec::::new(), + let call_token_a = ChainedCall::new( + token_program_id, + vec![user_holding_a.clone(), vault_a.clone()], + &token_core::Instruction::Transfer { + amount_to_transfer: actual_amount_a, + }, ); // Chain call for Token B (UserHoldingB -> Vault_B) - let call_token_b = initialize_token_transfer_chained_call( - TOKEN_PROGRAM_TRANSFER, - user_holding_b.clone(), - vault_b.clone(), - actual_amount_b, - Vec::::new(), + let call_token_b = ChainedCall::new( + token_program_id, + vec![user_holding_b.clone(), vault_b.clone()], + &token_core::Instruction::Transfer { + amount_to_transfer: actual_amount_b, + }, ); // Chain call for LP (mint new tokens for user_holding_lp) let mut pool_definition_lp_auth = pool_definition_lp.clone(); pool_definition_lp_auth.is_authorized = true; - let call_token_lp = initialize_token_transfer_chained_call( - TOKEN_PROGRAM_MINT, - pool_definition_lp_auth.clone(), - user_holding_lp.clone(), - delta_lp, - vec![compute_liquidity_token_pda_seed(pool.account_id)], - ); + let call_token_lp = ChainedCall::new( + token_program_id, + vec![pool_definition_lp_auth.clone(), user_holding_lp.clone()], + &token_core::Instruction::Mint { + amount_to_mint: delta_lp, + }, + ) + .with_pda_seeds(vec![compute_liquidity_token_pda_seed(pool.account_id)]); - chained_call.push(call_token_lp); - chained_call.push(call_token_b); - chained_call.push(call_token_a); + let chained_calls = vec![call_token_lp, call_token_b, call_token_a]; let post_states = vec![ AccountPostState::new(pool_post), @@ -922,7 +872,7 @@ fn add_liquidity( AccountPostState::new(pre_states[6].account.clone()), ]; - (post_states, chained_call) + (post_states, chained_calls) } fn remove_liquidity( @@ -986,11 +936,20 @@ fn remove_liquidity( } // 2. Compute withdrawal amounts - let user_holding_lp_data = TokenHolding::parse(&user_holding_lp.account.data) + let user_holding_lp_data = token_core::TokenHolding::try_from(&user_holding_lp.account.data) .expect("Remove liquidity: AMM Program expects a valid Token Account for liquidity token"); + let token_core::TokenHolding::Fungible { + definition_id: _, + balance: user_lp_balance, + } = user_holding_lp_data + else { + panic!( + "Remove liquidity: AMM Program expects a valid Fungible Token Holding Account for liquidity token" + ); + }; - if user_holding_lp_data.balance > pool_def_data.liquidity_pool_supply - || user_holding_lp_data.definition_id != pool_def_data.liquidity_pool_id + if user_lp_balance > pool_def_data.liquidity_pool_supply + || user_holding_lp_data.definition_id() != pool_def_data.liquidity_pool_id { panic!("Invalid liquidity account provided"); } @@ -1026,44 +985,45 @@ fn remove_liquidity( pool_post.data = pool_post_definition.into_data(); - let mut chained_calls = Vec::new(); + let token_program_id = user_holding_a.account.program_owner; // Chaincall for Token A withdraw - let call_token_a = initialize_token_transfer_chained_call( - TOKEN_PROGRAM_TRANSFER, - running_vault_a, - user_holding_a.clone(), - withdraw_amount_a, - vec![compute_vault_pda_seed( - pool.account_id, - pool_def_data.definition_token_a_id, - )], - ); + let call_token_a = ChainedCall::new( + token_program_id, + vec![running_vault_a, user_holding_a.clone()], + &token_core::Instruction::Transfer { + amount_to_transfer: withdraw_amount_a, + }, + ) + .with_pda_seeds(vec![compute_vault_pda_seed( + pool.account_id, + pool_def_data.definition_token_a_id, + )]); // Chaincall for Token B withdraw - let call_token_b = initialize_token_transfer_chained_call( - TOKEN_PROGRAM_TRANSFER, - running_vault_b, - user_holding_b.clone(), - withdraw_amount_b, - vec![compute_vault_pda_seed( - pool.account_id, - pool_def_data.definition_token_b_id, - )], - ); + let call_token_b = ChainedCall::new( + token_program_id, + vec![running_vault_b, user_holding_b.clone()], + &token_core::Instruction::Transfer { + amount_to_transfer: withdraw_amount_b, + }, + ) + .with_pda_seeds(vec![compute_vault_pda_seed( + pool.account_id, + pool_def_data.definition_token_b_id, + )]); // Chaincall for LP adjustment let mut pool_definition_lp_auth = pool_definition_lp.clone(); pool_definition_lp_auth.is_authorized = true; - let call_token_lp = initialize_token_transfer_chained_call( - TOKEN_PROGRAM_BURN, - pool_definition_lp_auth.clone(), - user_holding_lp.clone(), - delta_lp, - vec![compute_liquidity_token_pda_seed(pool.account_id)], - ); + let call_token_lp = ChainedCall::new( + token_program_id, + vec![pool_definition_lp_auth, user_holding_lp.clone()], + &token_core::Instruction::Burn { + amount_to_burn: delta_lp, + }, + ) + .with_pda_seeds(vec![compute_liquidity_token_pda_seed(pool.account_id)]); - chained_calls.push(call_token_lp); - chained_calls.push(call_token_b); - chained_calls.push(call_token_a); + let chained_calls = vec![call_token_lp, call_token_b, call_token_a]; let post_states = vec![ AccountPostState::new(pool_post.clone()), @@ -1082,41 +1042,18 @@ fn remove_liquidity( mod tests { use nssa_core::{ account::{Account, AccountId, AccountWithMetadata, Data}, - program::{ChainedCall, PdaSeed, ProgramId}, + program::{ChainedCall, ProgramId}, }; + use token_core::{TokenDefinition, TokenHolding}; use crate::{ - PoolDefinition, TokenHolding, add_liquidity, compute_liquidity_token_pda, + PoolDefinition, add_liquidity, compute_liquidity_token_pda, compute_liquidity_token_pda_seed, compute_pool_pda, compute_vault_pda, compute_vault_pda_seed, new_definition, remove_liquidity, swap, }; const TOKEN_PROGRAM_ID: ProgramId = [15; 8]; const AMM_PROGRAM_ID: ProgramId = [42; 8]; - const TOKEN_DEFINITION_DATA_SIZE: usize = 55; - - struct TokenDefinition { - account_type: u8, - name: [u8; 6], - total_supply: u128, - metadata_id: AccountId, - } - - impl TokenDefinition { - fn into_data(self) -> Data { - let mut bytes = Vec::::new(); - bytes.extend_from_slice(&[self.account_type]); - bytes.extend_from_slice(&self.name); - bytes.extend_from_slice(&self.total_supply.to_le_bytes()); - bytes.extend_from_slice(&self.metadata_id.to_bytes()); - - if bytes.len() != TOKEN_DEFINITION_DATA_SIZE { - panic!("Invalid Token Definition data"); - } - - Data::try_from(bytes).expect("Token definition data size must fit into data") - } - } struct BalanceForTests; @@ -1250,21 +1187,16 @@ mod tests { impl ChainedCallForTests { fn cc_swap_token_a_test_1() -> ChainedCall { - let mut instruction_data = vec![0; 23]; - instruction_data[0] = 1; - instruction_data[1..17] - .copy_from_slice(&BalanceForTests::add_max_amount_a().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![ AccountForTests::user_holding_a(), AccountForTests::vault_a_init(), ], - pda_seeds: Vec::::new(), - } + &token_core::Instruction::Transfer { + amount_to_transfer: BalanceForTests::add_max_amount_a(), + }, + ) } fn cc_swap_token_b_test_1() -> ChainedCall { @@ -1273,20 +1205,17 @@ mod tests { let mut vault_b_auth = AccountForTests::vault_b_init(); vault_b_auth.is_authorized = true; - let mut instruction = vec![0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice(&swap_amount.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![vault_b_auth, AccountForTests::user_holding_b()], - pda_seeds: vec![compute_vault_pda_seed( - IdForTests::pool_definition_id(), - IdForTests::token_b_definition_id(), - )], - } + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![vault_b_auth, AccountForTests::user_holding_b()], + &token_core::Instruction::Transfer { + amount_to_transfer: swap_amount, + }, + ) + .with_pda_seeds(vec![compute_vault_pda_seed( + IdForTests::pool_definition_id(), + IdForTests::token_b_definition_id(), + )]) } fn cc_swap_token_a_test_2() -> ChainedCall { @@ -1295,214 +1224,164 @@ mod tests { let mut vault_a_auth = AccountForTests::vault_a_init(); vault_a_auth.is_authorized = true; - let mut instruction_data = vec![0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&swap_amount.to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![vault_a_auth, AccountForTests::user_holding_a()], - pda_seeds: vec![compute_vault_pda_seed( - IdForTests::pool_definition_id(), - IdForTests::token_a_definition_id(), - )], - } + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![vault_a_auth, AccountForTests::user_holding_a()], + &token_core::Instruction::Transfer { + amount_to_transfer: swap_amount, + }, + ) + .with_pda_seeds(vec![compute_vault_pda_seed( + IdForTests::pool_definition_id(), + IdForTests::token_a_definition_id(), + )]) } fn cc_swap_token_b_test_2() -> ChainedCall { - let mut instruction = vec![0; 23]; - instruction[0] = 1; - instruction[1..17].copy_from_slice(&BalanceForTests::add_max_amount_b().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![ AccountForTests::user_holding_b(), AccountForTests::vault_b_init(), ], - pda_seeds: Vec::::new(), - } + &token_core::Instruction::Transfer { + amount_to_transfer: BalanceForTests::add_max_amount_b(), + }, + ) } fn cc_add_token_a() -> ChainedCall { - let mut instruction = vec![0u8; 23]; - instruction[0] = 1; - instruction[1..17] - .copy_from_slice(&BalanceForTests::add_successful_amount_a().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![ AccountForTests::user_holding_a(), AccountForTests::vault_a_init(), ], - pda_seeds: Vec::::new(), - } + &token_core::Instruction::Transfer { + amount_to_transfer: BalanceForTests::add_successful_amount_a(), + }, + ) } fn cc_add_token_b() -> ChainedCall { - let mut instruction = vec![0u8; 23]; - instruction[0] = 1; - instruction[1..17] - .copy_from_slice(&BalanceForTests::add_successful_amount_b().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![ AccountForTests::user_holding_b(), AccountForTests::vault_b_init(), ], - pda_seeds: Vec::::new(), - } + &token_core::Instruction::Transfer { + amount_to_transfer: BalanceForTests::add_successful_amount_b(), + }, + ) } fn cc_add_pool_lp() -> ChainedCall { let mut pool_lp_auth = AccountForTests::pool_lp_init(); pool_lp_auth.is_authorized = true; - let mut instruction = vec![0u8; 23]; - instruction[0] = 4; - instruction[1..17] - .copy_from_slice(&BalanceForTests::add_successful_amount_a().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![pool_lp_auth, AccountForTests::user_holding_lp_init()], - pda_seeds: vec![compute_liquidity_token_pda_seed( - IdForTests::pool_definition_id(), - )], - } + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![pool_lp_auth, AccountForTests::user_holding_lp_init()], + &token_core::Instruction::Mint { + amount_to_mint: BalanceForTests::add_successful_amount_a(), + }, + ) + .with_pda_seeds(vec![compute_liquidity_token_pda_seed( + IdForTests::pool_definition_id(), + )]) } fn cc_remove_token_a() -> ChainedCall { let mut vault_a_auth = AccountForTests::vault_a_init(); vault_a_auth.is_authorized = true; - let mut instruction = vec![0; 23]; - instruction[0] = 1; - instruction[1..17] - .copy_from_slice(&BalanceForTests::remove_actual_a_successful().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![vault_a_auth, AccountForTests::user_holding_a()], - pda_seeds: vec![compute_vault_pda_seed( - IdForTests::pool_definition_id(), - IdForTests::token_a_definition_id(), - )], - } + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![vault_a_auth, AccountForTests::user_holding_a()], + &token_core::Instruction::Transfer { + amount_to_transfer: BalanceForTests::remove_actual_a_successful(), + }, + ) + .with_pda_seeds(vec![compute_vault_pda_seed( + IdForTests::pool_definition_id(), + IdForTests::token_a_definition_id(), + )]) } fn cc_remove_token_b() -> ChainedCall { let mut vault_b_auth = AccountForTests::vault_b_init(); vault_b_auth.is_authorized = true; - let mut instruction = vec![0; 23]; - instruction[0] = 1; - instruction[1..17] - .copy_from_slice(&BalanceForTests::remove_min_amount_b_low().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![vault_b_auth, AccountForTests::user_holding_b()], - pda_seeds: vec![compute_vault_pda_seed( - IdForTests::pool_definition_id(), - IdForTests::token_b_definition_id(), - )], - } + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![vault_b_auth, AccountForTests::user_holding_b()], + &token_core::Instruction::Transfer { + amount_to_transfer: BalanceForTests::remove_min_amount_b_low(), + }, + ) + .with_pda_seeds(vec![compute_vault_pda_seed( + IdForTests::pool_definition_id(), + IdForTests::token_b_definition_id(), + )]) } fn cc_remove_pool_lp() -> ChainedCall { let mut pool_lp_auth = AccountForTests::pool_lp_init(); pool_lp_auth.is_authorized = true; - let mut instruction = vec![0; 23]; - instruction[0] = 3; - instruction[1..17] - .copy_from_slice(&BalanceForTests::remove_actual_a_successful().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ - AccountForTests::pool_lp_init(), - AccountForTests::user_holding_lp_init(), - ], - pda_seeds: vec![compute_liquidity_token_pda_seed( - IdForTests::pool_definition_id(), - )], - } + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![pool_lp_auth, AccountForTests::user_holding_lp_init()], + &token_core::Instruction::Burn { + amount_to_burn: BalanceForTests::remove_amount_lp(), + }, + ) + .with_pda_seeds(vec![compute_liquidity_token_pda_seed( + IdForTests::pool_definition_id(), + )]) } fn cc_new_definition_token_a() -> ChainedCall { - let mut instruction = vec![0; 23]; - instruction[0] = 1; - instruction[1..17] - .copy_from_slice(&BalanceForTests::add_successful_amount_a().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![ AccountForTests::user_holding_a(), AccountForTests::vault_a_init(), ], - pda_seeds: Vec::::new(), - } + &token_core::Instruction::Transfer { + amount_to_transfer: BalanceForTests::add_successful_amount_a(), + }, + ) } fn cc_new_definition_token_b() -> ChainedCall { - let mut instruction = vec![0; 23]; - instruction[0] = 1; - instruction[1..17] - .copy_from_slice(&BalanceForTests::add_successful_amount_b().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("Swap Logic: AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![ AccountForTests::user_holding_b(), AccountForTests::vault_b_init(), ], - pda_seeds: Vec::::new(), - } + &token_core::Instruction::Transfer { + amount_to_transfer: BalanceForTests::add_successful_amount_b(), + }, + ) } fn cc_new_definition_token_lp() -> ChainedCall { - let mut instruction = vec![0; 23]; - instruction[0] = 1; - instruction[1..17] - .copy_from_slice(&BalanceForTests::add_successful_amount_a().to_le_bytes()); - let instruction_data = risc0_zkvm::serde::to_vec(&instruction) - .expect("AMM Program expects valid transaction instruction data"); - ChainedCall { - program_id: TOKEN_PROGRAM_ID, - instruction_data, - pre_states: vec![ + ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![ AccountForTests::pool_lp_init(), AccountForTests::user_holding_lp_uninit(), ], - pda_seeds: vec![compute_liquidity_token_pda_seed( - IdForTests::pool_definition_id(), - )], - } + &token_core::Instruction::Mint { + amount_to_mint: BalanceForTests::add_successful_amount_a(), + }, + ) + .with_pda_seeds(vec![compute_liquidity_token_pda_seed( + IdForTests::pool_definition_id(), + )]) } } @@ -1566,8 +1445,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::user_token_a_balance(), }), @@ -1583,8 +1461,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::user_token_b_balance(), }), @@ -1600,8 +1477,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_reserve_init(), }), @@ -1617,8 +1493,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_reserve_init(), }), @@ -1634,8 +1509,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_reserve_high(), }), @@ -1651,8 +1525,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_reserve_high(), }), @@ -1668,8 +1541,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_reserve_low(), }), @@ -1685,8 +1557,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_reserve_low(), }), @@ -1702,8 +1573,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: 0, }), @@ -1719,8 +1589,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: 0, }), @@ -1736,11 +1605,10 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), total_supply: BalanceForTests::vault_a_reserve_init(), - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, }, @@ -1754,11 +1622,10 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: 0u8, - name: [1; 6], + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), total_supply: BalanceForTests::vault_a_reserve_init(), - metadata_id: AccountId::new([0; 32]), + metadata_id: None, }), nonce: 0, }, @@ -1772,8 +1639,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_lp_definition_id(), balance: 0, }), @@ -1789,8 +1655,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_lp_definition_id(), balance: BalanceForTests::user_token_lp_balance(), }), @@ -2102,8 +1967,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_reserve_init(), }), @@ -2119,8 +1983,7 @@ mod tests { account: Account { program_owner: TOKEN_PROGRAM_ID, balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: 1u8, + data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_reserve_init(), }), @@ -3552,8 +3415,14 @@ mod tests { let chained_call_a = chained_calls[0].clone(); let chained_call_b = chained_calls[1].clone(); - assert!(chained_call_a == ChainedCallForTests::cc_swap_token_a_test_1()); - assert!(chained_call_b == ChainedCallForTests::cc_swap_token_b_test_1()); + assert_eq!( + chained_call_a, + ChainedCallForTests::cc_swap_token_a_test_1() + ); + assert_eq!( + chained_call_b, + ChainedCallForTests::cc_swap_token_b_test_1() + ); } #[test] @@ -3581,7 +3450,13 @@ mod tests { let chained_call_a = chained_calls[1].clone(); let chained_call_b = chained_calls[0].clone(); - assert!(chained_call_a == ChainedCallForTests::cc_swap_token_a_test_2()); - assert!(chained_call_b == ChainedCallForTests::cc_swap_token_b_test_2()); + assert_eq!( + chained_call_a, + ChainedCallForTests::cc_swap_token_a_test_2() + ); + assert_eq!( + chained_call_b, + ChainedCallForTests::cc_swap_token_b_test_2() + ); } } diff --git a/program_methods/guest/src/bin/pinata_token.rs b/program_methods/guest/src/bin/pinata_token.rs index 04613791..188597cb 100644 --- a/program_methods/guest/src/bin/pinata_token.rs +++ b/program_methods/guest/src/bin/pinata_token.rs @@ -5,10 +5,7 @@ use nssa_core::{ write_nssa_outputs_with_chained_call, }, }; -use risc0_zkvm::{ - serde::to_vec, - sha::{Impl, Sha256}, -}; +use risc0_zkvm::sha::{Impl, Sha256}; const PRIZE: u128 = 150; @@ -82,23 +79,21 @@ fn main() { let winner_token_holding_post = winner_token_holding.account.clone(); pinata_definition_post.data = data.next_data(); - let mut instruction_data = vec![0; 23]; - instruction_data[0] = 1; - instruction_data[1..17].copy_from_slice(&PRIZE.to_le_bytes()); - // Flip authorization to true for chained call let mut pinata_token_holding_for_chain_call = pinata_token_holding.clone(); pinata_token_holding_for_chain_call.is_authorized = true; - let chained_calls = vec![ChainedCall { - program_id: pinata_token_holding_post.program_owner, - instruction_data: to_vec(&instruction_data).unwrap(), - pre_states: vec![ + let chained_call = ChainedCall::new( + pinata_token_holding_post.program_owner, + vec![ pinata_token_holding_for_chain_call, winner_token_holding.clone(), ], - pda_seeds: vec![PdaSeed::new([0; 32])], - }]; + &token_core::Instruction::Transfer { + amount_to_transfer: PRIZE, + }, + ) + .with_pda_seeds(vec![PdaSeed::new([0; 32])]); write_nssa_outputs_with_chained_call( instruction_words, @@ -112,6 +107,6 @@ fn main() { AccountPostState::new(pinata_token_holding_post), AccountPostState::new(winner_token_holding_post), ], - chained_calls, + vec![chained_call], ); } diff --git a/program_methods/guest/src/bin/token.rs b/program_methods/guest/src/bin/token.rs index 0f7b6287..0bc3d245 100644 --- a/program_methods/guest/src/bin/token.rs +++ b/program_methods/guest/src/bin/token.rs @@ -1,700 +1,13 @@ -use nssa_core::{ - account::{Account, AccountId, AccountWithMetadata, Data}, - program::{ - AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, read_nssa_inputs, write_nssa_outputs, - }, -}; - -// The token program has three functions: -// 1. New token definition. Arguments to this function are: -// * Two **default** accounts: [definition_account, holding_account]. The first default account -// will be initialized with the token definition account values. The second account will be -// initialized to a token holding account for the new token, holding the entire total supply. -// * An instruction data of 23-bytes, indicating the total supply and the token name, with the -// following layout: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] The -// name cannot be equal to [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] -// 2. Token transfer Arguments to this function are: -// * Two accounts: [sender_account, recipient_account]. -// * An instruction data byte string of length 23, indicating the total supply with the -// following layout [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 -// || 0x00 || 0x00]. -// 3. Initialize account with zero balance Arguments to this function are: -// * Two accounts: [definition_account, account_to_initialize]. -// * An dummy byte string of length 23, with the following layout [0x02 || 0x00 || 0x00 || 0x00 -// || ... || 0x00 || 0x00]. -// 4. Burn tokens from a Token Holding account (thus lowering total supply) Arguments to this -// function are: -// * Two accounts: [definition_account, holding_account]. -// * Authorization required: holding_account -// * An instruction data byte string of length 23, indicating the balance to burn with the -// folloiwng layout -// [0x03 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. -// 5. Mint additional supply of tokens tokens to a Token Holding account (thus increasing total -// supply) Arguments to this function are: -// * Two accounts: [definition_account, holding_account]. -// * Authorization required: definition_account -// * An instruction data byte string of length 23, indicating the balance to mint with the -// folloiwng layout -// [0x04 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. -// 6. New token definition with metadata. Arguments to this function are: -// * Three **default** accounts: [definition_account, metadata_account. holding_account]. The -// first default account will be initialized with the token definition account values. The -// second account will be initialized to a token metadata account for the new token -// definition. The third account will be initialized to a token holding account for the new -// token, holding the entire total supply. -// * An instruction data of 474-bytes, indicating the token name, total supply, token standard, -// metadata standard and metadata_values (uri and creators). the following layout: [0x05 || -// total_supply (little-endian 16 bytes) || name (6 bytes) || token_standard || -// metadata_standard || metadata_values] The name cannot be equal to [0x00, 0x00, 0x00, 0x00, -// 0x00, 0x00] -// 7. Print NFT copy from Master NFT Arguments to this function are: -// * Two accounts: [master_nft, printed_account (default)]. -// * Authorization required: master_nft -// * An dummy byte string of length 23, with the following layout [0x06 || 0x00 || 0x00 || 0x00 -// || ... || 0x00 || 0x00]. -const TOKEN_STANDARD_FUNGIBLE_TOKEN: u8 = 0; -const TOKEN_STANDARD_FUNGIBLE_ASSET: u8 = 1; -const TOKEN_STANDARD_NONFUNGIBLE: u8 = 2; -const TOKEN_STANDARD_NONFUNGIBLE_PRINTABLE: u8 = 3; - -const METADATA_TYPE_SIMPLE: u8 = 0; -const METADATA_TYPE_EXPANDED: u8 = 1; - -const TOKEN_DEFINITION_DATA_SIZE: usize = 55; - -const TOKEN_HOLDING_STANDARD: u8 = 1; -const TOKEN_HOLDING_NFT_MASTER: u8 = 2; -const TOKEN_HOLDING_NFT_PRINTED_COPY: u8 = 3; - -const TOKEN_HOLDING_DATA_SIZE: usize = 49; -const CURRENT_VERSION: u8 = 1; - -const TOKEN_METADATA_DATA_SIZE: usize = 463; - -fn is_token_standard_valid(standard: u8) -> bool { - matches!( - standard, - TOKEN_STANDARD_FUNGIBLE_TOKEN - | TOKEN_STANDARD_FUNGIBLE_ASSET - | TOKEN_STANDARD_NONFUNGIBLE - | TOKEN_STANDARD_NONFUNGIBLE_PRINTABLE - ) -} - -fn is_metadata_type_valid(standard: u8) -> bool { - matches!(standard, METADATA_TYPE_SIMPLE | METADATA_TYPE_EXPANDED) -} - -fn is_token_holding_type_valid(standard: u8) -> bool { - matches!(standard, |TOKEN_HOLDING_STANDARD| TOKEN_HOLDING_NFT_MASTER - | TOKEN_HOLDING_NFT_PRINTED_COPY) -} - -struct TokenDefinition { - account_type: u8, - name: [u8; 6], - total_supply: u128, - metadata_id: AccountId, -} - -impl TokenDefinition { - fn into_data(self) -> Data { - let mut bytes = Vec::::new(); - bytes.extend_from_slice(&[self.account_type]); - bytes.extend_from_slice(&self.name); - bytes.extend_from_slice(&self.total_supply.to_le_bytes()); - bytes.extend_from_slice(&self.metadata_id.to_bytes()); - - if bytes.len() != TOKEN_DEFINITION_DATA_SIZE { - panic!("Invalid Token Definition data"); - } - - Data::try_from(bytes).expect("Token definition data size must fit into data") - } - - fn parse(data: &Data) -> Option { - let data = Vec::::from(data.clone()); - - if data.len() != TOKEN_DEFINITION_DATA_SIZE { - None - } else { - let account_type = data[0]; - let name = data[1..7].try_into().expect("Name must be a 6 bytes"); - let total_supply = u128::from_le_bytes( - data[7..23] - .try_into() - .expect("Total supply must be 16 bytes little-endian"), - ); - let metadata_id = AccountId::new( - data[23..TOKEN_DEFINITION_DATA_SIZE] - .try_into() - .expect("Token Program expects valid Account Id for Metadata"), - ); - - let this = Some(Self { - account_type, - name, - total_supply, - metadata_id, - }); - - match account_type { - TOKEN_STANDARD_NONFUNGIBLE if total_supply != 1 => None, - TOKEN_STANDARD_FUNGIBLE_TOKEN if metadata_id != AccountId::new([0; 32]) => None, - _ => this, - } - } - } -} - -struct TokenHolding { - account_type: u8, - definition_id: AccountId, - balance: u128, -} - -impl TokenHolding { - fn new(definition_id: &AccountId) -> Self { - Self { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: *definition_id, - balance: 0, - } - } - - fn parse(data: &Data) -> Option { - let data = Vec::::from(data.clone()); - - if data.len() != TOKEN_HOLDING_DATA_SIZE { - return None; - } - - // Check account_type - if !is_token_holding_type_valid(data[0]) { - return None; - } - - let account_type = data[0]; - let definition_id = AccountId::new( - data[1..33] - .try_into() - .expect("Defintion ID must be 32 bytes long"), - ); - let balance = u128::from_le_bytes( - data[33..] - .try_into() - .expect("balance must be 16 bytes little-endian"), - ); - - Some(Self { - definition_id, - balance, - account_type, - }) - } - - fn into_data(self) -> Data { - if !is_token_holding_type_valid(self.account_type) { - panic!("Invalid Token Holding type"); - } - - let mut bytes = Vec::::new(); - bytes.extend_from_slice(&[self.account_type]); - bytes.extend_from_slice(&self.definition_id.to_bytes()); - bytes.extend_from_slice(&self.balance.to_le_bytes()); - - if bytes.len() != TOKEN_HOLDING_DATA_SIZE { - panic!("Invalid Token Holding data"); - } - - Data::try_from(bytes).expect("Invalid data") - } -} - -struct TokenMetadata { - account_type: u8, - version: u8, - definition_id: AccountId, - uri: [u8; 200], - creators: [u8; 250], - /// Block id - primary_sale_date: u64, -} - -impl TokenMetadata { - fn into_data(self) -> Data { - if !is_metadata_type_valid(self.account_type) { - panic!("Invalid Metadata type"); - } - - let mut bytes = Vec::::new(); - bytes.extend_from_slice(&[self.account_type]); - bytes.extend_from_slice(&[self.version]); - bytes.extend_from_slice(&self.definition_id.to_bytes()); - bytes.extend_from_slice(&self.uri); - bytes.extend_from_slice(&self.creators); - bytes.extend_from_slice(&self.primary_sale_date.to_le_bytes()); - - if bytes.len() != TOKEN_METADATA_DATA_SIZE { - panic!("Invalid Token Definition data length"); - } - - Data::try_from(bytes).expect("Invalid data") - } -} - -fn transfer(pre_states: &[AccountWithMetadata], balance_to_move: u128) -> Vec { - if pre_states.len() != 2 { - panic!("Invalid number of input accounts"); - } - let sender = &pre_states[0]; - let recipient = &pre_states[1]; - - if !sender.is_authorized { - panic!("Sender authorization is missing"); - } - - let sender_holding = TokenHolding::parse(&sender.account.data).expect("Invalid sender data"); - - let recipient_holding = if recipient.account == Account::default() { - TokenHolding::new(&sender_holding.definition_id) - } else { - TokenHolding::parse(&recipient.account.data).expect("Invalid recipient data") - }; - - if sender_holding.definition_id != recipient_holding.definition_id { - panic!("Sender and recipient definition id mismatch"); - } - - let (sender_holding, recipient_holding) = - if sender_holding.account_type != TOKEN_HOLDING_NFT_MASTER { - standard_transfer(sender_holding, recipient_holding, balance_to_move) - } else { - nft_master_transfer(sender_holding, recipient_holding, balance_to_move) - }; - - let sender_post = { - let mut this = sender.account.clone(); - this.data = sender_holding.into_data(); - AccountPostState::new(this) - }; - - let recipient_post = { - let mut this = recipient.account.clone(); - this.data = recipient_holding.into_data(); - - // Claim the recipient account if it has default program owner - if this.program_owner == DEFAULT_PROGRAM_ID { - AccountPostState::new_claimed(this) - } else { - AccountPostState::new(this) - } - }; - - vec![sender_post, recipient_post] -} - -fn standard_transfer( - sender_holding: TokenHolding, - recipient_holding: TokenHolding, - balance_to_move: u128, -) -> (TokenHolding, TokenHolding) { - let mut sender_holding = sender_holding; - let mut recipient_holding = recipient_holding; - - if sender_holding.balance < balance_to_move { - panic!("Insufficient balance"); - } - - sender_holding.balance = sender_holding - .balance - .checked_sub(balance_to_move) - .expect("Checked above"); - recipient_holding.balance = recipient_holding - .balance - .checked_add(balance_to_move) - .expect("Recipient balance overflow"); - - recipient_holding.account_type = sender_holding.account_type; - - (sender_holding, recipient_holding) -} - -fn nft_master_transfer( - sender_holding: TokenHolding, - recipient_holding: TokenHolding, - balance_to_move: u128, -) -> (TokenHolding, TokenHolding) { - let mut sender_holding = sender_holding; - let mut recipient_holding = recipient_holding; - - if recipient_holding.balance != 0 { - panic!("Invalid balance in recipient account for NFT transfer"); - } - - if sender_holding.balance != balance_to_move { - panic!("Invalid balance for NFT Master transfer"); - } - - sender_holding.balance = 0; - recipient_holding.balance = balance_to_move; - recipient_holding.account_type = sender_holding.account_type; - - (sender_holding, recipient_holding) -} - -fn new_definition( - pre_states: &[AccountWithMetadata], - name: [u8; 6], - total_supply: u128, -) -> Vec { - if pre_states.len() != 2 { - panic!("Invalid number of input accounts"); - } - - let definition_target_account = &pre_states[0]; - let holding_target_account = &pre_states[1]; - - if definition_target_account.account != Account::default() { - panic!("Definition target account must have default values"); - } - - if holding_target_account.account != Account::default() { - panic!("Holding target account must have default values"); - } - - let token_definition = TokenDefinition { - account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, - name, - total_supply, - metadata_id: AccountId::new([0; 32]), - }; - - let token_holding = TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: definition_target_account.account_id, - balance: total_supply, - }; - - let mut definition_target_account_post = definition_target_account.account.clone(); - definition_target_account_post.data = token_definition.into_data(); - - let mut holding_target_account_post = holding_target_account.account.clone(); - holding_target_account_post.data = token_holding.into_data(); - - vec![ - AccountPostState::new_claimed(definition_target_account_post), - AccountPostState::new_claimed(holding_target_account_post), - ] -} - -fn new_definition_with_metadata( - pre_states: &[AccountWithMetadata], - name: [u8; 6], - total_supply: u128, - token_standard: u8, - metadata_standard: u8, - metadata_values: &Data, -) -> Vec { - if pre_states.len() != 3 { - panic!("Invalid number of input accounts"); - } - - let definition_target_account = &pre_states[0]; - let metadata_target_account = &pre_states[1]; - let holding_target_account = &pre_states[2]; - - if definition_target_account.account != Account::default() { - panic!("Definition target account must have default values"); - } - - if metadata_target_account.account != Account::default() { - panic!("Metadata target account must have default values"); - } - - if holding_target_account.account != Account::default() { - panic!("Holding target account must have default values"); - } - - if !is_token_standard_valid(token_standard) { - panic!("Invalid Token Standard provided"); - } - - if !is_metadata_type_valid(metadata_standard) { - panic!("Invalid Metadata Standadard provided"); - } - - if !valid_total_supply_for_token_standard(total_supply, token_standard) { - panic!("Invalid total supply for the specified token supply"); - } - - let token_definition = TokenDefinition { - account_type: token_standard, - name, - total_supply, - metadata_id: metadata_target_account.account_id, - }; - - let token_holding = TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: definition_target_account.account_id, - balance: total_supply, - }; - - if metadata_values.len() != 450 { - panic!("Metadata values data should be 450 bytes"); - } - - let uri: [u8; 200] = metadata_values[0..200] - .try_into() - .expect("Token program expects valid uri for Metadata"); - let creators: [u8; 250] = metadata_values[200..450] - .try_into() - .expect("Token program expects valid creators for Metadata"); - - let token_metadata = TokenMetadata { - account_type: metadata_standard, - version: CURRENT_VERSION, - definition_id: definition_target_account.account_id, - uri, - creators, - primary_sale_date: 0u64, // TODO #261: future works to implement this - }; - - let mut definition_target_account_post = definition_target_account.account.clone(); - definition_target_account_post.data = token_definition.into_data(); - - let mut holding_target_account_post = holding_target_account.account.clone(); - holding_target_account_post.data = token_holding.into_data(); - - let mut metadata_target_account_post = metadata_target_account.account.clone(); - metadata_target_account_post.data = token_metadata.into_data(); - - vec![ - AccountPostState::new_claimed(definition_target_account_post), - AccountPostState::new_claimed(holding_target_account_post), - AccountPostState::new_claimed(metadata_target_account_post), - ] -} - -fn valid_total_supply_for_token_standard(total_supply: u128, token_standard: u8) -> bool { - token_standard != TOKEN_STANDARD_NONFUNGIBLE || total_supply == 1 -} - -fn initialize_account(pre_states: &[AccountWithMetadata]) -> Vec { - if pre_states.len() != 2 { - panic!("Invalid number of accounts"); - } - - let definition = &pre_states[0]; - let account_to_initialize = &pre_states[1]; - - if account_to_initialize.account != Account::default() { - panic!("Only Uninitialized accounts can be initialized"); - } - - // TODO: #212 We should check that this is an account owned by the token program. - // This check can't be done here since the ID of the program is known only after compiling it - // - // Check definition account is valid - let _definition_values = - TokenDefinition::parse(&definition.account.data).expect("Definition account must be valid"); - let holding_values = TokenHolding::new(&definition.account_id); - - let definition_post = definition.account.clone(); - let mut account_to_initialize = account_to_initialize.account.clone(); - account_to_initialize.data = holding_values.into_data(); - - vec![ - AccountPostState::new(definition_post), - AccountPostState::new_claimed(account_to_initialize), - ] -} - -fn burn(pre_states: &[AccountWithMetadata], balance_to_burn: u128) -> Vec { - if pre_states.len() != 2 { - panic!("Invalid number of accounts"); - } - - let definition = &pre_states[0]; - let user_holding = &pre_states[1]; - - if !user_holding.is_authorized { - panic!("Authorization is missing"); - } - - let definition_values = TokenDefinition::parse(&definition.account.data) - .expect("Token Definition account must be valid"); - let user_values = TokenHolding::parse(&user_holding.account.data) - .expect("Token Holding account must be valid"); - - if definition.account_id != user_values.definition_id { - panic!("Mismatch Token Definition and Token Holding"); - } - - if user_values.balance < balance_to_burn { - panic!("Insufficient balance to burn"); - } - - let mut post_user_holding = user_holding.account.clone(); - let mut post_definition = definition.account.clone(); - - post_user_holding.data = TokenHolding::into_data(TokenHolding { - account_type: user_values.account_type, - definition_id: user_values.definition_id, - balance: user_values - .balance - .checked_sub(balance_to_burn) - .expect("Checked above"), - }); - - post_definition.data = TokenDefinition::into_data(TokenDefinition { - account_type: definition_values.account_type, - name: definition_values.name, - total_supply: definition_values - .total_supply - .checked_sub(balance_to_burn) - .expect("Total supply underflow"), - metadata_id: definition_values.metadata_id, - }); - - vec![ - AccountPostState::new(post_definition), - AccountPostState::new(post_user_holding), - ] -} - -fn is_mintable(account_type: u8) -> bool { - account_type != TOKEN_STANDARD_NONFUNGIBLE -} - -fn mint_additional_supply( - pre_states: &[AccountWithMetadata], - amount_to_mint: u128, -) -> Vec { - if pre_states.len() != 2 { - panic!("Invalid number of accounts"); - } - - let definition = &pre_states[0]; - let token_holding = &pre_states[1]; - - if !definition.is_authorized { - panic!("Definition authorization is missing"); - } - - let definition_values = - TokenDefinition::parse(&definition.account.data).expect("Definition account must be valid"); - - let token_holding_values: TokenHolding = if token_holding.account == Account::default() { - TokenHolding::new(&definition.account_id) - } else { - TokenHolding::parse(&token_holding.account.data).expect("Holding account must be valid") - }; - - if !is_mintable(definition_values.account_type) { - panic!("Token Definition's standard does not permit minting additional supply"); - } - - if definition.account_id != token_holding_values.definition_id { - panic!("Mismatch Token Definition and Token Holding"); - } - - let token_holding_post_data = TokenHolding { - account_type: token_holding_values.account_type, - definition_id: token_holding_values.definition_id, - balance: token_holding_values - .balance - .checked_add(amount_to_mint) - .expect("New balance overflow"), - }; - - let post_total_supply = definition_values - .total_supply - .checked_add(amount_to_mint) - .expect("Total supply overflow"); - - let post_definition_data = TokenDefinition { - account_type: definition_values.account_type, - name: definition_values.name, - total_supply: post_total_supply, - metadata_id: definition_values.metadata_id, - }; - - let post_definition = { - let mut this = definition.account.clone(); - this.data = post_definition_data.into_data(); - AccountPostState::new(this) - }; - - let token_holding_post = { - let mut this = token_holding.account.clone(); - this.data = token_holding_post_data.into_data(); - - // Claim the recipient account if it has default program owner - if this.program_owner == DEFAULT_PROGRAM_ID { - AccountPostState::new_claimed(this) - } else { - AccountPostState::new(this) - } - }; - vec![post_definition, token_holding_post] -} - -fn print_nft(pre_states: &[AccountWithMetadata]) -> Vec { - if pre_states.len() != 2 { - panic!("Invalid number of accounts"); - } - - let master_account = &pre_states[0]; - let printed_account = &pre_states[1]; - - if !master_account.is_authorized { - panic!("Master NFT Account must be authorized"); - } - - if printed_account.account != Account::default() { - panic!("Printed Account must be uninitialized"); - } - - let mut master_account_data = - TokenHolding::parse(&master_account.account.data).expect("Invalid Token Holding data"); - - if master_account_data.account_type != TOKEN_HOLDING_NFT_MASTER { - panic!("Invalid Token Holding provided as NFT Master Account"); - } - - if master_account_data.balance < 2 { - panic!("Insufficient balance to print another NFT copy"); - } - - let definition_id = master_account_data.definition_id; - - let post_master_account = { - let mut this = master_account.account.clone(); - master_account_data.balance -= 1; - this.data = master_account_data.into_data(); - AccountPostState::new(this) - }; - - let post_printed_account = { - let mut this = printed_account.account.clone(); - - let printed_data = TokenHolding { - account_type: TOKEN_HOLDING_NFT_PRINTED_COPY, - definition_id, - balance: 1, - }; - - this.data = TokenHolding::into_data(printed_data); - - AccountPostState::new_claimed(this) - }; - - vec![post_master_account, post_printed_account] -} - -type Instruction = Vec; +//! The Token Program. +//! +//! This program implements a simple token system supporting both fungible and non-fungible tokens +//! (NFTs). +//! +//! Token program accepts [`Instruction`] as input, refer to the corresponding documentation +//! for more details. + +use nssa_core::program::{ProgramInput, read_nssa_inputs, write_nssa_outputs}; +use token_program::core::Instruction; fn main() { let ( @@ -705,1622 +18,68 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let post_states = match instruction[0] { - 0 => { - // Parse instruction - let total_supply = u128::from_le_bytes( - instruction[1..17] - .try_into() - .expect("Total supply must be 16 bytes little-endian"), - ); - let name: [u8; 6] = instruction[17..] + let pre_states_clone = pre_states.clone(); + + let post_states = match instruction { + Instruction::Transfer { + amount_to_transfer: balance_to_move, + } => { + let [sender, recipient] = pre_states .try_into() - .expect("Name must be 6 bytes long"); - assert_ne!(name, [0; 6]); - - // Execute - new_definition(&pre_states, name, total_supply) + .expect("Transfer instruction requires exactly two accounts"); + token_program::transfer::transfer(sender, recipient, balance_to_move) } - 1 => { - // Parse instruction - let balance_to_move = u128::from_le_bytes( - instruction[1..17] - .try_into() - .expect("Balance to move must be 16 bytes little-endian"), - ); - let name: [u8; 6] = instruction[17..] + Instruction::NewFungibleDefinition { name, total_supply } => { + let [definition_account, holding_account] = pre_states .try_into() - .expect("Name must be 6 bytes long"); - assert_eq!(name, [0; 6]); - - // Execute - transfer(&pre_states, balance_to_move) - } - 2 => { - // Initialize account - if instruction[1..] != [0; 22] { - panic!("Invalid instruction for initialize account"); - } - initialize_account(&pre_states) - } - 3 => { - let balance_to_burn = u128::from_le_bytes( - instruction[1..17] - .try_into() - .expect("Balance to burn must be 16 bytes little-endian"), - ); - let name: [u8; 6] = instruction[17..] - .try_into() - .expect("Name must be 6 bytes long"); - assert_eq!(name, [0; 6]); - - // Execute - burn(&pre_states, balance_to_burn) - } - 4 => { - let balance_to_mint = u128::from_le_bytes( - instruction[1..17] - .try_into() - .expect("Balance to burn must be 16 bytes little-endian"), - ); - let name: [u8; 6] = instruction[17..] - .try_into() - .expect("Name must be 6 bytes long"); - assert_eq!(name, [0; 6]); - - // Execute - mint_additional_supply(&pre_states, balance_to_mint) - } - 5 => { - if instruction.len() != 474 { - panic!("Invalid instruction length") - } - - // Parse instruction - let total_supply = u128::from_le_bytes( - instruction[1..17] - .try_into() - .expect("Total supply must be 16 bytes little-endian"), - ); - let name = instruction[17..23] - .try_into() - .expect("Name must be 6 bytes long"); - assert_ne!(name, [0; 6]); - let token_standard = instruction[23]; - let metadata_standard = instruction[24]; - let metadata_values: Data = - Data::try_from(instruction[25..474].to_vec()).expect("Invalid metadata"); - - // Execute - new_definition_with_metadata( - &pre_states, + .expect("NewFungibleDefinition instruction requires exactly two accounts"); + token_program::new_definition::new_fungible_definition( + definition_account, + holding_account, name, total_supply, - token_standard, - metadata_standard, - &metadata_values, ) } - 6 => { - if instruction.len() != 23 { - panic!("Invalid instruction length"); - } - - // Initialize account - if instruction[1..] != [0; 22] { - panic!("Invalid instruction for initialize account"); - } - - print_nft(&pre_states) + Instruction::NewDefinitionWithMetadata { + new_definition, + metadata, + } => { + let [definition_account, holding_account, metadata_account] = pre_states + .try_into() + .expect("NewDefinitionWithMetadata instruction requires exactly three accounts"); + token_program::new_definition::new_definition_with_metadata( + definition_account, + holding_account, + metadata_account, + new_definition, + *metadata, + ) + } + Instruction::InitializeAccount => { + let [definition_account, account_to_initialize] = pre_states + .try_into() + .expect("InitializeAccount instruction requires exactly two accounts"); + token_program::initialize::initialize_account(definition_account, account_to_initialize) + } + Instruction::Burn { amount_to_burn } => { + let [definition_account, user_holding_account] = pre_states + .try_into() + .expect("Burn instruction requires exactly two accounts"); + token_program::burn::burn(definition_account, user_holding_account, amount_to_burn) + } + Instruction::Mint { amount_to_mint } => { + let [definition_account, user_holding_account] = pre_states + .try_into() + .expect("Mint instruction requires exactly two accounts"); + token_program::mint::mint(definition_account, user_holding_account, amount_to_mint) + } + Instruction::PrintNft => { + let [master_account, printed_account] = pre_states + .try_into() + .expect("PrintNft instruction requires exactly two accounts"); + token_program::print_nft::print_nft(master_account, printed_account) } - _ => panic!("Invalid instruction"), }; - write_nssa_outputs(instruction_words, pre_states, post_states); -} - -#[cfg(test)] -mod tests { - use nssa_core::account::{Account, AccountId, AccountWithMetadata, Data}; - - use crate::{ - TOKEN_DEFINITION_DATA_SIZE, TOKEN_HOLDING_DATA_SIZE, TOKEN_HOLDING_NFT_MASTER, - TOKEN_HOLDING_NFT_PRINTED_COPY, TOKEN_HOLDING_STANDARD, TOKEN_STANDARD_FUNGIBLE_TOKEN, - TOKEN_STANDARD_NONFUNGIBLE, TokenDefinition, TokenHolding, burn, mint_additional_supply, - new_definition, new_definition_with_metadata, print_nft, transfer, - }; - - struct BalanceForTests; - struct IdForTests; - - struct AccountForTests; - - impl AccountForTests { - fn definition_account_auth() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, - name: [2; 6], - total_supply: BalanceForTests::init_supply(), - metadata_id: AccountId::new([0; 32]), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::pool_definition_id(), - } - } - - fn definition_account_without_auth() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, - name: [2; 6], - total_supply: BalanceForTests::init_supply(), - metadata_id: AccountId::new([0; 32]), - }), - nonce: 0, - }, - is_authorized: false, - account_id: IdForTests::pool_definition_id(), - } - } - - fn holding_different_definition() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id_diff(), - balance: BalanceForTests::holding_balance(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - - fn holding_same_definition_with_authorization() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::holding_balance(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - - fn holding_same_definition_without_authorization() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::holding_balance(), - }), - nonce: 0, - }, - is_authorized: false, - account_id: IdForTests::holding_id(), - } - } - - fn holding_same_definition_without_authorization_overflow() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::init_supply(), - }), - nonce: 0, - }, - is_authorized: false, - account_id: IdForTests::holding_id(), - } - } - - fn definition_account_post_burn() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, - name: [2; 6], - total_supply: BalanceForTests::init_supply_burned(), - metadata_id: AccountId::new([0; 32]), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::pool_definition_id(), - } - } - - fn holding_account_post_burn() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::holding_balance_burned(), - }), - nonce: 0, - }, - is_authorized: false, - account_id: IdForTests::holding_id(), - } - } - - fn holding_account_uninit() -> AccountWithMetadata { - AccountWithMetadata { - account: Account::default(), - is_authorized: false, - account_id: IdForTests::holding_id_2(), - } - } - - fn init_mint() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [0u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::mint_success(), - }), - nonce: 0, - }, - is_authorized: false, - account_id: IdForTests::holding_id(), - } - } - - fn holding_account_same_definition_mint() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::holding_balance_mint(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::pool_definition_id(), - } - } - - fn definition_account_mint() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, - name: [2; 6], - total_supply: BalanceForTests::init_supply_mint(), - metadata_id: AccountId::new([0; 32]), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::pool_definition_id(), - } - } - - fn holding_same_definition_with_authorization_and_large_balance() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::mint_overflow(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::pool_definition_id(), - } - } - - fn definition_account_with_authorization_nonfungible() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_STANDARD_NONFUNGIBLE, - name: [2; 6], - total_supply: 1, - metadata_id: AccountId::new([0; 32]), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::pool_definition_id(), - } - } - - fn definition_account_uninit() -> AccountWithMetadata { - AccountWithMetadata { - account: Account::default(), - is_authorized: false, - account_id: IdForTests::pool_definition_id(), - } - } - - fn holding_account_init() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::init_supply(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - - fn definition_account_unclaimed() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [0u32; 8], - balance: 0u128, - data: TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_STANDARD_FUNGIBLE_TOKEN, - name: [2; 6], - total_supply: BalanceForTests::init_supply(), - metadata_id: AccountId::new([0; 32]), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::pool_definition_id(), - } - } - - fn holding_account_unclaimed() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [0u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::init_supply(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - - fn holding_account2_init() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::init_supply(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id_2(), - } - } - - fn holding_account2_init_post_transfer() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::recipient_post_transfer(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id_2(), - } - } - - fn holding_account_init_post_transfer() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_STANDARD, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::sender_post_transfer(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - - fn holding_account_master_nft() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_NFT_MASTER, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::printable_copies(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - - fn holding_account_master_nft_insufficient_balance() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_NFT_MASTER, - definition_id: IdForTests::pool_definition_id(), - balance: 1, - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - - fn holding_account_master_nft_after_print() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_NFT_MASTER, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::printable_copies() - 1, - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - - fn holding_account_printed_nft() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [0u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_NFT_PRINTED_COPY, - definition_id: IdForTests::pool_definition_id(), - balance: 1, - }), - nonce: 0, - }, - is_authorized: false, - account_id: IdForTests::holding_id(), - } - } - - fn holding_account_with_master_nft_transferred_to() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [0u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_NFT_MASTER, - definition_id: IdForTests::pool_definition_id(), - balance: BalanceForTests::printable_copies(), - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id_2(), - } - } - - fn holding_account_master_nft_post_transfer() -> AccountWithMetadata { - AccountWithMetadata { - account: Account { - program_owner: [5u32; 8], - balance: 0u128, - data: TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_NFT_MASTER, - definition_id: IdForTests::pool_definition_id(), - balance: 0, - }), - nonce: 0, - }, - is_authorized: true, - account_id: IdForTests::holding_id(), - } - } - } - - impl BalanceForTests { - fn init_supply() -> u128 { - 100_000 - } - - fn holding_balance() -> u128 { - 1_000 - } - - fn init_supply_burned() -> u128 { - 99_500 - } - - fn holding_balance_burned() -> u128 { - 500 - } - - fn burn_success() -> u128 { - 500 - } - - fn burn_insufficient() -> u128 { - 1_500 - } - - fn mint_success() -> u128 { - 50_000 - } - - fn holding_balance_mint() -> u128 { - 51_000 - } - - fn mint_overflow() -> u128 { - u128::MAX - 40_000 - } - - fn init_supply_mint() -> u128 { - 150_000 - } - - fn sender_post_transfer() -> u128 { - 95_000 - } - - fn recipient_post_transfer() -> u128 { - 105_000 - } - - fn transfer_amount() -> u128 { - 5_000 - } - - fn printable_copies() -> u128 { - 10 - } - } - - impl IdForTests { - fn pool_definition_id() -> AccountId { - AccountId::new([15; 32]) - } - - fn pool_definition_id_diff() -> AccountId { - AccountId::new([16; 32]) - } - - fn holding_id() -> AccountId { - AccountId::new([17; 32]) - } - - fn holding_id_2() -> AccountId { - AccountId::new([42; 32]) - } - } - - #[should_panic(expected = "Invalid number of input accounts")] - #[test] - fn test_call_new_definition_with_invalid_number_of_accounts_1() { - let pre_states = vec![AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }]; - let _post_states = new_definition(&pre_states, [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe], 10); - } - - #[should_panic(expected = "Invalid number of input accounts")] - #[test] - fn test_call_new_definition_with_invalid_number_of_accounts_2() { - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = new_definition(&pre_states, [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe], 10); - } - - #[should_panic(expected = "Definition target account must have default values")] - #[test] - fn test_new_definition_non_default_first_account_should_fail() { - let pre_states = vec![ - AccountWithMetadata { - account: Account { - program_owner: [1, 2, 3, 4, 5, 6, 7, 8], - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - ]; - let _post_states = new_definition(&pre_states, [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe], 10); - } - - #[should_panic(expected = "Holding target account must have default values")] - #[test] - fn test_new_definition_non_default_second_account_should_fail() { - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account { - program_owner: [1, 2, 3, 4, 5, 6, 7, 8], - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - ]; - let _post_states = new_definition(&pre_states, [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe], 10); - } - - #[test] - fn test_new_definition_with_valid_inputs_succeeds() { - let pre_states = vec![ - AccountForTests::definition_account_uninit(), - AccountForTests::holding_account_uninit(), - ]; - - let post_states = new_definition(&pre_states, [2u8; 6], BalanceForTests::init_supply()); - - let [definition_account, holding_account] = post_states.try_into().ok().unwrap(); - assert!( - *definition_account.account() - == AccountForTests::definition_account_unclaimed().account - ); - - assert!(*holding_account.account() == AccountForTests::holding_account_unclaimed().account); - } - - #[should_panic(expected = "Invalid number of input accounts")] - #[test] - fn test_call_transfer_with_invalid_number_of_accounts_1() { - let pre_states = vec![AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }]; - let _post_states = transfer(&pre_states, 10); - } - - #[should_panic(expected = "Invalid number of input accounts")] - #[test] - fn test_call_transfer_with_invalid_number_of_accounts_2() { - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = transfer(&pre_states, 10); - } - - #[should_panic(expected = "Invalid sender data")] - #[test] - fn test_transfer_invalid_instruction_type_should_fail() { - let invalid_type = TOKEN_HOLDING_STANDARD ^ 1; - let pre_states = vec![ - AccountWithMetadata { - account: Account { - // First byte should be `TOKEN_HOLDING_STANDARD` for token holding accounts - data: Data::try_from(vec![invalid_type; TOKEN_HOLDING_DATA_SIZE]) - .expect("Invalid data"), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - ]; - let _post_states = transfer(&pre_states, 10); - } - - #[should_panic(expected = "Invalid sender data")] - #[test] - fn test_transfer_invalid_data_size_should_fail_1() { - let pre_states = vec![ - AccountWithMetadata { - account: Account { - // Data must be of exact length `TOKEN_HOLDING_DATA_SIZE` - data: Data::try_from(vec![1; TOKEN_HOLDING_DATA_SIZE - 1]).unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - ]; - let _post_states = transfer(&pre_states, 10); - } - - #[should_panic(expected = "Invalid sender data")] - #[test] - fn test_transfer_invalid_data_size_should_fail_2() { - let pre_states = vec![ - AccountWithMetadata { - account: Account { - // Data must be of exact length `TOKEN_HOLDING_DATA_SIZE` - data: Data::try_from(vec![1; TOKEN_HOLDING_DATA_SIZE - 1]).unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - ]; - let _post_states = transfer(&pre_states, 10); - } - - #[should_panic(expected = "Sender and recipient definition id mismatch")] - #[test] - fn test_transfer_with_different_definition_ids_should_fail() { - let pre_states = vec![ - AccountForTests::holding_same_definition_with_authorization(), - AccountForTests::holding_different_definition(), - ]; - let _post_states = transfer(&pre_states, 10); - } - - #[should_panic(expected = "Insufficient balance")] - #[test] - fn test_transfer_with_insufficient_balance_should_fail() { - let pre_states = vec![ - AccountForTests::holding_same_definition_with_authorization(), - AccountForTests::holding_account_same_definition_mint(), - ]; - // Attempt to transfer 38 tokens - let _post_states = transfer(&pre_states, BalanceForTests::burn_insufficient()); - } - - #[should_panic(expected = "Sender authorization is missing")] - #[test] - fn test_transfer_without_sender_authorization_should_fail() { - let mut def_data = Vec::::new(); - def_data.extend_from_slice(&[1; TOKEN_DEFINITION_DATA_SIZE - 16]); - def_data.extend_from_slice(&u128::to_le_bytes(37)); - - let pre_states = vec![ - AccountWithMetadata { - account: Account { - // Account with balance 37 - data: Data::try_from(def_data).unwrap(), - ..Account::default() - }, - is_authorized: false, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account { - data: Data::try_from(vec![1; TOKEN_HOLDING_DATA_SIZE - 1]).unwrap(), - ..Account::default() - }, - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - ]; - let _post_states = transfer(&pre_states, 37); - } - - #[test] - fn test_transfer_with_valid_inputs_succeeds() { - let pre_states = vec![ - AccountForTests::holding_account_init(), - AccountForTests::holding_account2_init(), - ]; - let post_states = transfer(&pre_states, BalanceForTests::transfer_amount()); - let [sender_post, recipient_post] = post_states.try_into().ok().unwrap(); - - assert!( - *sender_post.account() == AccountForTests::holding_account_init_post_transfer().account - ); - assert!( - *recipient_post.account() - == AccountForTests::holding_account2_init_post_transfer().account - ); - } - - #[should_panic(expected = "Invalid balance for NFT Master transfer")] - #[test] - fn test_transfer_with_master_nft_invalid_balance() { - let pre_states = vec![ - AccountForTests::holding_account_master_nft(), - AccountForTests::holding_account_uninit(), - ]; - let _post_states = transfer(&pre_states, BalanceForTests::transfer_amount()); - } - - #[should_panic(expected = "Invalid balance in recipient account for NFT transfer")] - #[test] - fn test_transfer_with_master_nft_invalid_recipient_balance() { - let pre_states = vec![ - AccountForTests::holding_account_master_nft(), - AccountForTests::holding_account_with_master_nft_transferred_to(), - ]; - let _post_states = transfer(&pre_states, BalanceForTests::printable_copies()); - } - - #[test] - fn test_transfer_with_master_nft_success() { - let pre_states = vec![ - AccountForTests::holding_account_master_nft(), - AccountForTests::holding_account_uninit(), - ]; - let post_states = transfer(&pre_states, BalanceForTests::printable_copies()); - let [sender_post, recipient_post] = post_states.try_into().ok().unwrap(); - - assert!( - *sender_post.account() - == AccountForTests::holding_account_master_nft_post_transfer().account - ); - assert!( - *recipient_post.account() - == AccountForTests::holding_account_with_master_nft_transferred_to().account - ); - } - - #[test] - fn test_token_initialize_account_succeeds() { - let pre_states = vec![ - AccountForTests::holding_account_init(), - AccountForTests::holding_account2_init(), - ]; - let post_states = transfer(&pre_states, BalanceForTests::transfer_amount()); - let [sender_post, recipient_post] = post_states.try_into().ok().unwrap(); - - assert!( - *sender_post.account() == AccountForTests::holding_account_init_post_transfer().account - ); - assert!( - *recipient_post.account() - == AccountForTests::holding_account2_init_post_transfer().account - ); - } - - #[test] - #[should_panic(expected = "Invalid number of accounts")] - fn test_burn_invalid_number_of_accounts() { - let pre_states = vec![AccountForTests::definition_account_auth()]; - let _post_states = burn(&pre_states, BalanceForTests::burn_success()); - } - - #[test] - #[should_panic(expected = "Mismatch Token Definition and Token Holding")] - fn test_burn_mismatch_def() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_different_definition(), - ]; - let _post_states = burn(&pre_states, BalanceForTests::burn_success()); - } - - #[test] - #[should_panic(expected = "Authorization is missing")] - fn test_burn_missing_authorization() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_same_definition_without_authorization(), - ]; - let _post_states = burn(&pre_states, BalanceForTests::burn_success()); - } - - #[test] - #[should_panic(expected = "Insufficient balance to burn")] - fn test_burn_insufficient_balance() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_same_definition_with_authorization(), - ]; - let _post_states = burn(&pre_states, BalanceForTests::burn_insufficient()); - } - - #[test] - #[should_panic(expected = "Total supply underflow")] - fn test_burn_total_supply_underflow() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_same_definition_with_authorization_and_large_balance(), - ]; - let _post_states = burn(&pre_states, BalanceForTests::mint_overflow()); - } - - #[test] - fn test_burn_success() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_same_definition_with_authorization(), - ]; - let post_states = burn(&pre_states, BalanceForTests::burn_success()); - - let def_post = post_states[0].clone(); - let holding_post = post_states[1].clone(); - - assert!(*def_post.account() == AccountForTests::definition_account_post_burn().account); - assert!(*holding_post.account() == AccountForTests::holding_account_post_burn().account); - } - - #[test] - #[should_panic(expected = "Invalid number of accounts")] - fn test_mint_invalid_number_of_accounts_1() { - let pre_states = vec![AccountForTests::definition_account_auth()]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - } - - #[test] - #[should_panic(expected = "Invalid number of accounts")] - fn test_mint_invalid_number_of_accounts_2() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_account_same_definition_mint(), - AccountForTests::holding_same_definition_with_authorization(), - ]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - } - - #[test] - #[should_panic(expected = "Holding account must be valid")] - fn test_mint_not_valid_holding_account() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::definition_account_without_auth(), - ]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - } - - #[test] - #[should_panic(expected = "Definition account must be valid")] - fn test_mint_not_valid_definition_account() { - let pre_states = vec![ - AccountForTests::holding_same_definition_with_authorization(), - AccountForTests::holding_same_definition_without_authorization(), - ]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - } - - #[test] - #[should_panic(expected = "Definition authorization is missing")] - fn test_mint_missing_authorization() { - let pre_states = vec![ - AccountForTests::definition_account_without_auth(), - AccountForTests::holding_same_definition_without_authorization(), - ]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - } - - #[test] - #[should_panic(expected = "Mismatch Token Definition and Token Holding")] - fn test_mint_mismatched_token_definition() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_different_definition(), - ]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - } - - #[test] - fn test_mint_success() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_same_definition_without_authorization(), - ]; - let post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - - let def_post = post_states[0].clone(); - let holding_post = post_states[1].clone(); - - assert!(*def_post.account() == AccountForTests::definition_account_mint().account); - assert!( - *holding_post.account() - == AccountForTests::holding_account_same_definition_mint().account - ); - } - - #[test] - fn test_mint_uninit_holding_success() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_account_uninit(), - ]; - let post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - - let def_post = post_states[0].clone(); - let holding_post = post_states[1].clone(); - - assert!(*def_post.account() == AccountForTests::definition_account_mint().account); - assert!(*holding_post.account() == AccountForTests::init_mint().account); - assert!(holding_post.requires_claim()); - } - - #[test] - #[should_panic(expected = "Total supply overflow")] - fn test_mint_total_supply_overflow() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_same_definition_without_authorization(), - ]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_overflow()); - } - - #[test] - #[should_panic(expected = "New balance overflow")] - fn test_mint_holding_account_overflow() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_same_definition_without_authorization_overflow(), - ]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_overflow()); - } - - #[test] - #[should_panic( - expected = "Token Definition's standard does not permit minting additional supply" - )] - fn test_mint_cannot_mint_unmintable_tokens() { - let pre_states = vec![ - AccountForTests::definition_account_with_authorization_nonfungible(), - AccountForTests::holding_same_definition_without_authorization(), - ]; - let _post_states = mint_additional_supply(&pre_states, BalanceForTests::mint_success()); - } - - #[should_panic(expected = "Invalid number of input accounts")] - #[test] - fn test_call_new_definition_metadata_with_invalid_number_of_accounts_1() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Invalid number of input accounts")] - #[test] - fn test_call_new_definition_metadata_with_invalid_number_of_accounts_2() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Invalid number of input accounts")] - #[test] - fn test_call_new_definition_metadata_with_invalid_number_of_accounts_3() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([4; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Definition target account must have default values")] - #[test] - fn test_call_new_definition_metadata_with_init_definition() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Metadata target account must have default values")] - #[test] - fn test_call_new_definition_metadata_with_init_metadata() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountForTests::holding_account_same_definition_mint(), - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Holding target account must have default values")] - #[test] - fn test_call_new_definition_metadata_with_init_holding() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountForTests::holding_account_same_definition_mint(), - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Metadata values data should be 450 bytes")] - #[test] - fn test_call_new_definition_metadata_with_too_short_metadata_length() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 449].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Metadata values data should be 450 bytes")] - #[test] - fn test_call_new_definition_metadata_with_too_long_metadata_length() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 451].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Invalid Token Standard provided")] - #[test] - fn test_call_new_definition_metadata_with_invalid_token_standard() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 14u8; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Invalid Metadata Standadard provided")] - #[test] - fn test_call_new_definition_metadata_with_invalid_metadata_standard() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = 0u8; - let metadata_standard = 14u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Invalid total supply for the specified token supply")] - #[test] - fn test_call_new_definition_metadata_invalid_supply_for_nonfungible() { - let name = [0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe]; - let total_supply = 15u128; - let token_standard = TOKEN_STANDARD_NONFUNGIBLE; - let metadata_standard = 0u8; - let metadata_values: Data = Data::try_from([1u8; 450].to_vec()).unwrap(); - - let pre_states = vec![ - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([1; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([2; 32]), - }, - AccountWithMetadata { - account: Account::default(), - is_authorized: true, - account_id: AccountId::new([3; 32]), - }, - ]; - let _post_states = new_definition_with_metadata( - &pre_states, - name, - total_supply, - token_standard, - metadata_standard, - &metadata_values, - ); - } - - #[should_panic(expected = "Invalid number of accounts")] - #[test] - fn test_print_nft_invalid_number_of_accounts_1() { - let pre_states = vec![AccountForTests::holding_account_master_nft()]; - let _post_states = print_nft(&pre_states); - } - - #[should_panic(expected = "Invalid number of accounts")] - #[test] - fn test_print_nft_invalid_number_of_accounts_2() { - let pre_states = vec![ - AccountForTests::holding_account_master_nft(), - AccountForTests::definition_account_auth(), - AccountForTests::holding_account_uninit(), - ]; - let _post_states = print_nft(&pre_states); - } - - #[should_panic(expected = "Master NFT Account must be authorized")] - #[test] - fn test_print_nft_master_account_must_be_authorized() { - let pre_states = vec![ - AccountForTests::holding_account_uninit(), - AccountForTests::holding_account_uninit(), - ]; - let _post_states = print_nft(&pre_states); - } - - #[should_panic(expected = "Printed Account must be uninitialized")] - #[test] - fn test_print_nft_print_account_initialized() { - let pre_states = vec![ - AccountForTests::holding_account_master_nft(), - AccountForTests::holding_account_init(), - ]; - let _post_states = print_nft(&pre_states); - } - - #[should_panic(expected = "Invalid Token Holding data")] - #[test] - fn test_print_nft_master_nft_invalid_token_holding() { - let pre_states = vec![ - AccountForTests::definition_account_auth(), - AccountForTests::holding_account_uninit(), - ]; - let _post_states = print_nft(&pre_states); - } - - #[should_panic(expected = "Invalid Token Holding provided as NFT Master Account")] - #[test] - fn test_print_nft_master_nft_not_nft_master_account() { - let pre_states = vec![ - AccountForTests::holding_account_init(), - AccountForTests::holding_account_uninit(), - ]; - let _post_states = print_nft(&pre_states); - } - - #[should_panic(expected = "Insufficient balance to print another NFT copy")] - #[test] - fn test_print_nft_master_nft_insufficient_balance() { - let pre_states = vec![ - AccountForTests::holding_account_master_nft_insufficient_balance(), - AccountForTests::holding_account_uninit(), - ]; - let _post_states = print_nft(&pre_states); - } - - #[test] - fn test_print_nft_success() { - let pre_states = vec![ - AccountForTests::holding_account_master_nft(), - AccountForTests::holding_account_uninit(), - ]; - let post_states = print_nft(&pre_states); - - let post_master_nft = post_states[0].account(); - let post_printed = post_states[1].account(); - - assert!( - *post_master_nft == AccountForTests::holding_account_master_nft_after_print().account - ); - assert!(*post_printed == AccountForTests::holding_account_printed_nft().account); - } + write_nssa_outputs(instruction_words, pre_states_clone, post_states); } diff --git a/programs/token/Cargo.toml b/programs/token/Cargo.toml new file mode 100644 index 00000000..39beb96a --- /dev/null +++ b/programs/token/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "token_program" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[dependencies] +nssa_core.workspace = true +token_core.workspace = true diff --git a/programs/token/core/Cargo.toml b/programs/token/core/Cargo.toml new file mode 100644 index 00000000..cf61a35f --- /dev/null +++ b/programs/token/core/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "token_core" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[dependencies] +nssa_core.workspace = true +serde.workspace = true +borsh.workspace = true diff --git a/programs/token/core/src/lib.rs b/programs/token/core/src/lib.rs new file mode 100644 index 00000000..140ae38f --- /dev/null +++ b/programs/token/core/src/lib.rs @@ -0,0 +1,241 @@ +//! This crate contains core data structures and utilities for the Token Program. + +use borsh::{BorshDeserialize, BorshSerialize}; +use nssa_core::account::{AccountId, Data}; +use serde::{Deserialize, Serialize}; + +/// Token Program Instruction. +#[derive(Serialize, Deserialize)] +pub enum Instruction { + /// Transfer tokens from sender to recipient. + /// + /// Required accounts: + /// - Sender's Token Holding account (authorized), + /// - Recipient's Token Holding account. + Transfer { amount_to_transfer: u128 }, + + /// Create a new fungible token definition without metadata. + /// + /// Required accounts: + /// - Token Definition account (uninitialized), + /// - Token Holding account (uninitialized). + NewFungibleDefinition { name: String, total_supply: u128 }, + + /// Create a new fungible or non-fungible token definition with metadata. + /// + /// Required accounts: + /// - Token Definition account (uninitialized), + /// - Token Holding account (uninitialized), + /// - Token Metadata account (uninitialized). + NewDefinitionWithMetadata { + new_definition: NewTokenDefinition, + /// Boxed to avoid large enum variant size + metadata: Box, + }, + + /// Initialize a token holding account for a given token definition. + /// + /// Required accounts: + /// - Token Definition account (initialized), + /// - Token Holding account (uninitialized), + InitializeAccount, + + /// Burn tokens from the holder's account. + /// + /// Required accounts: + /// - Token Definition account (initialized), + /// - Token Holding account (authorized). + Burn { amount_to_burn: u128 }, + + /// Mint new tokens to the holder's account. + /// + /// Required accounts: + /// - Token Definition account (authorized), + /// - Token Holding account (uninitialized or initialized). + Mint { amount_to_mint: u128 }, + + /// Print a new NFT from the master copy. + /// + /// Required accounts: + /// - NFT Master Token Holding account (authorized), + /// - NFT Printed Copy Token Holding account (uninitialized). + PrintNft, +} + +#[derive(Serialize, Deserialize)] +pub enum NewTokenDefinition { + Fungible { + name: String, + total_supply: u128, + }, + NonFungible { + name: String, + printable_supply: u128, + }, +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +pub enum TokenDefinition { + Fungible { + name: String, + total_supply: u128, + metadata_id: Option, + }, + NonFungible { + name: String, + printable_supply: u128, + metadata_id: AccountId, + }, +} + +impl TryFrom<&Data> for TokenDefinition { + type Error = std::io::Error; + + fn try_from(data: &Data) -> Result { + TokenDefinition::try_from_slice(data.as_ref()) + } +} + +impl From<&TokenDefinition> for Data { + fn from(definition: &TokenDefinition) -> Self { + // Using size_of_val as size hint for Vec allocation + let mut data = Vec::with_capacity(std::mem::size_of_val(definition)); + + BorshSerialize::serialize(definition, &mut data) + .expect("Serialization to Vec should not fail"); + + Data::try_from(data).expect("Token definition encoded data should fit into Data") + } +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +pub enum TokenHolding { + Fungible { + definition_id: AccountId, + balance: u128, + }, + NftMaster { + definition_id: AccountId, + /// The amount of printed copies left - 1 (1 reserved for master copy itself). + print_balance: u128, + }, + NftPrintedCopy { + definition_id: AccountId, + /// Whether nft is owned by the holder. + owned: bool, + }, +} + +impl TokenHolding { + pub fn zeroized_clone_from(other: &Self) -> Self { + match other { + TokenHolding::Fungible { definition_id, .. } => TokenHolding::Fungible { + definition_id: *definition_id, + balance: 0, + }, + TokenHolding::NftMaster { definition_id, .. } => TokenHolding::NftMaster { + definition_id: *definition_id, + print_balance: 0, + }, + TokenHolding::NftPrintedCopy { definition_id, .. } => TokenHolding::NftPrintedCopy { + definition_id: *definition_id, + owned: false, + }, + } + } + + pub fn zeroized_from_definition( + definition_id: AccountId, + definition: &TokenDefinition, + ) -> Self { + match definition { + TokenDefinition::Fungible { .. } => TokenHolding::Fungible { + definition_id, + balance: 0, + }, + TokenDefinition::NonFungible { .. } => TokenHolding::NftPrintedCopy { + definition_id, + owned: false, + }, + } + } + + pub fn definition_id(&self) -> AccountId { + match self { + TokenHolding::Fungible { definition_id, .. } => *definition_id, + TokenHolding::NftMaster { definition_id, .. } => *definition_id, + TokenHolding::NftPrintedCopy { definition_id, .. } => *definition_id, + } + } +} + +impl TryFrom<&Data> for TokenHolding { + type Error = std::io::Error; + + fn try_from(data: &Data) -> Result { + TokenHolding::try_from_slice(data.as_ref()) + } +} + +impl From<&TokenHolding> for Data { + fn from(holding: &TokenHolding) -> Self { + // Using size_of_val as size hint for Vec allocation + let mut data = Vec::with_capacity(std::mem::size_of_val(holding)); + + BorshSerialize::serialize(holding, &mut data) + .expect("Serialization to Vec should not fail"); + + Data::try_from(data).expect("Token holding encoded data should fit into Data") + } +} + +#[derive(Serialize, Deserialize)] +pub struct NewTokenMetadata { + /// Metadata standard. + pub standard: MetadataStandard, + /// Pointer to off-chain metadata + pub uri: String, + /// Creators of the token. + pub creators: String, +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +pub struct TokenMetadata { + /// Token Definition account id. + pub definition_id: AccountId, + /// Metadata standard . + pub standard: MetadataStandard, + /// Pointer to off-chain metadata. + pub uri: String, + /// Creators of the token. + pub creators: String, + /// Block id of primary sale. + pub primary_sale_date: u64, +} + +/// Metadata standard defining the expected format of JSON located off-chain. +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +pub enum MetadataStandard { + Simple, + Expanded, +} + +impl TryFrom<&Data> for TokenMetadata { + type Error = std::io::Error; + + fn try_from(data: &Data) -> Result { + TokenMetadata::try_from_slice(data.as_ref()) + } +} + +impl From<&TokenMetadata> for Data { + fn from(metadata: &TokenMetadata) -> Self { + // Using size_of_val as size hint for Vec allocation + let mut data = Vec::with_capacity(std::mem::size_of_val(metadata)); + + BorshSerialize::serialize(metadata, &mut data) + .expect("Serialization to Vec should not fail"); + + Data::try_from(data).expect("Token metadata encoded data should fit into Data") + } +} diff --git a/programs/token/src/burn.rs b/programs/token/src/burn.rs new file mode 100644 index 00000000..94637d92 --- /dev/null +++ b/programs/token/src/burn.rs @@ -0,0 +1,104 @@ +use nssa_core::{ + account::{AccountWithMetadata, Data}, + program::AccountPostState, +}; +use token_core::{TokenDefinition, TokenHolding}; + +pub fn burn( + definition_account: AccountWithMetadata, + user_holding_account: AccountWithMetadata, + amount_to_burn: u128, +) -> Vec { + assert!( + user_holding_account.is_authorized, + "Authorization is missing" + ); + + let mut definition = TokenDefinition::try_from(&definition_account.account.data) + .expect("Token Definition account must be valid"); + let mut holding = TokenHolding::try_from(&user_holding_account.account.data) + .expect("Token Holding account must be valid"); + + assert_eq!( + definition_account.account_id, + holding.definition_id(), + "Mismatch Token Definition and Token Holding" + ); + + match (&mut definition, &mut holding) { + ( + TokenDefinition::Fungible { + name: _, + metadata_id: _, + total_supply, + }, + TokenHolding::Fungible { + definition_id: _, + balance, + }, + ) => { + *balance = balance + .checked_sub(amount_to_burn) + .expect("Insufficient balance to burn"); + + *total_supply = total_supply + .checked_sub(amount_to_burn) + .expect("Total supply underflow"); + } + ( + TokenDefinition::NonFungible { + name: _, + printable_supply, + metadata_id: _, + }, + TokenHolding::NftMaster { + definition_id: _, + print_balance, + }, + ) => { + *printable_supply = printable_supply + .checked_sub(amount_to_burn) + .expect("Printable supply underflow"); + + *print_balance = print_balance + .checked_sub(amount_to_burn) + .expect("Insufficient balance to burn"); + } + ( + TokenDefinition::NonFungible { + name: _, + printable_supply, + metadata_id: _, + }, + TokenHolding::NftPrintedCopy { + definition_id: _, + owned, + }, + ) => { + assert_eq!( + amount_to_burn, 1, + "Invalid balance to burn for NFT Printed Copy" + ); + + assert!(*owned, "Cannot burn unowned NFT Printed Copy"); + + *printable_supply = printable_supply + .checked_sub(1) + .expect("Printable supply underflow"); + + *owned = false; + } + _ => panic!("Mismatched Token Definition and Token Holding types"), + } + + let mut definition_post = definition_account.account; + definition_post.data = Data::from(&definition); + + let mut holding_post = user_holding_account.account; + holding_post.data = Data::from(&holding); + + vec![ + AccountPostState::new(definition_post), + AccountPostState::new(holding_post), + ] +} diff --git a/programs/token/src/initialize.rs b/programs/token/src/initialize.rs new file mode 100644 index 00000000..744fdb64 --- /dev/null +++ b/programs/token/src/initialize.rs @@ -0,0 +1,34 @@ +use nssa_core::{ + account::{Account, AccountWithMetadata, Data}, + program::AccountPostState, +}; +use token_core::{TokenDefinition, TokenHolding}; + +pub fn initialize_account( + definition_account: AccountWithMetadata, + account_to_initialize: AccountWithMetadata, +) -> Vec { + assert_eq!( + account_to_initialize.account, + Account::default(), + "Only Uninitialized accounts can be initialized" + ); + + // TODO: #212 We should check that this is an account owned by the token program. + // This check can't be done here since the ID of the program is known only after compiling it + // + // Check definition account is valid + let definition = TokenDefinition::try_from(&definition_account.account.data) + .expect("Definition account must be valid"); + let holding = + TokenHolding::zeroized_from_definition(definition_account.account_id, &definition); + + let definition_post = definition_account.account; + let mut account_to_initialize = account_to_initialize.account; + account_to_initialize.data = Data::from(&holding); + + vec![ + AccountPostState::new(definition_post), + AccountPostState::new_claimed(account_to_initialize), + ] +} diff --git a/programs/token/src/lib.rs b/programs/token/src/lib.rs new file mode 100644 index 00000000..8b0698c5 --- /dev/null +++ b/programs/token/src/lib.rs @@ -0,0 +1,12 @@ +//! The Token Program implementation. + +pub use token_core as core; + +pub mod burn; +pub mod initialize; +pub mod mint; +pub mod new_definition; +pub mod print_nft; +pub mod transfer; + +mod tests; diff --git a/programs/token/src/mint.rs b/programs/token/src/mint.rs new file mode 100644 index 00000000..2f17cc62 --- /dev/null +++ b/programs/token/src/mint.rs @@ -0,0 +1,71 @@ +use nssa_core::{ + account::{Account, AccountWithMetadata, Data}, + program::AccountPostState, +}; +use token_core::{TokenDefinition, TokenHolding}; + +pub fn mint( + definition_account: AccountWithMetadata, + user_holding_account: AccountWithMetadata, + amount_to_mint: u128, +) -> Vec { + assert!( + definition_account.is_authorized, + "Definition authorization is missing" + ); + + let mut definition = TokenDefinition::try_from(&definition_account.account.data) + .expect("Token Definition account must be valid"); + let mut holding = if user_holding_account.account == Account::default() { + TokenHolding::zeroized_from_definition(definition_account.account_id, &definition) + } else { + TokenHolding::try_from(&user_holding_account.account.data) + .expect("Token Holding account must be valid") + }; + + assert_eq!( + definition_account.account_id, + holding.definition_id(), + "Mismatch Token Definition and Token Holding" + ); + + match (&mut definition, &mut holding) { + ( + TokenDefinition::Fungible { + name: _, + metadata_id: _, + total_supply, + }, + TokenHolding::Fungible { + definition_id: _, + balance, + }, + ) => { + *balance = balance + .checked_add(amount_to_mint) + .expect("Balance overflow on minting"); + + *total_supply = total_supply + .checked_add(amount_to_mint) + .expect("Total supply overflow"); + } + ( + TokenDefinition::NonFungible { .. }, + TokenHolding::NftMaster { .. } | TokenHolding::NftPrintedCopy { .. }, + ) => { + panic!("Cannot mint additional supply for Non-Fungible Tokens"); + } + _ => panic!("Mismatched Token Definition and Token Holding types"), + } + + let mut definition_post = definition_account.account; + definition_post.data = Data::from(&definition); + + let mut holding_post = user_holding_account.account; + holding_post.data = Data::from(&holding); + + vec![ + AccountPostState::new(definition_post), + AccountPostState::new_claimed_if_default(holding_post), + ] +} diff --git a/programs/token/src/new_definition.rs b/programs/token/src/new_definition.rs new file mode 100644 index 00000000..b2a9ae9f --- /dev/null +++ b/programs/token/src/new_definition.rs @@ -0,0 +1,124 @@ +use nssa_core::{ + account::{Account, AccountWithMetadata, Data}, + program::AccountPostState, +}; +use token_core::{ + NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding, TokenMetadata, +}; + +pub fn new_fungible_definition( + definition_target_account: AccountWithMetadata, + holding_target_account: AccountWithMetadata, + name: String, + total_supply: u128, +) -> Vec { + assert_eq!( + definition_target_account.account, + Account::default(), + "Definition target account must have default values" + ); + + assert_eq!( + holding_target_account.account, + Account::default(), + "Holding target account must have default values" + ); + + let token_definition = TokenDefinition::Fungible { + name, + total_supply, + metadata_id: None, + }; + let token_holding = TokenHolding::Fungible { + definition_id: definition_target_account.account_id, + balance: total_supply, + }; + + let mut definition_target_account_post = definition_target_account.account; + definition_target_account_post.data = Data::from(&token_definition); + + let mut holding_target_account_post = holding_target_account.account; + holding_target_account_post.data = Data::from(&token_holding); + + vec![ + AccountPostState::new_claimed(definition_target_account_post), + AccountPostState::new_claimed(holding_target_account_post), + ] +} + +pub fn new_definition_with_metadata( + definition_target_account: AccountWithMetadata, + holding_target_account: AccountWithMetadata, + metadata_target_account: AccountWithMetadata, + new_definition: NewTokenDefinition, + metadata: NewTokenMetadata, +) -> Vec { + assert_eq!( + definition_target_account.account, + Account::default(), + "Definition target account must have default values" + ); + + assert_eq!( + holding_target_account.account, + Account::default(), + "Holding target account must have default values" + ); + + assert_eq!( + metadata_target_account.account, + Account::default(), + "Metadata target account must have default values" + ); + + let (token_definition, token_holding) = match new_definition { + NewTokenDefinition::Fungible { name, total_supply } => ( + TokenDefinition::Fungible { + name, + total_supply, + metadata_id: Some(metadata_target_account.account_id), + }, + TokenHolding::Fungible { + definition_id: definition_target_account.account_id, + balance: total_supply, + }, + ), + NewTokenDefinition::NonFungible { + name, + printable_supply, + } => ( + TokenDefinition::NonFungible { + name, + printable_supply, + metadata_id: metadata_target_account.account_id, + }, + TokenHolding::NftMaster { + definition_id: definition_target_account.account_id, + print_balance: printable_supply, + }, + ), + }; + + let token_metadata = TokenMetadata { + definition_id: definition_target_account.account_id, + standard: metadata.standard, + uri: metadata.uri, + creators: metadata.creators, + primary_sale_date: 0u64, // TODO #261: future works to implement this + }; + + let mut definition_target_account_post = definition_target_account.account.clone(); + definition_target_account_post.data = Data::from(&token_definition); + + let mut holding_target_account_post = holding_target_account.account.clone(); + holding_target_account_post.data = Data::from(&token_holding); + + let mut metadata_target_account_post = metadata_target_account.account.clone(); + metadata_target_account_post.data = Data::from(&token_metadata); + + vec![ + AccountPostState::new_claimed(definition_target_account_post), + AccountPostState::new_claimed(holding_target_account_post), + AccountPostState::new_claimed(metadata_target_account_post), + ] +} diff --git a/programs/token/src/print_nft.rs b/programs/token/src/print_nft.rs new file mode 100644 index 00000000..d10533c1 --- /dev/null +++ b/programs/token/src/print_nft.rs @@ -0,0 +1,54 @@ +use nssa_core::{ + account::{Account, AccountWithMetadata, Data}, + program::AccountPostState, +}; +use token_core::TokenHolding; + +pub fn print_nft( + master_account: AccountWithMetadata, + printed_account: AccountWithMetadata, +) -> Vec { + assert!( + master_account.is_authorized, + "Master NFT Account must be authorized" + ); + + assert_eq!( + printed_account.account, + Account::default(), + "Printed Account must be uninitialized" + ); + + let mut master_account_data = + TokenHolding::try_from(&master_account.account.data).expect("Invalid Token Holding data"); + + let TokenHolding::NftMaster { + definition_id, + print_balance, + } = &mut master_account_data + else { + panic!("Invalid Token Holding provided as NFT Master Account"); + }; + + let definition_id = *definition_id; + + assert!( + *print_balance > 1, + "Insufficient balance to print another NFT copy" + ); + *print_balance -= 1; + + let mut master_account_post = master_account.account; + master_account_post.data = Data::from(&master_account_data); + + let mut printed_account_post = printed_account.account; + printed_account_post.data = Data::from(&TokenHolding::NftPrintedCopy { + definition_id, + owned: true, + }); + + vec![ + AccountPostState::new(master_account_post), + AccountPostState::new_claimed(printed_account_post), + ] +} diff --git a/programs/token/src/tests.rs b/programs/token/src/tests.rs new file mode 100644 index 00000000..cf95c4d4 --- /dev/null +++ b/programs/token/src/tests.rs @@ -0,0 +1,1040 @@ +#![cfg(test)] + +use nssa_core::account::{Account, AccountId, AccountWithMetadata, Data}; +use token_core::{ + MetadataStandard, NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding, +}; + +use crate::{ + burn::burn, + mint::mint, + new_definition::{new_definition_with_metadata, new_fungible_definition}, + print_nft::print_nft, + transfer::transfer, +}; + +// TODO: Move tests to a proper modules like burn, mint, transfer, etc, so that they are more +// unit-test. + +struct BalanceForTests; +struct IdForTests; + +struct AccountForTests; + +impl AccountForTests { + fn definition_account_auth() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), + total_supply: BalanceForTests::init_supply(), + metadata_id: None, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_without_auth() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), + total_supply: BalanceForTests::init_supply(), + metadata_id: None, + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_different_definition() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id_diff(), + balance: BalanceForTests::holding_balance(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_same_definition_with_authorization() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::holding_balance(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_same_definition_without_authorization() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::holding_balance(), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn holding_same_definition_without_authorization_overflow() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::init_supply(), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn definition_account_post_burn() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), + total_supply: BalanceForTests::init_supply_burned(), + metadata_id: None, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_account_post_burn() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::holding_balance_burned(), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_uninit() -> AccountWithMetadata { + AccountWithMetadata { + account: Account::default(), + is_authorized: false, + account_id: IdForTests::holding_id_2(), + } + } + + fn init_mint() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::mint_success(), + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_same_definition_mint() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::holding_balance_mint(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_mint() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), + total_supply: BalanceForTests::init_supply_mint(), + metadata_id: None, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_same_definition_with_authorization_and_large_balance() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::mint_overflow(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_with_authorization_nonfungible() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenDefinition::NonFungible { + name: String::from("test"), + printable_supply: BalanceForTests::printable_copies(), + metadata_id: AccountId::new([0; 32]), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_uninit() -> AccountWithMetadata { + AccountWithMetadata { + account: Account::default(), + is_authorized: false, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_account_init() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::init_supply(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn definition_account_unclaimed() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), + total_supply: BalanceForTests::init_supply(), + metadata_id: None, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn holding_account_unclaimed() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::init_supply(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account2_init() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::init_supply(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id_2(), + } + } + + fn holding_account2_init_post_transfer() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::recipient_post_transfer(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id_2(), + } + } + + fn holding_account_init_post_transfer() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: IdForTests::pool_definition_id(), + balance: BalanceForTests::sender_post_transfer(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_master_nft() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::NftMaster { + definition_id: IdForTests::pool_definition_id(), + print_balance: BalanceForTests::printable_copies(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_master_nft_insufficient_balance() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::NftMaster { + definition_id: IdForTests::pool_definition_id(), + print_balance: 1, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_master_nft_after_print() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::NftMaster { + definition_id: IdForTests::pool_definition_id(), + print_balance: BalanceForTests::printable_copies() - 1, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_printed_nft() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::NftPrintedCopy { + definition_id: IdForTests::pool_definition_id(), + owned: true, + }), + nonce: 0, + }, + is_authorized: false, + account_id: IdForTests::holding_id(), + } + } + + fn holding_account_with_master_nft_transferred_to() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [0u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::NftMaster { + definition_id: IdForTests::pool_definition_id(), + print_balance: BalanceForTests::printable_copies(), + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id_2(), + } + } + + fn holding_account_master_nft_post_transfer() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: [5u32; 8], + balance: 0u128, + data: Data::from(&TokenHolding::NftMaster { + definition_id: IdForTests::pool_definition_id(), + print_balance: 0, + }), + nonce: 0, + }, + is_authorized: true, + account_id: IdForTests::holding_id(), + } + } +} + +impl BalanceForTests { + fn init_supply() -> u128 { + 100_000 + } + + fn holding_balance() -> u128 { + 1_000 + } + + fn init_supply_burned() -> u128 { + 99_500 + } + + fn holding_balance_burned() -> u128 { + 500 + } + + fn burn_success() -> u128 { + 500 + } + + fn burn_insufficient() -> u128 { + 1_500 + } + + fn mint_success() -> u128 { + 50_000 + } + + fn holding_balance_mint() -> u128 { + 51_000 + } + + fn mint_overflow() -> u128 { + u128::MAX - 40_000 + } + + fn init_supply_mint() -> u128 { + 150_000 + } + + fn sender_post_transfer() -> u128 { + 95_000 + } + + fn recipient_post_transfer() -> u128 { + 105_000 + } + + fn transfer_amount() -> u128 { + 5_000 + } + + fn printable_copies() -> u128 { + 10 + } +} + +impl IdForTests { + fn pool_definition_id() -> AccountId { + AccountId::new([15; 32]) + } + + fn pool_definition_id_diff() -> AccountId { + AccountId::new([16; 32]) + } + + fn holding_id() -> AccountId { + AccountId::new([17; 32]) + } + + fn holding_id_2() -> AccountId { + AccountId::new([42; 32]) + } +} + +#[should_panic(expected = "Definition target account must have default values")] +#[test] +fn test_new_definition_non_default_first_account_should_fail() { + let definition_account = AccountWithMetadata { + account: Account { + program_owner: [1, 2, 3, 4, 5, 6, 7, 8], + ..Account::default() + }, + is_authorized: true, + account_id: AccountId::new([1; 32]), + }; + let holding_account = AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }; + let _post_states = new_fungible_definition( + definition_account, + holding_account, + String::from("test"), + 10, + ); +} + +#[should_panic(expected = "Holding target account must have default values")] +#[test] +fn test_new_definition_non_default_second_account_should_fail() { + let definition_account = AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }; + let holding_account = AccountWithMetadata { + account: Account { + program_owner: [1, 2, 3, 4, 5, 6, 7, 8], + ..Account::default() + }, + is_authorized: true, + account_id: AccountId::new([2; 32]), + }; + let _post_states = new_fungible_definition( + definition_account, + holding_account, + String::from("test"), + 10, + ); +} + +#[test] +fn test_new_definition_with_valid_inputs_succeeds() { + let definition_account = AccountForTests::definition_account_uninit(); + let holding_account = AccountForTests::holding_account_uninit(); + + let post_states = new_fungible_definition( + definition_account, + holding_account, + String::from("test"), + BalanceForTests::init_supply(), + ); + + let [definition_account, holding_account] = post_states.try_into().unwrap(); + assert_eq!( + *definition_account.account(), + AccountForTests::definition_account_unclaimed().account + ); + + assert_eq!( + *holding_account.account(), + AccountForTests::holding_account_unclaimed().account + ); +} + +#[should_panic(expected = "Sender and recipient definition id mismatch")] +#[test] +fn test_transfer_with_different_definition_ids_should_fail() { + let sender = AccountForTests::holding_same_definition_with_authorization(); + let recipient = AccountForTests::holding_different_definition(); + let _post_states = transfer(sender, recipient, 10); +} + +#[should_panic(expected = "Insufficient balance")] +#[test] +fn test_transfer_with_insufficient_balance_should_fail() { + let sender = AccountForTests::holding_same_definition_with_authorization(); + let recipient = AccountForTests::holding_account_same_definition_mint(); + // Attempt to transfer more than balance + let _post_states = transfer(sender, recipient, BalanceForTests::burn_insufficient()); +} + +#[should_panic(expected = "Sender authorization is missing")] +#[test] +fn test_transfer_without_sender_authorization_should_fail() { + let sender = AccountForTests::holding_same_definition_without_authorization(); + let recipient = AccountForTests::holding_account_uninit(); + let _post_states = transfer(sender, recipient, 37); +} + +#[test] +fn test_transfer_with_valid_inputs_succeeds() { + let sender = AccountForTests::holding_account_init(); + let recipient = AccountForTests::holding_account2_init(); + let post_states = transfer(sender, recipient, BalanceForTests::transfer_amount()); + let [sender_post, recipient_post] = post_states.try_into().unwrap(); + + assert_eq!( + *sender_post.account(), + AccountForTests::holding_account_init_post_transfer().account + ); + assert_eq!( + *recipient_post.account(), + AccountForTests::holding_account2_init_post_transfer().account + ); +} + +#[should_panic(expected = "Invalid balance for NFT Master transfer")] +#[test] +fn test_transfer_with_master_nft_invalid_balance() { + let sender = AccountForTests::holding_account_master_nft(); + let recipient = AccountForTests::holding_account_uninit(); + let _post_states = transfer(sender, recipient, BalanceForTests::transfer_amount()); +} + +#[should_panic(expected = "Invalid balance in recipient account for NFT transfer")] +#[test] +fn test_transfer_with_master_nft_invalid_recipient_balance() { + let sender = AccountForTests::holding_account_master_nft(); + let recipient = AccountForTests::holding_account_with_master_nft_transferred_to(); + let _post_states = transfer(sender, recipient, BalanceForTests::printable_copies()); +} + +#[test] +fn test_transfer_with_master_nft_success() { + let sender = AccountForTests::holding_account_master_nft(); + let recipient = AccountForTests::holding_account_uninit(); + let post_states = transfer(sender, recipient, BalanceForTests::printable_copies()); + let [sender_post, recipient_post] = post_states.try_into().unwrap(); + + assert_eq!( + *sender_post.account(), + AccountForTests::holding_account_master_nft_post_transfer().account + ); + assert_eq!( + *recipient_post.account(), + AccountForTests::holding_account_with_master_nft_transferred_to().account + ); +} + +#[test] +fn test_token_initialize_account_succeeds() { + let sender = AccountForTests::holding_account_init(); + let recipient = AccountForTests::holding_account2_init(); + let post_states = transfer(sender, recipient, BalanceForTests::transfer_amount()); + let [sender_post, recipient_post] = post_states.try_into().unwrap(); + + assert_eq!( + *sender_post.account(), + AccountForTests::holding_account_init_post_transfer().account + ); + assert_eq!( + *recipient_post.account(), + AccountForTests::holding_account2_init_post_transfer().account + ); +} + +#[test] +#[should_panic(expected = "Mismatch Token Definition and Token Holding")] +fn test_burn_mismatch_def() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_different_definition(); + let _post_states = burn( + definition_account, + holding_account, + BalanceForTests::burn_success(), + ); +} + +#[test] +#[should_panic(expected = "Authorization is missing")] +fn test_burn_missing_authorization() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_same_definition_without_authorization(); + let _post_states = burn( + definition_account, + holding_account, + BalanceForTests::burn_success(), + ); +} + +#[test] +#[should_panic(expected = "Insufficient balance to burn")] +fn test_burn_insufficient_balance() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_same_definition_with_authorization(); + let _post_states = burn( + definition_account, + holding_account, + BalanceForTests::burn_insufficient(), + ); +} + +#[test] +#[should_panic(expected = "Total supply underflow")] +fn test_burn_total_supply_underflow() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = + AccountForTests::holding_same_definition_with_authorization_and_large_balance(); + let _post_states = burn( + definition_account, + holding_account, + BalanceForTests::mint_overflow(), + ); +} + +#[test] +fn test_burn_success() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_same_definition_with_authorization(); + let post_states = burn( + definition_account, + holding_account, + BalanceForTests::burn_success(), + ); + + let [def_post, holding_post] = post_states.try_into().unwrap(); + + assert_eq!( + *def_post.account(), + AccountForTests::definition_account_post_burn().account + ); + assert_eq!( + *holding_post.account(), + AccountForTests::holding_account_post_burn().account + ); +} + +#[test] +#[should_panic(expected = "Holding account must be valid")] +fn test_mint_not_valid_holding_account() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::definition_account_without_auth(); + let _post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_success(), + ); +} + +#[test] +#[should_panic(expected = "Definition account must be valid")] +fn test_mint_not_valid_definition_account() { + let definition_account = AccountForTests::holding_same_definition_with_authorization(); + let holding_account = AccountForTests::holding_same_definition_without_authorization(); + let _post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_success(), + ); +} + +#[test] +#[should_panic(expected = "Definition authorization is missing")] +fn test_mint_missing_authorization() { + let definition_account = AccountForTests::definition_account_without_auth(); + let holding_account = AccountForTests::holding_same_definition_without_authorization(); + let _post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_success(), + ); +} + +#[test] +#[should_panic(expected = "Mismatch Token Definition and Token Holding")] +fn test_mint_mismatched_token_definition() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_different_definition(); + let _post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_success(), + ); +} + +#[test] +fn test_mint_success() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_same_definition_without_authorization(); + let post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_success(), + ); + + let [def_post, holding_post] = post_states.try_into().unwrap(); + + assert_eq!( + *def_post.account(), + AccountForTests::definition_account_mint().account + ); + assert_eq!( + *holding_post.account(), + AccountForTests::holding_account_same_definition_mint().account + ); +} + +#[test] +fn test_mint_uninit_holding_success() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_account_uninit(); + let post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_success(), + ); + + let [def_post, holding_post] = post_states.try_into().unwrap(); + + assert_eq!( + *def_post.account(), + AccountForTests::definition_account_mint().account + ); + assert_eq!( + *holding_post.account(), + AccountForTests::init_mint().account + ); + assert!(holding_post.requires_claim()); +} + +#[test] +#[should_panic(expected = "Total supply overflow")] +fn test_mint_total_supply_overflow() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_same_definition_without_authorization(); + let _post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_overflow(), + ); +} + +#[test] +#[should_panic(expected = "Balance overflow on minting")] +fn test_mint_holding_account_overflow() { + let definition_account = AccountForTests::definition_account_auth(); + let holding_account = AccountForTests::holding_same_definition_without_authorization_overflow(); + let _post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_overflow(), + ); +} + +#[test] +#[should_panic(expected = "Cannot mint additional supply for Non-Fungible Tokens")] +fn test_mint_cannot_mint_unmintable_tokens() { + let definition_account = AccountForTests::definition_account_with_authorization_nonfungible(); + let holding_account = AccountForTests::holding_account_master_nft(); + let _post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_success(), + ); +} + +#[should_panic(expected = "Definition target account must have default values")] +#[test] +fn test_call_new_definition_metadata_with_init_definition() { + let definition_account = AccountForTests::definition_account_auth(); + let metadata_account = AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }; + let holding_account = AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }; + let new_definition = NewTokenDefinition::Fungible { + name: String::from("test"), + total_supply: 15u128, + }; + let metadata = NewTokenMetadata { + standard: MetadataStandard::Simple, + uri: "test_uri".to_string(), + creators: "test_creators".to_string(), + }; + let _post_states = new_definition_with_metadata( + definition_account, + metadata_account, + holding_account, + new_definition, + metadata, + ); +} + +#[should_panic(expected = "Metadata target account must have default values")] +#[test] +fn test_call_new_definition_metadata_with_init_metadata() { + let definition_account = AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }; + let holding_account = AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([3; 32]), + }; + let metadata_account = AccountForTests::holding_account_same_definition_mint(); + let new_definition = NewTokenDefinition::Fungible { + name: String::from("test"), + total_supply: 15u128, + }; + let metadata = NewTokenMetadata { + standard: MetadataStandard::Simple, + uri: "test_uri".to_string(), + creators: "test_creators".to_string(), + }; + let _post_states = new_definition_with_metadata( + definition_account, + holding_account, + metadata_account, + new_definition, + metadata, + ); +} + +#[should_panic(expected = "Holding target account must have default values")] +#[test] +fn test_call_new_definition_metadata_with_init_holding() { + let definition_account = AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([1; 32]), + }; + let metadata_account = AccountWithMetadata { + account: Account::default(), + is_authorized: true, + account_id: AccountId::new([2; 32]), + }; + let holding_account = AccountForTests::holding_account_same_definition_mint(); + let new_definition = NewTokenDefinition::Fungible { + name: String::from("test"), + total_supply: 15u128, + }; + let metadata = NewTokenMetadata { + standard: MetadataStandard::Simple, + uri: "test_uri".to_string(), + creators: "test_creators".to_string(), + }; + let _post_states = new_definition_with_metadata( + definition_account, + holding_account, + metadata_account, + new_definition, + metadata, + ); +} + +#[should_panic(expected = "Master NFT Account must be authorized")] +#[test] +fn test_print_nft_master_account_must_be_authorized() { + let master_account = AccountForTests::holding_account_uninit(); + let printed_account = AccountForTests::holding_account_uninit(); + let _post_states = print_nft(master_account, printed_account); +} + +#[should_panic(expected = "Printed Account must be uninitialized")] +#[test] +fn test_print_nft_print_account_initialized() { + let master_account = AccountForTests::holding_account_master_nft(); + let printed_account = AccountForTests::holding_account_init(); + let _post_states = print_nft(master_account, printed_account); +} + +#[should_panic(expected = "Invalid Token Holding data")] +#[test] +fn test_print_nft_master_nft_invalid_token_holding() { + let master_account = AccountForTests::definition_account_auth(); + let printed_account = AccountForTests::holding_account_uninit(); + let _post_states = print_nft(master_account, printed_account); +} + +#[should_panic(expected = "Invalid Token Holding provided as NFT Master Account")] +#[test] +fn test_print_nft_master_nft_not_nft_master_account() { + let master_account = AccountForTests::holding_account_init(); + let printed_account = AccountForTests::holding_account_uninit(); + let _post_states = print_nft(master_account, printed_account); +} + +#[should_panic(expected = "Insufficient balance to print another NFT copy")] +#[test] +fn test_print_nft_master_nft_insufficient_balance() { + let master_account = AccountForTests::holding_account_master_nft_insufficient_balance(); + let printed_account = AccountForTests::holding_account_uninit(); + let _post_states = print_nft(master_account, printed_account); +} + +#[test] +fn test_print_nft_success() { + let master_account = AccountForTests::holding_account_master_nft(); + let printed_account = AccountForTests::holding_account_uninit(); + let post_states = print_nft(master_account, printed_account); + + let [post_master_nft, post_printed] = post_states.try_into().unwrap(); + + assert_eq!( + *post_master_nft.account(), + AccountForTests::holding_account_master_nft_after_print().account + ); + assert_eq!( + *post_printed.account(), + AccountForTests::holding_account_printed_nft().account + ); +} diff --git a/programs/token/src/transfer.rs b/programs/token/src/transfer.rs new file mode 100644 index 00000000..a1087bb1 --- /dev/null +++ b/programs/token/src/transfer.rs @@ -0,0 +1,110 @@ +use nssa_core::{ + account::{Account, AccountWithMetadata, Data}, + program::AccountPostState, +}; +use token_core::TokenHolding; + +pub fn transfer( + sender: AccountWithMetadata, + recipient: AccountWithMetadata, + balance_to_move: u128, +) -> Vec { + assert!(sender.is_authorized, "Sender authorization is missing"); + + let mut sender_holding = + TokenHolding::try_from(&sender.account.data).expect("Invalid sender data"); + + let mut recipient_holding = if recipient.account == Account::default() { + TokenHolding::zeroized_clone_from(&sender_holding) + } else { + TokenHolding::try_from(&recipient.account.data).expect("Invalid recipient data") + }; + + assert_eq!( + sender_holding.definition_id(), + recipient_holding.definition_id(), + "Sender and recipient definition id mismatch" + ); + + match (&mut sender_holding, &mut recipient_holding) { + ( + TokenHolding::Fungible { + definition_id: _, + balance: sender_balance, + }, + TokenHolding::Fungible { + definition_id: _, + balance: recipient_balance, + }, + ) => { + *sender_balance = sender_balance + .checked_sub(balance_to_move) + .expect("Insufficient balance"); + + *recipient_balance = recipient_balance + .checked_add(balance_to_move) + .expect("Recipient balance overflow"); + } + ( + TokenHolding::NftMaster { + definition_id: _, + print_balance: sender_print_balance, + }, + TokenHolding::NftMaster { + definition_id: _, + print_balance: recipient_print_balance, + }, + ) => { + assert_eq!( + *recipient_print_balance, 0, + "Invalid balance in recipient account for NFT transfer" + ); + + assert_eq!( + *sender_print_balance, balance_to_move, + "Invalid balance for NFT Master transfer" + ); + + std::mem::swap(sender_print_balance, recipient_print_balance); + } + ( + TokenHolding::NftPrintedCopy { + definition_id: _, + owned: sender_owned, + }, + TokenHolding::NftPrintedCopy { + definition_id: _, + owned: recipient_owned, + }, + ) => { + assert_eq!( + balance_to_move, 1, + "Invalid balance for NFT Printed Copy transfer" + ); + + assert!(*sender_owned, "Sender does not own the NFT Printed Copy"); + + assert!( + !*recipient_owned, + "Recipient already owns the NFT Printed Copy" + ); + + *sender_owned = false; + *recipient_owned = true; + } + _ => { + panic!("Mismatched token holding types for transfer"); + } + }; + + let mut sender_post = sender.account; + sender_post.data = Data::from(&sender_holding); + + let mut recipient_post = recipient.account; + recipient_post.data = Data::from(&recipient_holding); + + vec![ + AccountPostState::new(sender_post), + AccountPostState::new_claimed_if_default(recipient_post), + ] +} diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 9b2d00da..ca8548bc 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -9,6 +9,7 @@ nssa_core.workspace = true nssa.workspace = true common.workspace = true key_protocol.workspace = true +token_core.workspace = true anyhow.workspace = true serde_json.workspace = true diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 0e6c48fa..9407c8c5 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -4,10 +4,10 @@ use clap::Subcommand; use itertools::Itertools as _; use key_protocol::key_management::key_tree::chain_index::ChainIndex; use nssa::{Account, PublicKey, program::Program}; -use serde::Serialize; +use token_core::{TokenDefinition, TokenHolding}; use crate::{ - TokenDefinition, TokenHolding, WalletCore, + WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, config::Label, helperfunctions::{AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, @@ -121,83 +121,26 @@ impl WalletSubcommand for NewSubcommand { } } -#[derive(Debug, Serialize)] -pub struct AuthenticatedTransferAccountView { - pub balance: u128, -} - -impl From for AuthenticatedTransferAccountView { - fn from(value: nssa::Account) -> Self { - Self { - balance: value.balance, - } - } -} - -#[derive(Debug, Serialize)] -pub struct TokedDefinitionAccountView { - pub account_type: String, - pub name: String, - pub total_supply: u128, -} - -impl From for TokedDefinitionAccountView { - fn from(value: TokenDefinition) -> Self { - Self { - account_type: "Token definition".to_string(), - name: { - // Assuming, that name does not have UTF-8 NULL and all zeroes are padding. - let name_trimmed: Vec<_> = - value.name.into_iter().take_while(|ch| *ch != 0).collect(); - String::from_utf8(name_trimmed).unwrap_or(hex::encode(value.name)) - }, - total_supply: value.total_supply, - } - } -} - -#[derive(Debug, Serialize)] -pub struct TokedHoldingAccountView { - pub account_type: String, - pub definition_id: String, - pub balance: u128, -} - -impl From for TokedHoldingAccountView { - fn from(value: TokenHolding) -> Self { - Self { - account_type: "Token holding".to_string(), - definition_id: value.definition_id.to_string(), - balance: value.balance, - } - } -} - /// Formats account details for display, returning (description, json_view) fn format_account_details(account: &Account) -> (String, String) { let auth_tr_prog_id = Program::authenticated_transfer_program().id(); let token_prog_id = Program::token().id(); match &account.program_owner { - _ if account.program_owner == auth_tr_prog_id => { - let acc_view: AuthenticatedTransferAccountView = account.clone().into(); - ( - "Account owned by authenticated transfer program".to_string(), - serde_json::to_string(&acc_view).unwrap(), - ) - } - _ if account.program_owner == token_prog_id => { - if let Some(token_def) = TokenDefinition::parse(&account.data) { - let acc_view: TokedDefinitionAccountView = token_def.into(); + o if *o == auth_tr_prog_id => ( + "Account owned by authenticated transfer program".to_string(), + serde_json::to_string(&account).unwrap(), + ), + o if *o == token_prog_id => { + if let Ok(token_def) = TokenDefinition::try_from(&account.data) { ( "Definition account owned by token program".to_string(), - serde_json::to_string(&acc_view).unwrap(), + serde_json::to_string(&token_def).unwrap(), ) - } else if let Some(token_hold) = TokenHolding::parse(&account.data) { - let acc_view: TokedHoldingAccountView = token_hold.into(); + } else if let Ok(token_hold) = TokenHolding::try_from(&account.data) { ( "Holding account owned by token program".to_string(), - serde_json::to_string(&acc_view).unwrap(), + serde_json::to_string(&token_hold).unwrap(), ) } else { let account_hr: HumanReadableAccount = account.clone().into(); @@ -456,52 +399,3 @@ impl WalletSubcommand for AccountSubcommand { } } } - -#[cfg(test)] -mod tests { - use nssa::AccountId; - - use crate::cli::account::{TokedDefinitionAccountView, TokenDefinition}; - - #[test] - fn test_invalid_utf_8_name_of_token() { - let token_def = TokenDefinition { - account_type: 1, - name: [137, 12, 14, 3, 5, 4], - total_supply: 100, - metadata_id: AccountId::new([0; 32]), - }; - - let token_def_view: TokedDefinitionAccountView = token_def.into(); - - assert_eq!(token_def_view.name, "890c0e030504"); - } - - #[test] - fn test_valid_utf_8_name_of_token_all_bytes() { - let token_def = TokenDefinition { - account_type: 1, - name: [240, 159, 146, 150, 66, 66], - total_supply: 100, - metadata_id: AccountId::new([0; 32]), - }; - - let token_def_view: TokedDefinitionAccountView = token_def.into(); - - assert_eq!(token_def_view.name, "💖BB"); - } - - #[test] - fn test_valid_utf_8_name_of_token_less_bytes() { - let token_def = TokenDefinition { - account_type: 1, - name: [78, 65, 77, 69, 0, 0], - total_supply: 100, - metadata_id: AccountId::new([0; 32]), - }; - - let token_def_view: TokedDefinitionAccountView = token_def.into(); - - assert_eq!(token_def_view.name, "NAME"); - } -} diff --git a/wallet/src/cli/programs/token.rs b/wallet/src/cli/programs/token.rs index b5ea1b34..c16c0c94 100644 --- a/wallet/src/cli/programs/token.rs +++ b/wallet/src/cli/programs/token.rs @@ -1258,14 +1258,6 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { name, total_supply, } => { - let name = name.as_bytes(); - if name.len() > 6 { - // TODO: return error - panic!("Name length mismatch"); - } - let mut name_bytes = [0; 6]; - name_bytes[..name.len()].copy_from_slice(name); - let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let supply_account_id: AccountId = supply_account_id.parse().unwrap(); @@ -1273,7 +1265,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { .send_new_definition_private_owned_definiton_and_supply( definition_account_id, supply_account_id, - name_bytes, + name, total_supply, ) .await?; @@ -1307,14 +1299,6 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { name, total_supply, } => { - let name = name.as_bytes(); - if name.len() > 6 { - // TODO: return error - panic!("Name length mismatch"); - } - let mut name_bytes = [0; 6]; - name_bytes[..name.len()].copy_from_slice(name); - let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let supply_account_id: AccountId = supply_account_id.parse().unwrap(); @@ -1322,7 +1306,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { .send_new_definition_private_owned_definiton( definition_account_id, supply_account_id, - name_bytes, + name, total_supply, ) .await?; @@ -1353,14 +1337,6 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { name, total_supply, } => { - let name = name.as_bytes(); - if name.len() > 6 { - // TODO: return error - panic!("Name length mismatch"); - } - let mut name_bytes = [0; 6]; - name_bytes[..name.len()].copy_from_slice(name); - let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let supply_account_id: AccountId = supply_account_id.parse().unwrap(); @@ -1368,7 +1344,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { .send_new_definition_private_owned_supply( definition_account_id, supply_account_id, - name_bytes, + name, total_supply, ) .await?; @@ -1399,18 +1375,11 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { name, total_supply, } => { - let name = name.as_bytes(); - if name.len() > 6 { - // TODO: return error - panic!(); - } - let mut name_bytes = [0; 6]; - name_bytes[..name.len()].copy_from_slice(name); Token(wallet_core) .send_new_definition( definition_account_id.parse().unwrap(), supply_account_id.parse().unwrap(), - name_bytes, + name, total_supply, ) .await?; diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 23344107..baf263ce 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -18,9 +18,7 @@ use nssa::{ circuit::ProgramWithDependencies, message::EncryptedAccountData, }, }; -use nssa_core::{ - Commitment, MembershipProof, SharedSecretKey, account::Data, program::InstructionData, -}; +use nssa_core::{Commitment, MembershipProof, SharedSecretKey, program::InstructionData}; pub use privacy_preserving_tx::PrivacyPreservingAccount; use tokio::io::AsyncWriteExt; use url::Url; @@ -46,82 +44,6 @@ pub enum AccDecodeData { Decode(nssa_core::SharedSecretKey, AccountId), } -const TOKEN_DEFINITION_DATA_SIZE: usize = 55; - -const TOKEN_HOLDING_TYPE: u8 = 1; -const TOKEN_HOLDING_DATA_SIZE: usize = 49; -const TOKEN_STANDARD_FUNGIBLE_TOKEN: u8 = 0; -const TOKEN_STANDARD_NONFUNGIBLE: u8 = 2; - -struct TokenDefinition { - #[allow(unused)] - account_type: u8, - name: [u8; 6], - total_supply: u128, - #[allow(unused)] - metadata_id: AccountId, -} - -struct TokenHolding { - #[allow(unused)] - account_type: u8, - definition_id: AccountId, - balance: u128, -} - -impl TokenDefinition { - fn parse(data: &Data) -> Option { - let data = Vec::::from(data.clone()); - - if data.len() != TOKEN_DEFINITION_DATA_SIZE { - None - } else { - let account_type = data[0]; - let name = data[1..7].try_into().expect("Name must be a 6 bytes"); - let total_supply = u128::from_le_bytes( - data[7..23] - .try_into() - .expect("Total supply must be 16 bytes little-endian"), - ); - let metadata_id = AccountId::new( - data[23..TOKEN_DEFINITION_DATA_SIZE] - .try_into() - .expect("Token Program expects valid Account Id for Metadata"), - ); - - let this = Some(Self { - account_type, - name, - total_supply, - metadata_id, - }); - - match account_type { - TOKEN_STANDARD_NONFUNGIBLE if total_supply != 1 => None, - TOKEN_STANDARD_FUNGIBLE_TOKEN if metadata_id != AccountId::new([0; 32]) => None, - _ => this, - } - } - } -} - -impl TokenHolding { - fn parse(data: &[u8]) -> Option { - if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE { - None - } else { - let account_type = data[0]; - let definition_id = AccountId::new(data[1..33].try_into().unwrap()); - let balance = u128::from_le_bytes(data[33..].try_into().unwrap()); - Some(Self { - definition_id, - balance, - account_type, - }) - } - } -} - pub struct WalletCore { config_path: PathBuf, config_overrides: Option, diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index 3beb92cb..7039a937 100644 --- a/wallet/src/program_facades/amm.rs +++ b/wallet/src/program_facades/amm.rs @@ -1,8 +1,9 @@ use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; use nssa::{AccountId, ProgramId, program::Program}; use nssa_core::program::PdaSeed; +use token_core::TokenHolding; -use crate::{TokenHolding, WalletCore}; +use crate::WalletCore; fn compute_pool_pda( amm_program_id: ProgramId, @@ -123,12 +124,12 @@ impl Amm<'_> { .await .map_err(|_| ExecutionFailureKind::SequencerError)?; - let definition_token_a_id = TokenHolding::parse(&user_a_acc.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? - .definition_id; - let definition_token_b_id = TokenHolding::parse(&user_b_acc.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? - .definition_id; + let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_a))? + .definition_id(); + let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_b))? + .definition_id(); let amm_pool = compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id); @@ -208,12 +209,12 @@ impl Amm<'_> { .await .map_err(|_| ExecutionFailureKind::SequencerError)?; - let definition_token_a_id = TokenHolding::parse(&user_a_acc.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? - .definition_id; - let definition_token_b_id = TokenHolding::parse(&user_b_acc.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_b))? - .definition_id; + let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_a))? + .definition_id(); + let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_b))? + .definition_id(); let amm_pool = compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id); @@ -242,14 +243,14 @@ impl Amm<'_> { .await .map_err(|_| ExecutionFailureKind::SequencerError)?; - let token_holder_a = TokenHolding::parse(&token_holder_acc_a.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))?; - let token_holder_b = TokenHolding::parse(&token_holder_acc_b.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_b))?; + let token_holder_a = TokenHolding::try_from(&token_holder_acc_a.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_a))?; + let token_holder_b = TokenHolding::try_from(&token_holder_acc_b.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_b))?; - if token_holder_a.definition_id == token_definition_id { + if token_holder_a.definition_id() == token_definition_id { account_id_auth = user_holding_a; - } else if token_holder_b.definition_id == token_definition_id { + } else if token_holder_b.definition_id() == token_definition_id { account_id_auth = user_holding_b; } else { return Err(ExecutionFailureKind::AccountDataError(token_definition_id)); @@ -309,12 +310,12 @@ impl Amm<'_> { .await .map_err(|_| ExecutionFailureKind::SequencerError)?; - let definition_token_a_id = TokenHolding::parse(&user_a_acc.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? - .definition_id; - let definition_token_b_id = TokenHolding::parse(&user_b_acc.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? - .definition_id; + let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_a))? + .definition_id(); + let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_b))? + .definition_id(); let amm_pool = compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id); @@ -395,12 +396,12 @@ impl Amm<'_> { .await .map_err(|_| ExecutionFailureKind::SequencerError)?; - let definition_token_a_id = TokenHolding::parse(&user_a_acc.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? - .definition_id; - let definition_token_b_id = TokenHolding::parse(&user_b_acc.data) - .ok_or(ExecutionFailureKind::AccountDataError(user_holding_a))? - .definition_id; + let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_a))? + .definition_id(); + let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data) + .map_err(|_| ExecutionFailureKind::AccountDataError(user_holding_b))? + .definition_id(); let amm_pool = compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id); diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index 0d3f79d7..4160e255 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -1,6 +1,7 @@ use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; use nssa::{AccountId, program::Program}; use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey}; +use token_core::Instruction; use crate::{PrivacyPreservingAccount, WalletCore}; @@ -11,15 +12,12 @@ impl Token<'_> { &self, definition_account_id: AccountId, supply_account_id: AccountId, - name: [u8; 6], + name: String, total_supply: u128, ) -> Result { let account_ids = vec![definition_account_id, supply_account_id]; let program_id = nssa::program::Program::token().id(); - // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] - let mut instruction = vec![0u8; 23]; - instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); - instruction[17..].copy_from_slice(&name); + let instruction = Instruction::NewFungibleDefinition { name, total_supply }; let message = nssa::public_transaction::Message::try_new( program_id, account_ids, @@ -39,10 +37,10 @@ impl Token<'_> { &self, definition_account_id: AccountId, supply_account_id: AccountId, - name: [u8; 6], + name: String, total_supply: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_definition(name, total_supply); + let instruction = Instruction::NewFungibleDefinition { name, total_supply }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -69,10 +67,10 @@ impl Token<'_> { &self, definition_account_id: AccountId, supply_account_id: AccountId, - name: [u8; 6], + name: String, total_supply: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_definition(name, total_supply); + let instruction = Instruction::NewFungibleDefinition { name, total_supply }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -99,10 +97,10 @@ impl Token<'_> { &self, definition_account_id: AccountId, supply_account_id: AccountId, - name: [u8; 6], + name: String, total_supply: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let instruction = token_program_preparation_definition(name, total_supply); + let instruction = Instruction::NewFungibleDefinition { name, total_supply }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -132,11 +130,9 @@ impl Token<'_> { ) -> Result { let account_ids = vec![sender_account_id, recipient_account_id]; let program_id = nssa::program::Program::token().id(); - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || - // 0x00 || 0x00 || 0x00]. - let mut instruction = vec![0u8; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); + let instruction = Instruction::Transfer { + amount_to_transfer: amount, + }; let Ok(nonces) = self.0.get_accounts_nonces(vec![sender_account_id]).await else { return Err(ExecutionFailureKind::SequencerError); }; @@ -170,7 +166,9 @@ impl Token<'_> { recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let instruction = token_program_preparation_transfer(amount); + let instruction = Instruction::Transfer { + amount_to_transfer: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -199,7 +197,9 @@ impl Token<'_> { recipient_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let instruction = token_program_preparation_transfer(amount); + let instruction = Instruction::Transfer { + amount_to_transfer: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -230,7 +230,9 @@ impl Token<'_> { recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_transfer(amount); + let instruction = Instruction::Transfer { + amount_to_transfer: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -259,7 +261,9 @@ impl Token<'_> { recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_transfer(amount); + let instruction = Instruction::Transfer { + amount_to_transfer: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -289,7 +293,9 @@ impl Token<'_> { recipient_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_transfer(amount); + let instruction = Instruction::Transfer { + amount_to_transfer: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -322,7 +328,9 @@ impl Token<'_> { amount: u128, ) -> Result { let account_ids = vec![definition_account_id, holder_account_id]; - let instruction = token_program_preparation_burn(amount); + let instruction = Instruction::Burn { + amount_to_burn: amount, + }; let Ok(nonces) = self.0.get_accounts_nonces(vec![holder_account_id]).await else { return Err(ExecutionFailureKind::SequencerError); @@ -355,7 +363,9 @@ impl Token<'_> { holder_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let instruction = token_program_preparation_burn(amount); + let instruction = Instruction::Burn { + amount_to_burn: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -383,7 +393,9 @@ impl Token<'_> { holder_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_burn(amount); + let instruction = Instruction::Burn { + amount_to_burn: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -412,7 +424,9 @@ impl Token<'_> { holder_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_burn(amount); + let instruction = Instruction::Burn { + amount_to_burn: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -442,7 +456,9 @@ impl Token<'_> { amount: u128, ) -> Result { let account_ids = vec![definition_account_id, holder_account_id]; - let instruction = token_program_preparation_mint(amount); + let instruction = Instruction::Mint { + amount_to_mint: amount, + }; let Ok(nonces) = self .0 @@ -481,7 +497,9 @@ impl Token<'_> { holder_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let instruction = token_program_preparation_mint(amount); + let instruction = Instruction::Mint { + amount_to_mint: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -510,7 +528,9 @@ impl Token<'_> { holder_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let instruction = token_program_preparation_mint(amount); + let instruction = Instruction::Mint { + amount_to_mint: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -541,7 +561,9 @@ impl Token<'_> { holder_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_mint(amount); + let instruction = Instruction::Mint { + amount_to_mint: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -570,7 +592,9 @@ impl Token<'_> { holder_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_mint(amount); + let instruction = Instruction::Mint { + amount_to_mint: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -600,7 +624,9 @@ impl Token<'_> { holder_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let instruction = token_program_preparation_mint(amount); + let instruction = Instruction::Mint { + amount_to_mint: amount, + }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -626,42 +652,3 @@ impl Token<'_> { }) } } - -fn token_program_preparation_transfer(amount: u128) -> Vec { - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || - // 0x00 || 0x00 || 0x00]. - let mut instruction = vec![0u8; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - instruction -} - -fn token_program_preparation_definition(name: [u8; 6], total_supply: u128) -> Vec { - // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] - let mut instruction = vec![0u8; 23]; - instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); - instruction[17..].copy_from_slice(&name); - - instruction -} - -fn token_program_preparation_burn(amount: u128) -> Vec { - // Instruction must be: [0x03 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || - // 0x00 || 0x00 || 0x00]. - let mut instruction = vec![0; 23]; - instruction[0] = 0x03; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - instruction -} - -fn token_program_preparation_mint(amount: u128) -> Vec { - // Instruction must be: [0x04 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || - // 0x00 || 0x00 || 0x00]. - let mut instruction = vec![0; 23]; - instruction[0] = 0x04; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - instruction -}