diff --git a/Cargo.lock b/Cargo.lock index 83ec4b3..0e3b0b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,42 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + [[package]] name = "agave-feature-set" version = "3.1.10" @@ -533,6 +569,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + [[package]] name = "bv" version = "0.11.1" @@ -606,6 +648,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -691,9 +743,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -854,7 +916,9 @@ dependencies = [ "mollusk-svm", "mollusk-svm-programs-token", "solana-account 3.4.0", + "solana-program-pack", "solana-sdk", + "spl-token-2022-interface", "spl-token-interface", ] @@ -1128,8 +1192,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1241,6 +1307,15 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1304,6 +1379,16 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "js-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "k256" version = "0.13.4" @@ -1449,6 +1534,18 @@ dependencies = [ "autocfg", ] +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1761,7 +1858,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06810dac15a4ef83d3dabdb4f2f22fb39c9adff669cd2781da4f716510a647c" dependencies = [ "solana-account-view 1.0.0", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-define-syscall 4.0.1", "solana-instruction-view 1.0.0", "solana-program-error", @@ -1774,7 +1871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "febf3bbe37f4e2723b9b41a1768c6542a1ae1b1d7bcac27f892f30cabcf70ec4" dependencies = [ "solana-account-view 1.0.0", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-instruction-view 1.0.0", "solana-program-error", ] @@ -1785,7 +1882,7 @@ version = "0.2.0" source = "git+https://github.com/anza-xyz/pinocchio?branch=main#009301423f920fd105bd32a25560d127b6f0bf4f" dependencies = [ "solana-account-view 2.0.0", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-instruction-view 2.0.0", "solana-program-error", ] @@ -1800,6 +1897,18 @@ dependencies = [ "spki", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -2186,6 +2295,19 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.9.9" @@ -2319,13 +2441,13 @@ dependencies = [ [[package]] name = "solana-account-info" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" +checksum = "a9cf16495d9eb53e3d04e72366a33bb1c20c24e78c171d8b8f5978357b63ae95" dependencies = [ "bincode", "serde_core", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-program-error", "solana-program-memory", ] @@ -2336,7 +2458,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37ca34c37f92ee341b73d5ce7c8ef5bb38e9a87955b4bd343c63fa18b149215" dependencies = [ - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-program-error", ] @@ -2346,7 +2468,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc141b940560430425ebaadb7645496c45f6a10fad9911d719bd03eab7f4d422" dependencies = [ - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-program-error", ] @@ -2356,14 +2478,14 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" dependencies = [ - "solana-address 2.3.0", + "solana-address 2.5.0", ] [[package]] name = "solana-address" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500b83d41bda401b84ebff6033e2e7bc828870ea444805112d15fc0a3e470b9c" +checksum = "5f08236dacd0e6dc8234becef58e27c8567856644ef509d7e97957d55a91dc72" dependencies = [ "borsh", "bytemuck", @@ -2377,6 +2499,7 @@ dependencies = [ "sha2-const-stable", "solana-atomic-u64", "solana-define-syscall 5.0.0", + "solana-nullable", "solana-program-error", "solana-sanitize", "solana-sha256-hasher", @@ -2589,7 +2712,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee8beac9bff4db9225e57d532d169b0be5e447f1e6601a2f50f27a01bf5518f" dependencies = [ "siphasher", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-hash 4.2.0", ] @@ -2698,9 +2821,9 @@ dependencies = [ [[package]] name = "solana-instruction" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a6d22d0a6fdf345be294bb9afdcd40c296cdc095e64e7ceaa3bb3c2f608c1c" +checksum = "a97881335fc698deb46c6571945969aae6d93a14e2fff792a368b4fac872f116" dependencies = [ "bincode", "borsh", @@ -2730,7 +2853,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60147e4d0a4620013df40bf30a86dd299203ff12fcb8b593cd51014fce0875d8" dependencies = [ "solana-account-view 1.0.0", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-define-syscall 4.0.1", "solana-program-error", ] @@ -2742,7 +2865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c35d02cd27575b1fd05938d3624e476b0173208139053b51aa48dd9bec149f1" dependencies = [ "solana-account-view 2.0.0", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-define-syscall 5.0.0", "solana-program-error", ] @@ -2787,7 +2910,7 @@ dependencies = [ "five8", "five8_core", "rand 0.9.2", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-derivation-path", "solana-seed-derivable", "solana-seed-phrase", @@ -2857,7 +2980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0448b1fd891c5f46491e5dc7d9986385ba3c852c340db2911dd29faa01d2b08d" dependencies = [ "lazy_static", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-hash 4.2.0", "solana-instruction", "solana-sanitize", @@ -2875,7 +2998,7 @@ dependencies = [ "lazy_static", "serde", "serde_derive", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-hash 4.2.0", "solana-instruction", "solana-sanitize", @@ -2926,6 +3049,15 @@ dependencies = [ "solana-sdk-ids", ] +[[package]] +name = "solana-nullable" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da028344c595c7416769ff648d206de7962571291a4cea24c38a60b6f40d53bb" +dependencies = [ + "bytemuck", +] + [[package]] name = "solana-offchain-message" version = "3.0.0" @@ -3140,7 +3272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b06bd918d60111ee1f97de817113e2040ca0cedb740099ee8d646233f6b906c" dependencies = [ "rand 0.9.2", - "solana-address 2.3.0", + "solana-address 2.5.0", ] [[package]] @@ -3253,7 +3385,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" dependencies = [ - "solana-address 2.3.0", + "solana-address 2.5.0", ] [[package]] @@ -3530,7 +3662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a95a6f2e23ed861d6444ad4a6d6896c418d7d101b960787e65a8e33157cee81b" dependencies = [ "num-traits", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-msg", "solana-program-error", ] @@ -3633,7 +3765,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" dependencies = [ - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-sdk-ids", ] @@ -3649,7 +3781,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96697cff5075a028265324255efed226099f6d761ca67342b230d09f72cc48d2" dependencies = [ - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-hash 4.2.0", "solana-instruction", "solana-instruction-error", @@ -3668,7 +3800,7 @@ checksum = "9dc0d18f4f109cc1777459271800755705ca6d1aba319934611e1d4f6bb162b5" dependencies = [ "serde", "serde_derive", - "solana-address 2.3.0", + "solana-address 2.5.0", "solana-hash 4.2.0", "solana-instruction", "solana-instruction-error", @@ -3712,6 +3844,54 @@ dependencies = [ "solana-sanitize", ] +[[package]] +name = "solana-zero-copy" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f52dd8f733a13f6a18e55de83cf97c4c3f5fdf27ea3830bcff0b35313efcc2" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", +] + +[[package]] +name = "solana-zk-sdk" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9602bcb1f7af15caef92b91132ec2347e1c51a72ecdbefdaefa3eac4b8711475" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "getrandom 0.2.17", + "itertools 0.12.1", + "js-sys", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.18", + "wasm-bindgen", + "zeroize", +] + [[package]] name = "spki" version = "0.7.3" @@ -3732,6 +3912,140 @@ dependencies = [ "solana-pubkey 3.0.0", ] +[[package]] +name = "spl-discriminator" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e597c5ff9ed7c74a54dbc47bae2f06e4db8c98f4356ad280200dc11878266db1" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.117", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.9", + "syn 2.0.117", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-pod" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f9c6e142cdf1e7e77f480053ec9f0ce989890768ddf91f619b50f39d1b456f5" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "num-derive", + "num-traits", + "num_enum", + "solana-program-error", + "solana-program-option", + "solana-pubkey 3.0.0", + "solana-zero-copy", + "solana-zk-sdk", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-2022-interface" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcd81188211f4b3c8a5eba7fd534c7142f9dd026123b3472492782cc72f4dc6" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-type-length-value", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879a9ebad0d77383d3ea71e7de50503554961ff0f4ef6cbca39ad126e6f6da3a" +dependencies = [ + "bytemuck", + "solana-account-info", + "solana-curve25519", + "solana-instruction", + "solana-instructions-sysvar", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0cd59fce3dc00f563c6fa364d67c3f200d278eae681f4dc250240afcfe044b1" +dependencies = [ + "curve25519-dalek", + "solana-zk-sdk", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841cbd6f2322d02719be4da1affedbe6495b1048b7b985ec9796032564026e22" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-address 2.5.0", + "solana-instruction", + "solana-nullable", + "solana-program-error", + "solana-zero-copy", + "spl-discriminator", + "thiserror 2.0.18", +] + [[package]] name = "spl-token-interface" version = "2.0.0" @@ -3752,6 +4066,42 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "spl-token-metadata-interface" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c467c7c3bd056f8fe60119e7ec34ddd6f23052c2fa8f1f51999098063b72676" +dependencies = [ + "borsh", + "num-derive", + "num-traits", + "solana-borsh", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "spl-discriminator", + "spl-pod", + "spl-type-length-value", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-type-length-value" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2504631748c48d2a937414d64a12dcac4588d34bd07d355d648619c189d29435" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-program-error", + "solana-zero-copy", + "spl-discriminator", + "thiserror 2.0.18", +] + [[package]] name = "strsim" version = "0.11.1" @@ -3883,6 +4233,16 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unreachable" version = "1.0.0" @@ -3982,6 +4342,51 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +dependencies = [ + "unicode-ident", +] + [[package]] name = "webpki-roots" version = "1.0.6" @@ -4015,9 +4420,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wincode" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc91ddd8c932a38bbec58ed536d9e93ce9cd01b6af9b6de3c501132cf98ddec6" +checksum = "657690780ce23e6f66576a782ffd88eb353512381817029cc1d7a99154bb6d1f" dependencies = [ "pastey", "proc-macro2", @@ -4181,3 +4586,9 @@ dependencies = [ "quote", "syn 2.0.117", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index db3bfc5..68bb7ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,10 @@ pinocchio-token-2022 = {git = "https://github.com/anza-xyz/pinocchio", branch = proc-macro2 = "1.0.106" quote = "1.0.45" solana-account = "3.2" +solana-program-pack = "3.1" solana-sbpf = "0.16.0" solana-sdk = "4.0.1" +spl-token-2022-interface = "2.1.0" spl-token-interface = "2.0.0" syn = {version = "2.0.117", features = ["full"]} ureq = "3.3.0" diff --git a/docs/algorithms/INIT-MARKET-PDA.tex b/docs/algorithms/INIT-MARKET-PDA.tex index 9ba2f89..8b42ff7 100644 --- a/docs/algorithms/INIT-MARKET-PDA.tex +++ b/docs/algorithms/INIT-MARKET-PDA.tex @@ -11,7 +11,7 @@ \INPUT $r_{10}$ = frame \COMMENT{Pointer to shifted input buffer for quote mint offsets.} \REQUIRE frame.input\_shifted - \REQUIRE *frame.system\_program\_id = input.system\_program.address + \REQUIRE frame.system\_program\_id = \&input.system\_program.address \REQUIRE frame.cpi[0].info.data\_len = \texttt{data.LEN\_ZERO} \REQUIRE frame.cpi[1].info.data\_len = \texttt{data.LEN\_ZERO} \ENSURE $r_9$ = acct diff --git a/docs/algorithms/INIT-VAULT.tex b/docs/algorithms/INIT-VAULT.tex index affa6cd..fa6f5fe 100644 --- a/docs/algorithms/INIT-VAULT.tex +++ b/docs/algorithms/INIT-VAULT.tex @@ -13,23 +13,28 @@ \texttt{true}, \texttt{false} \} - \REQUIRE *frame.mint $\in$ \{ + \REQUIRE frame.mint $\in$ \{ input.base\_mint, input\_shifted.quote\_mint \} \REQUIRE frame.token\_program\_id \REQUIRE frame.program\_id \REQUIRE frame.input + \REQUIRE frame.rent \REQUIRE frame.lamports\_per\_byte \REQUIRE frame.pda\_seeds[0].len = \texttt{Address.size} \REQUIRE frame.pda\_seeds[2].addr = \&frame.bump \REQUIRE frame.pda\_seeds[2].len = \texttt{u8.size} - \REQUIRE *frame.system\_program\_id = input.system\_program.address + \REQUIRE frame.system\_program\_id = \&input.system\_program.address \REQUIRE frame.signers\_seeds.addr = \&frame.pda\_seeds \REQUIRE frame.signers\_seeds.len = \texttt{RegisterMarketFrame.PDA\_SEEDS\_N\_SEEDS} \REQUIRE input.user.data\_len = \texttt{data.LEN\_ZERO} \REQUIRE acct.data\_len = \texttt{data.LEN\_ZERO} \REQUIRE frame.cpi[0].info.executable = \texttt{false} + \REQUIRE frame.cpi[2].info.is\_signer = \texttt{false} + \REQUIRE frame.cpi[2].info.is\_writable = \texttt{false} + \REQUIRE frame.cpi[2].meta.is\_signer = \texttt{false} + \REQUIRE frame.cpi[2].meta.is\_writable = \texttt{false} \FUNCTION{INIT-VAULT}{acct, frame} \STATE \CALL{Store}{frame} \STATE \CALL{Store}{acct} @@ -73,7 +78,7 @@ \texttt{token.GET\_ACCOUNT\_DATA\_SIZE\_DISC} \STATE frame.sol\_instruction.data = \&frame.get\_account\_data\_size\_data \STATE frame.sol\_instruction.data\_len = \texttt{u8.size} - \COMMENT{Invoke GetAccountDataSize CPI (no signers).} + \COMMENT{Invoke GetAccountDataSize CPI.} \STATE syscall.instruction = \&frame.sol\_instruction \STATE syscall.account\_infos = \&frame.cpi[0].info \STATE syscall.account\_infos\_len = @@ -134,6 +139,50 @@ \STATE syscall.seeds = \&frame.signers\_seeds \STATE syscall.seeds\_len = \texttt{register\_misc.N\_PDA\_SIGNERS} \STATE \CALL{sol-invoke-signed-c}{} + \COMMENT{Assign CPI account fields for vault.} + \STATE frame.cpi[0].meta.pubkey = \&acct.address + \STATE frame.cpi[0].info.key = \&acct.address + \STATE frame.cpi[0].info.owner = \&acct.owner + \STATE frame.cpi[0].info.lamports = \&acct.lamports + \STATE frame.cpi[0].info.data = \&acct.data + \STATE frame.cpi[0].info.data\_len = acct.data\_len + \COMMENT{Assign CPI account fields for mint.} + \STATE mint = frame.mint + \STATE frame.cpi[1].info.is\_signer = \texttt{false} + \STATE frame.cpi[1].info.is\_writable = \texttt{false} + \STATE frame.cpi[1].meta.is\_signer = \texttt{false} + \STATE frame.cpi[1].meta.is\_writable = \texttt{false} + \STATE frame.cpi[1].meta.pubkey = \&mint.address + \STATE frame.cpi[1].info.key = \&mint.address + \STATE frame.cpi[1].info.owner = \&mint.owner + \STATE frame.cpi[1].info.lamports = \&mint.lamports + \STATE frame.cpi[1].info.data = \&mint.data + \STATE frame.cpi[1].info.data\_len = mint.data\_len + \COMMENT{Assign CPI account fields for Rent sysvar.} + \STATE rent = frame.rent + \STATE frame.cpi[2].meta.pubkey = \&rent.address + \STATE frame.cpi[2].info.key = \&rent.address + \STATE frame.cpi[2].info.owner = \&rent.owner + \STATE frame.cpi[2].info.lamports = \&rent.lamports + \STATE frame.cpi[2].info.data = \&rent.data + \STATE frame.cpi[2].info.data\_len = rent.data\_len + \COMMENT{Populate SolInstruction for InitializeAccount2.} + \STATE frame.sol\_instruction.program\_id = frame.token\_program\_id + \STATE frame.sol\_instruction.accounts = \&frame.cpi.account\_metas + \STATE frame.sol\_instruction.account\_len = + \texttt{token.INITIALIZE\_ACCOUNT\_2\_N\_ACCOUNTS} + \STATE frame.initialize\_account\_2\_data.discriminant = + \texttt{token.INITIALIZE\_ACCOUNT\_2\_DISC} + \STATE frame.initialize\_account\_2\_data.proprietor = input.market.address + \STATE frame.sol\_instruction.data = \&frame.initialize\_account\_2\_data + \STATE frame.sol\_instruction.data\_len = \texttt{InitializeAccount2.size} + \COMMENT{Invoke InitializeAccount2 CPI.} + \STATE syscall.instruction = \&frame.sol\_instruction + \STATE syscall.account\_infos = \&frame.cpi.account\_infos + \STATE syscall.account\_infos\_len = + \texttt{token.INITIALIZE\_ACCOUNT\_2\_N\_ACCOUNTS} + \STATE syscall.seeds\_len = \texttt{token.INITIALIZE\_ACCOUNT\_2\_N\_SEEDS} + \STATE \CALL{sol-invoke-signed-c}{} \ENDFUNCTION \end{algorithmic} \end{algorithm} diff --git a/docs/algorithms/REGISTER-MARKET.tex b/docs/algorithms/REGISTER-MARKET.tex index 5ca59cf..57e2a1a 100644 --- a/docs/algorithms/REGISTER-MARKET.tex +++ b/docs/algorithms/REGISTER-MARKET.tex @@ -64,6 +64,7 @@ \IF{acct.address $\neq$ \texttt{pubkey.RENT}} \RETURN \texttt{ErrorCode::InvalidRentSysvarPubkey} \ENDIF + \STATE frame.rent = acct \COMMENT{Derive market PDA, populate CPI fields, invoke CreateAccount.} \STATE \CALL{INIT-MARKET-PDA}{input, insn, acct, frame} \COMMENT{Retrieve input buffer pointers and advance to base token program account.} diff --git a/docs/src/program/layout.md b/docs/src/program/layout.md index 1373884..7b92134 100644 --- a/docs/src/program/layout.md +++ b/docs/src/program/layout.md @@ -95,7 +95,7 @@ emits the same set of constants with a `_UOFF` suffix instead of `_OFF`. ### Token -SPL Token constants (account size, instruction discriminators) are injected +SPL Token constants (account size, instruction discriminants) are injected from the [`token`][token-mod] module via [`constant_group!`][bs-constant-group]: diff --git a/interface/src/market.rs b/interface/src/market.rs index 2132828..ecd1ba9 100644 --- a/interface/src/market.rs +++ b/interface/src/market.rs @@ -5,6 +5,7 @@ use crate::memory::EmptyAccount; use crate::memory::StackNode; use crate::order::Order; use crate::seat::Seat; +use crate::token::InitializeAccount2; use dropset_macros::{ constant_group, cpi_accounts, frame, instruction_accounts, instruction_data, signer_seeds, svm_data, @@ -110,7 +111,7 @@ pub enum RegisterMarketAccounts { /// CPI instruction data for CreateAccount. pub struct CreateAccountData { /// Zero-initialized on stack. - pub discriminator: u32, + pub discriminant: u32, pub lamports: u64, pub space: u64, /// Zero-initialized on stack. @@ -162,6 +163,8 @@ pub struct RegisterMarketFrame { pub token_account_data_size: u64, /// Pointer to mint account for vault initialization. pub mint: *const RuntimeAccount, + /// Pointer to Rent sysvar account. + pub rent: *const RuntimeAccount, /// Signer seeds for PDA derivation and CPI signing. pub pda_seeds: PDASignerSeeds, /// From `sol_try_find_program_address`. @@ -174,6 +177,8 @@ pub struct RegisterMarketFrame { pub get_return_data_program_id: Address, /// CPI instruction data for CreateAccount. pub create_account_data: CreateAccountData, + /// CPI instruction data for InitializeAccount2. + pub initialize_account_2_data: InitializeAccount2, /// GetAccountDataSize CPI instruction data. pub get_account_data_size_data: u8, /// CPI accounts for CreateAccount and InitializeAccount2. @@ -210,6 +215,8 @@ constant_group! { TOKEN_ACCOUNT_DATA_SIZE = offset!(token_account_data_size), /// Pointer to mint account for vault initialization. MINT = offset!(mint), + /// Pointer to Rent sysvar account. + RENT = offset!(rent), /// PDA signer seeds. PDA_SEEDS = signer_seeds!(pda_seeds), /// PDA address. @@ -228,6 +235,12 @@ constant_group! { CREATE_ACCT_SPACE = unaligned_offset!(create_account_data.space), /// Owner field within CreateAccount instruction data. CREATE_ACCT_OWNER = unaligned_pubkey_offsets!(create_account_data.owner), + /// InitializeAccount2 CPI instruction data. + INIT_ACCT_2_DATA = offset!(initialize_account_2_data), + /// Discriminant field within InitializeAccount2 instruction data. + INIT_ACCT_2_DISC = unaligned_offset!(initialize_account_2_data.discriminant), + /// Proprietor field within InitializeAccount2 instruction data. + INIT_ACCT_2_PROPRIETOR = unaligned_pubkey_offsets!(initialize_account_2_data.proprietor), /// GetAccountDataSize CPI instruction data. GET_ACCOUNT_DATA_SIZE_DATA = unaligned_offset!(get_account_data_size_data), /// CPI accounts. diff --git a/interface/src/memory.rs b/interface/src/memory.rs index 302b95e..8f2f892 100644 --- a/interface/src/memory.rs +++ b/interface/src/memory.rs @@ -1,4 +1,5 @@ use crate::market::{CreateAccountData, MarketHeader}; +use crate::token::InitializeAccount2; use dropset_macros::{constant_group, size_of_group, svm_data}; use pinocchio::Address; use pinocchio::account::{MAX_PERMITTED_DATA_INCREASE, RuntimeAccount}; @@ -129,7 +130,7 @@ constant_group! { // region: size_of_group_example size_of_group! { #[inject("common/memory")] - [u8, u64, Address, EmptyAccount, MarketHeader, CreateAccountData] + [u8, u64, Address, EmptyAccount, MarketHeader, CreateAccountData, InitializeAccount2] } // endregion: size_of_group_example diff --git a/interface/src/token.rs b/interface/src/token.rs index 2690c56..c3c2178 100644 --- a/interface/src/token.rs +++ b/interface/src/token.rs @@ -1,8 +1,17 @@ -use dropset_macros::constant_group; +use dropset_macros::{constant_group, svm_data}; +use pinocchio::Address; use pinocchio_token::state::TokenAccount; // pinocchio-token does not export GetAccountDataSize yet. use pinocchio_token_2022::instructions::GetAccountDataSize; +#[svm_data] +/// CPI instruction data for InitializeAccount2. +pub struct InitializeAccount2 { + pub discriminant: u8, + /// In this implementation, the market PDA. + pub proprietor: Address, +} + constant_group! { #[prefix("TOKEN")] #[inject("common/token")] @@ -10,11 +19,18 @@ constant_group! { token { /// Size of a token account (SPL Token and Token 2022 base). ACCOUNT_SIZE = immediate!(TokenAccount::LEN), - /// GetAccountDataSize instruction discriminator (Token 2022). + /// GetAccountDataSize instruction discriminant (Token 2022). GET_ACCOUNT_DATA_SIZE_DISC = immediate!(GetAccountDataSize::DISCRIMINATOR), /// GetAccountDataSize number of accounts. GET_ACCOUNT_DATA_SIZE_N_ACCOUNTS = immediate!(1), /// GetAccountDataSize number of seeds. GET_ACCOUNT_DATA_SIZE_N_SEEDS = immediate!(0), + /// InitializeAccount2 instruction discriminant. + // Not exported by token program: https://github.com/anza-xyz/pinocchio/issues/384 + INITIALIZE_ACCOUNT_2_DISC = immediate!(16), + /// InitializeAccount2 number of accounts. + INITIALIZE_ACCOUNT_2_N_ACCOUNTS = immediate!(3), + /// InitializeAccount2 number of seeds. + INITIALIZE_ACCOUNT_2_N_SEEDS = immediate!(0), } } diff --git a/program/src/dropset/common/memory.s b/program/src/dropset/common/memory.s index e379a84..f4d66d7 100644 --- a/program/src/dropset/common/memory.s +++ b/program/src/dropset/common/memory.s @@ -81,3 +81,4 @@ .equ SIZE_OF_EMPTY_ACCOUNT, 10336 # Size of EmptyAccount in bytes. .equ SIZE_OF_MARKET_HEADER, 43 # Size of MarketHeader in bytes. .equ SIZE_OF_CREATE_ACCOUNT_DATA, 56 # Size of CreateAccountData in bytes. +.equ SIZE_OF_INITIALIZE_ACCOUNT2, 33 # Size of InitializeAccount2 in bytes. diff --git a/program/src/dropset/common/token.s b/program/src/dropset/common/token.s index c91133a..c46c7f7 100644 --- a/program/src/dropset/common/token.s +++ b/program/src/dropset/common/token.s @@ -2,10 +2,16 @@ # ------------------------------------------------------------------------- # Size of a token account (SPL Token and Token 2022 base). .equ TOKEN_ACCOUNT_SIZE, 165 -# GetAccountDataSize instruction discriminator (Token 2022). +# GetAccountDataSize instruction discriminant (Token 2022). .equ TOKEN_GET_ACCOUNT_DATA_SIZE_DISC, 21 # GetAccountDataSize number of accounts. .equ TOKEN_GET_ACCOUNT_DATA_SIZE_N_ACCOUNTS, 1 # GetAccountDataSize number of seeds. .equ TOKEN_GET_ACCOUNT_DATA_SIZE_N_SEEDS, 0 +# InitializeAccount2 instruction discriminant. +.equ TOKEN_INITIALIZE_ACCOUNT_2_DISC, 16 +# InitializeAccount2 number of accounts. +.equ TOKEN_INITIALIZE_ACCOUNT_2_N_ACCOUNTS, 3 +# InitializeAccount2 number of seeds. +.equ TOKEN_INITIALIZE_ACCOUNT_2_N_SEEDS, 0 # ------------------------------------------------------------------------- diff --git a/program/src/dropset/market/init_vault.s b/program/src/dropset/market/init_vault.s index 0403bde..e2da5a4 100644 --- a/program/src/dropset/market/init_vault.s +++ b/program/src/dropset/market/init_vault.s @@ -213,6 +213,112 @@ init_vault_create_account: # syscall.seeds_len = register_misc.N_PDA_SIGNERS mov64 r5, RM_MISC_N_PDA_SIGNERS call sol_invoke_signed_c + # frame.cpi[0].meta.pubkey = &acct.address + # frame.cpi[0].info.key = &acct.address + mov64 r8, r7 + add64 r8, ACCT_ADDRESS_OFF + stxdw [r6 + RM_FM_CPI_IDX_0_ACCT_META_PUBKEY_UOFF], r8 + stxdw [r6 + RM_FM_CPI_IDX_0_ACCT_INFO_KEY_UOFF], r8 + # frame.cpi[0].info.owner = &acct.owner + add64 r8, IB_ADDRESS_TO_OWNER_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_0_ACCT_INFO_OWNER_UOFF], r8 + # frame.cpi[0].info.lamports = &acct.lamports + add64 r8, IB_OWNER_TO_LAMPORTS_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_0_ACCT_INFO_LAMPORTS_UOFF], r8 + # frame.cpi[0].info.data = &acct.data + add64 r8, IB_LAMPORTS_TO_DATA_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_0_ACCT_INFO_DATA_UOFF], r8 + # frame.cpi[0].info.data_len = acct.data_len + ldxdw r8, [r7 + ACCT_DATA_LEN_OFF] + stxdw [r6 + RM_FM_CPI_IDX_0_ACCT_INFO_DATA_LEN_UOFF], r8 + # mint = frame.mint + ldxdw r8, [r6 + RM_FM_MINT_OFF] + # frame.cpi[1].info.is_signer = false + # frame.cpi[1].info.is_writable = false + sth [r6 + RM_FM_CPI_IDX_1_ACCT_INFO_IS_SIGNER_UOFF], CPI_READONLY_NON_SIGNER + # frame.cpi[1].meta.is_writable = false + # frame.cpi[1].meta.is_signer = false + sth [r6 + RM_FM_CPI_IDX_1_ACCT_META_IS_WRITABLE_UOFF], CPI_READONLY_NON_SIGNER + # frame.cpi[1].meta.pubkey = &mint.address + # frame.cpi[1].info.key = &mint.address + mov64 r9, r8 + add64 r9, ACCT_ADDRESS_OFF + stxdw [r6 + RM_FM_CPI_IDX_1_ACCT_META_PUBKEY_UOFF], r9 + stxdw [r6 + RM_FM_CPI_IDX_1_ACCT_INFO_KEY_UOFF], r9 + # frame.cpi[1].info.owner = &mint.owner + add64 r9, IB_ADDRESS_TO_OWNER_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_1_ACCT_INFO_OWNER_UOFF], r9 + # frame.cpi[1].info.lamports = &mint.lamports + add64 r9, IB_OWNER_TO_LAMPORTS_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_1_ACCT_INFO_LAMPORTS_UOFF], r9 + # frame.cpi[1].info.data = &mint.data + add64 r9, IB_LAMPORTS_TO_DATA_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_1_ACCT_INFO_DATA_UOFF], r9 + # frame.cpi[1].info.data_len = mint.data_len + ldxdw r9, [r8 + ACCT_DATA_LEN_OFF] + stxdw [r6 + RM_FM_CPI_IDX_1_ACCT_INFO_DATA_LEN_UOFF], r9 + # rent = frame.rent + ldxdw r8, [r6 + RM_FM_RENT_OFF] + # frame.cpi[2].meta.pubkey = &rent.address + # frame.cpi[2].info.key = &rent.address + mov64 r9, r8 + add64 r9, ACCT_ADDRESS_OFF + stxdw [r6 + RM_FM_CPI_IDX_2_ACCT_META_PUBKEY_UOFF], r9 + stxdw [r6 + RM_FM_CPI_IDX_2_ACCT_INFO_KEY_UOFF], r9 + # frame.cpi[2].info.owner = &rent.owner + add64 r9, IB_ADDRESS_TO_OWNER_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_2_ACCT_INFO_OWNER_UOFF], r9 + # frame.cpi[2].info.lamports = &rent.lamports + add64 r9, IB_OWNER_TO_LAMPORTS_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_2_ACCT_INFO_LAMPORTS_UOFF], r9 + # frame.cpi[2].info.data = &rent.data + add64 r9, IB_LAMPORTS_TO_DATA_REL_OFF_IMM + stxdw [r6 + RM_FM_CPI_IDX_2_ACCT_INFO_DATA_UOFF], r9 + # frame.cpi[2].info.data_len = rent.data_len + ldxdw r9, [r8 + ACCT_DATA_LEN_OFF] + stxdw [r6 + RM_FM_CPI_IDX_2_ACCT_INFO_DATA_LEN_UOFF], r9 + # Populate SolInstruction for InitializeAccount2. + # frame.sol_instruction.program_id = frame.token_program_id + ldxdw r8, [r6 + RM_FM_TOKEN_PROGRAM_ID_OFF] + stxdw [r6 + RM_FM_SOL_INSN_PROGRAM_ID_UOFF], r8 + # frame.sol_instruction.accounts = &frame.cpi.account_metas + mov64 r8, r6 + add64 r8, RM_FM_CPI_IDX_0_ACCT_META_PUBKEY_UOFF + stxdw [r6 + RM_FM_SOL_INSN_ACCOUNTS_UOFF], r8 + # frame.sol_instruction.account_len = token.INITIALIZE_ACCOUNT_2_N_ACCOUNTS + mov64 r8, TOKEN_INITIALIZE_ACCOUNT_2_N_ACCOUNTS + stxdw [r6 + RM_FM_SOL_INSN_ACCOUNT_LEN_UOFF], r8 + # frame.initialize_account_2_data.discriminant = token.INITIALIZE_ACCOUNT_2_DISC + stb [r6 + RM_FM_INIT_ACCT_2_DISC_UOFF], TOKEN_INITIALIZE_ACCOUNT_2_DISC + # frame.initialize_account_2_data.proprietor = input.market.address + ldxdw r8, [r6 + RM_FM_INPUT_OFF] + add64 r8, IB_MARKET_PUBKEY_OFF + ldxdw r9, [r8 + PUBKEY_CHUNK_0_OFF] + stxdw [r6 + RM_FM_INIT_ACCT_2_PROPRIETOR_CHUNK_0_UOFF], r9 + ldxdw r9, [r8 + PUBKEY_CHUNK_1_OFF] + stxdw [r6 + RM_FM_INIT_ACCT_2_PROPRIETOR_CHUNK_1_UOFF], r9 + ldxdw r9, [r8 + PUBKEY_CHUNK_2_OFF] + stxdw [r6 + RM_FM_INIT_ACCT_2_PROPRIETOR_CHUNK_2_UOFF], r9 + ldxdw r9, [r8 + PUBKEY_CHUNK_3_OFF] + stxdw [r6 + RM_FM_INIT_ACCT_2_PROPRIETOR_CHUNK_3_UOFF], r9 + # frame.sol_instruction.data = &frame.initialize_account_2_data + mov64 r8, r6 + add64 r8, RM_FM_INIT_ACCT_2_DATA_OFF + stxdw [r6 + RM_FM_SOL_INSN_DATA_UOFF], r8 + # frame.sol_instruction.data_len = InitializeAccount2.size + mov64 r8, SIZE_OF_INITIALIZE_ACCOUNT2 + stxdw [r6 + RM_FM_SOL_INSN_DATA_LEN_UOFF], r8 + # syscall.instruction = &frame.sol_instruction + mov64 r1, r6 + add64 r1, RM_FM_SOL_INSN_OFF + # syscall.account_infos = &frame.cpi.account_infos + mov64 r2, r6 + add64 r2, RM_FM_CPI_SOL_ACCT_INFO_OFF + # syscall.account_infos_len = token.INITIALIZE_ACCOUNT_2_N_ACCOUNTS + mov64 r3, TOKEN_INITIALIZE_ACCOUNT_2_N_ACCOUNTS + # syscall.seeds_len = token.INITIALIZE_ACCOUNT_2_N_SEEDS + mov64 r5, TOKEN_INITIALIZE_ACCOUNT_2_N_SEEDS + call sol_invoke_signed_c exit init_vault_invalid_pda: # if frame.vault_index == register_misc.VAULT_INDEX_BASE diff --git a/program/src/dropset/market/register.s b/program/src/dropset/market/register.s index 3ed1f3c..97caa92 100644 --- a/program/src/dropset/market/register.s +++ b/program/src/dropset/market/register.s @@ -24,57 +24,72 @@ # Stack frame for REGISTER-MARKET. # ------------------------------------------------------------------------- -.equ RM_FM_TOKEN_PROGRAM_ID_OFF, -552 # Pointer to token program address. -.equ RM_FM_PROGRAM_ID_OFF, -544 # Pointer to program ID in input buffer. -.equ RM_FM_INPUT_OFF, -536 # Saved input buffer pointer. -.equ RM_FM_INPUT_SHIFTED_OFF, -528 # Saved input_shifted pointer. -.equ RM_FM_LAMPORTS_PER_BYTE_OFF, -520 # From Rent sysvar. +.equ RM_FM_TOKEN_PROGRAM_ID_OFF, -592 # Pointer to token program address. +.equ RM_FM_PROGRAM_ID_OFF, -584 # Pointer to program ID in input buffer. +.equ RM_FM_INPUT_OFF, -576 # Saved input buffer pointer. +.equ RM_FM_INPUT_SHIFTED_OFF, -568 # Saved input_shifted pointer. +.equ RM_FM_LAMPORTS_PER_BYTE_OFF, -560 # From Rent sysvar. # Return value from GetAccountDataSize CPI, to check token account data size at runtime. -.equ RM_FM_TOKEN_ACCOUNT_DATA_SIZE_OFF, -512 +.equ RM_FM_TOKEN_ACCOUNT_DATA_SIZE_OFF, -552 # Pointer to mint account for vault initialization. -.equ RM_FM_MINT_OFF, -504 -.equ RM_FM_PDA_SEEDS_OFF, -496 # Signer seeds offset. +.equ RM_FM_MINT_OFF, -544 +.equ RM_FM_RENT_OFF, -536 # Pointer to Rent sysvar account. +.equ RM_FM_PDA_SEEDS_OFF, -528 # Signer seeds offset. .equ RM_FM_PDA_SEEDS_N_SEEDS, 3 # Number of signer seeds. -.equ RM_FM_PDA_SEEDS_IDX_0_ADDR_OFF, -496 # Idx 0 signer seed address. -.equ RM_FM_PDA_SEEDS_IDX_0_LEN_OFF, -488 # Idx 0 signer seed length. -.equ RM_FM_PDA_SEEDS_IDX_1_ADDR_OFF, -480 # Idx 1 signer seed address. -.equ RM_FM_PDA_SEEDS_IDX_1_LEN_OFF, -472 # Idx 1 signer seed length. -.equ RM_FM_PDA_SEEDS_IDX_2_ADDR_OFF, -464 # Idx 2 signer seed address. -.equ RM_FM_PDA_SEEDS_IDX_2_LEN_OFF, -456 # Idx 2 signer seed length. -.equ RM_FM_PDA_OFF, -448 # PDA address. -.equ RM_FM_PDA_CHUNK_0_OFF, -448 # PDA address (chunk 0). -.equ RM_FM_PDA_CHUNK_1_OFF, -440 # PDA address (chunk 1). -.equ RM_FM_PDA_CHUNK_2_OFF, -432 # PDA address (chunk 2). -.equ RM_FM_PDA_CHUNK_3_OFF, -424 # PDA address (chunk 3). -.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_OFF, -416 # System Program pubkey. +.equ RM_FM_PDA_SEEDS_IDX_0_ADDR_OFF, -528 # Idx 0 signer seed address. +.equ RM_FM_PDA_SEEDS_IDX_0_LEN_OFF, -520 # Idx 0 signer seed length. +.equ RM_FM_PDA_SEEDS_IDX_1_ADDR_OFF, -512 # Idx 1 signer seed address. +.equ RM_FM_PDA_SEEDS_IDX_1_LEN_OFF, -504 # Idx 1 signer seed length. +.equ RM_FM_PDA_SEEDS_IDX_2_ADDR_OFF, -496 # Idx 2 signer seed address. +.equ RM_FM_PDA_SEEDS_IDX_2_LEN_OFF, -488 # Idx 2 signer seed length. +.equ RM_FM_PDA_OFF, -480 # PDA address. +.equ RM_FM_PDA_CHUNK_0_OFF, -480 # PDA address (chunk 0). +.equ RM_FM_PDA_CHUNK_1_OFF, -472 # PDA address (chunk 1). +.equ RM_FM_PDA_CHUNK_2_OFF, -464 # PDA address (chunk 2). +.equ RM_FM_PDA_CHUNK_3_OFF, -456 # PDA address (chunk 3). +.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_OFF, -448 # System Program pubkey. # System Program pubkey (chunk 0). -.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_CHUNK_0_OFF, -416 +.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_CHUNK_0_OFF, -448 # System Program pubkey (chunk 1). -.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_CHUNK_1_OFF, -408 +.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_CHUNK_1_OFF, -440 # System Program pubkey (chunk 2). -.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_CHUNK_2_OFF, -400 +.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_CHUNK_2_OFF, -432 # System Program pubkey (chunk 3). -.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_CHUNK_3_OFF, -392 -.equ RM_FM_SYSTEM_PROGRAM_ID_OFF, -384 # System Program ID in input buffer. +.equ RM_FM_SYSTEM_PROGRAM_PUBKEY_CHUNK_3_OFF, -424 +.equ RM_FM_SYSTEM_PROGRAM_ID_OFF, -416 # System Program ID in input buffer. # Get return data program ID for CPI calls. -.equ RM_FM_GET_RETURN_DATA_PROGRAM_ID_OFF, -376 -.equ RM_FM_CREATE_ACCT_DATA_OFF, -344 # CreateAccount instruction data. +.equ RM_FM_GET_RETURN_DATA_PROGRAM_ID_OFF, -408 +.equ RM_FM_CREATE_ACCT_DATA_OFF, -376 # CreateAccount instruction data. # Lamports field within CreateAccount instruction data. -.equ RM_FM_CREATE_ACCT_LAMPORTS_UOFF, -340 +.equ RM_FM_CREATE_ACCT_LAMPORTS_UOFF, -372 # Space field within CreateAccount instruction data. -.equ RM_FM_CREATE_ACCT_SPACE_UOFF, -332 +.equ RM_FM_CREATE_ACCT_SPACE_UOFF, -364 # Owner field within CreateAccount instruction data. -.equ RM_FM_CREATE_ACCT_OWNER_UOFF, -324 +.equ RM_FM_CREATE_ACCT_OWNER_UOFF, -356 # Owner field within CreateAccount instruction data (chunk 0). -.equ RM_FM_CREATE_ACCT_OWNER_CHUNK_0_UOFF, -324 +.equ RM_FM_CREATE_ACCT_OWNER_CHUNK_0_UOFF, -356 # Owner field within CreateAccount instruction data (chunk 1). -.equ RM_FM_CREATE_ACCT_OWNER_CHUNK_1_UOFF, -316 +.equ RM_FM_CREATE_ACCT_OWNER_CHUNK_1_UOFF, -348 # Owner field within CreateAccount instruction data (chunk 2). -.equ RM_FM_CREATE_ACCT_OWNER_CHUNK_2_UOFF, -308 +.equ RM_FM_CREATE_ACCT_OWNER_CHUNK_2_UOFF, -340 # Owner field within CreateAccount instruction data (chunk 3). -.equ RM_FM_CREATE_ACCT_OWNER_CHUNK_3_UOFF, -300 +.equ RM_FM_CREATE_ACCT_OWNER_CHUNK_3_UOFF, -332 +# InitializeAccount2 CPI instruction data. +.equ RM_FM_INIT_ACCT_2_DATA_OFF, -320 +# Discriminant field within InitializeAccount2 instruction data. +.equ RM_FM_INIT_ACCT_2_DISC_UOFF, -320 +# Proprietor field within InitializeAccount2 instruction data. +.equ RM_FM_INIT_ACCT_2_PROPRIETOR_UOFF, -319 +# Proprietor field within InitializeAccount2 instruction data (chunk 0). +.equ RM_FM_INIT_ACCT_2_PROPRIETOR_CHUNK_0_UOFF, -319 +# Proprietor field within InitializeAccount2 instruction data (chunk 1). +.equ RM_FM_INIT_ACCT_2_PROPRIETOR_CHUNK_1_UOFF, -311 +# Proprietor field within InitializeAccount2 instruction data (chunk 2). +.equ RM_FM_INIT_ACCT_2_PROPRIETOR_CHUNK_2_UOFF, -303 +# Proprietor field within InitializeAccount2 instruction data (chunk 3). +.equ RM_FM_INIT_ACCT_2_PROPRIETOR_CHUNK_3_UOFF, -295 # GetAccountDataSize CPI instruction data. -.equ RM_FM_GET_ACCOUNT_DATA_SIZE_DATA_UOFF, -288 +.equ RM_FM_GET_ACCOUNT_DATA_SIZE_DATA_UOFF, -287 .equ RM_FM_CPI_N_ACCOUNTS, 3 # Number of CPI accounts. .equ RM_FM_CPI_SOL_ACCT_INFO_OFF, -280 # Start of SolAccountInfo vector. .equ RM_FM_CPI_SOL_ACCT_META_OFF, -112 # Start of SolAccountMeta vector. @@ -154,11 +169,11 @@ # Whether the current token program is Token 2022. .equ RM_FM_TOKEN_PROGRAM_IS_2022_UOFF, -6 # From pda_seeds to sol_instruction. -.equ RM_FM_PDA_SEEDS_TO_SOL_INSN_REL_OFF_IMM, 448 +.equ RM_FM_PDA_SEEDS_TO_SOL_INSN_REL_OFF_IMM, 480 # From pda to signers_seeds. -.equ RM_FM_PDA_TO_SIGNERS_SEEDS_REL_OFF_IMM, 384 +.equ RM_FM_PDA_TO_SIGNERS_SEEDS_REL_OFF_IMM, 416 # From create_account_data to CPI account metas. -.equ RM_FM_CREATE_ACCT_DATA_TO_CPI_ACCT_METAS_REL_OFF_IMM, 232 +.equ RM_FM_CREATE_ACCT_DATA_TO_CPI_ACCT_METAS_REL_OFF_IMM, 264 # ------------------------------------------------------------------------- # Miscellaneous market registration constants. @@ -303,6 +318,8 @@ register_market: # (1 CU) replaces lddw (2 CUs). mov32 r8, PUBKEY_RENT_CHUNK_3_LO jne r7, r8, e_invalid_rent_sysvar_pubkey + # frame.rent = acct + stxdw [r10 + RM_FM_RENT_OFF], r9 # INIT-MARKET-PDA(input, insn, acct, frame) ja init_market_pda init_market_pda_return: diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 5cd71ac..3ae9456 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -3,7 +3,9 @@ dropset-interface = {path = "../interface"} mollusk-svm = {workspace = true} mollusk-svm-programs-token = {workspace = true} solana-account = {workspace = true} +solana-program-pack = {workspace = true} solana-sdk = {workspace = true} +spl-token-2022-interface = {workspace = true} spl-token-interface = {workspace = true} heck.workspace = true diff --git a/tests/tests/cases/register_market.rs b/tests/tests/cases/register_market.rs index e050006..5fa0fd8 100644 --- a/tests/tests/cases/register_market.rs +++ b/tests/tests/cases/register_market.rs @@ -10,8 +10,15 @@ use dropset_tests::{ use mollusk_svm::program; use mollusk_svm::result::ProgramResult as MolluskResult; use solana_account::Account; +use solana_program_pack::Pack; use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::pubkey::Pubkey; +use spl_token_2022_interface::extension::transfer_fee::{TransferFeeAmount, TransferFeeConfig}; +use spl_token_2022_interface::extension::transfer_hook::{TransferHook, TransferHookAccount}; +use spl_token_2022_interface::extension::{AccountType, ExtensionType, Length}; +use spl_token_interface::state::Account as TokenAccount; +use spl_token_interface::state::AccountState; +use spl_token_interface::state::Mint; test_cases! { #[derive(Clone, Copy)] @@ -113,23 +120,76 @@ fn into_metas_and_accounts( const USER_LAMPORTS: u64 = 10_000_000; const MARKET_HEADER_SIZE: usize = size_of::(); -const TOKEN_ACCOUNT_SIZE: usize = 165; +const TOKEN_ACCOUNT_SIZE: usize = TokenAccount::LEN; + +/// Token 2022 TLV header size: ExtensionType + Length. +const TLV_HEADER_SIZE: usize = size_of::() + size_of::(); + +/// Token 2022 base token account + AccountType discriminator. +const BASE_ACCOUNT_AND_TYPE_LENGTH: usize = TokenAccount::LEN + size_of::(); + +/// Expected token account size for a mint with TransferFeeConfig. +/// GetAccountDataSize returns base + AccountType + one TransferFeeAmount TLV entry. +const TOKEN_2022_ACCOUNT_SIZE_A: usize = + BASE_ACCOUNT_AND_TYPE_LENGTH + TLV_HEADER_SIZE + size_of::(); + +/// Expected token account size for a mint with TransferHook. +/// GetAccountDataSize returns base + AccountType + one TransferHookAccount TLV entry. +const TOKEN_2022_ACCOUNT_SIZE_B: usize = + BASE_ACCOUNT_AND_TYPE_LENGTH + TLV_HEADER_SIZE + size_of::(); + +/// Build a Token 2022 mint account with a single TLV extension appended. +fn mint_account_2022(ext_type: ExtensionType, ext_data_len: usize) -> Account { + let mut data = vec![0u8; Mint::LEN]; + Mint::pack(default_mint(), &mut data).unwrap(); + // Zero-pad from Mint::LEN to TokenAccount::LEN, the offset Token 2022 + // uses for the AccountType discriminator. + data.resize(TokenAccount::LEN, 0); + data.push(AccountType::Mint as u8); + // TLV entry: ExtensionType + Length + zeroed extension data. + data.extend_from_slice(&<[u8; size_of::()]>::from(ext_type)); + data.extend_from_slice(&(ext_data_len as u16).to_le_bytes()); + data.extend_from_slice(&vec![0u8; ext_data_len]); + + Account { + lamports: solana_sdk::rent::Rent::default().minimum_balance(data.len()), + data, + owner: Pubkey::from(TOKEN_2022_PROGRAM_ID), + executable: false, + rent_epoch: 0, + } +} + +/// Token 2022 mint with TransferFeeConfig extension. +fn mint_account_2022_a() -> Account { + mint_account_2022( + ExtensionType::TransferFeeConfig, + size_of::(), + ) +} + +/// Token 2022 mint with TransferHook extension. +fn mint_account_2022_b() -> Account { + mint_account_2022(ExtensionType::TransferHook, size_of::()) +} macro_rules! check_vault { - ($errors:expr, $label:expr, $vault:expr, $expected_owner:expr, $rent:expr) => {{ + ($errors:expr, $label:expr, $vault:expr, $expected_owner:expr, $rent:expr, + $expected_mint:expr, $expected_proprietor:expr, $expected_data_len:expr) => {{ let vault = $vault; let expected_owner = $expected_owner; + let expected_data_len: usize = $expected_data_len; if vault.owner != *expected_owner { $errors.push(format!( "{} owner: expected {:?}, got {:?}", $label, expected_owner, vault.owner )); } - if vault.data.len() != TOKEN_ACCOUNT_SIZE { + if vault.data.len() != expected_data_len { $errors.push(format!( "{} data len: expected {}, got {}", $label, - TOKEN_ACCOUNT_SIZE, + expected_data_len, vault.data.len() )); } @@ -141,11 +201,45 @@ macro_rules! check_vault { vault.data.len() )); } + match TokenAccount::unpack_from_slice(&vault.data) { + Ok(token_account) => { + if token_account.mint != $expected_mint { + $errors.push(format!( + "{} mint: expected {:?}, got {:?}", + $label, $expected_mint, token_account.mint + )); + } + if token_account.owner != $expected_proprietor { + $errors.push(format!( + "{} proprietor: expected {:?}, got {:?}", + $label, $expected_proprietor, token_account.owner + )); + } + if token_account.amount != 0 { + $errors.push(format!( + "{} amount: expected 0, got {}", + $label, token_account.amount + )); + } + if token_account.state != AccountState::Initialized { + $errors.push(format!( + "{} state: expected Initialized, got {:?}", + $label, token_account.state + )); + } + } + Err(e) => { + $errors.push(format!( + "{} failed to unpack token account: {:?}", + $label, e + )); + } + } }}; } -fn default_mint() -> spl_token_interface::state::Mint { - spl_token_interface::state::Mint { +fn default_mint() -> Mint { + Mint { is_initialized: true, ..Default::default() } @@ -154,8 +248,6 @@ fn default_mint() -> spl_token_interface::state::Mint { fn mint_account(owner: Pubkey) -> Account { if owner == Pubkey::from(TOKEN_PROGRAM_ID) { mollusk_svm_programs_token::token::create_account_for_mint(default_mint()) - } else if owner == Pubkey::from(TOKEN_2022_PROGRAM_ID) { - mollusk_svm_programs_token::token2022::create_account_for_mint(default_mint()) } else { let mut acct = Account::default(); acct.owner = owner; @@ -328,8 +420,18 @@ fn token_program_base_accounts( keys[RegisterMarketAccounts::RentSysvar as usize] = rent_sysvar_pubkey; accounts[RegisterMarketAccounts::RentSysvar as usize] = rent_sysvar_account; - accounts[RegisterMarketAccounts::BaseMint as usize] = mint_account(base_token_program); - accounts[RegisterMarketAccounts::QuoteMint as usize] = mint_account(quote_token_program); + accounts[RegisterMarketAccounts::BaseMint as usize] = + if base_token_program == Pubkey::from(TOKEN_2022_PROGRAM_ID) { + mint_account_2022_a() + } else { + mint_account(base_token_program) + }; + accounts[RegisterMarketAccounts::QuoteMint as usize] = + if quote_token_program == Pubkey::from(TOKEN_2022_PROGRAM_ID) { + mint_account_2022_b() + } else { + mint_account(quote_token_program) + }; keys[RegisterMarketAccounts::BaseTokenProgram as usize] = base_token_program; accounts[RegisterMarketAccounts::BaseTokenProgram as usize] = @@ -1486,15 +1588,40 @@ impl TestCase for Case { )); } + let market_pda = + result.resulting_accounts[RegisterMarketAccounts::Market as usize].0; + let base_mint_key = + result.resulting_accounts[RegisterMarketAccounts::BaseMint as usize].0; + let quote_mint_key = + result.resulting_accounts[RegisterMarketAccounts::QuoteMint as usize].0; + let base_vault = &result.resulting_accounts [RegisterMarketAccounts::BaseVault as usize] .1; - check_vault!(errors, "base vault", base_vault, &token_program_id, rent); + check_vault!( + errors, + "base vault", + base_vault, + &token_program_id, + rent, + base_mint_key, + market_pda, + TOKEN_ACCOUNT_SIZE + ); let quote_vault = &result.resulting_accounts [RegisterMarketAccounts::QuoteVault as usize] .1; - check_vault!(errors, "quote vault", quote_vault, &token_program_id, rent); + check_vault!( + errors, + "quote vault", + quote_vault, + &token_program_id, + rent, + quote_mint_key, + market_pda, + TOKEN_ACCOUNT_SIZE + ); } other => { errors.push(format!("expected success, got {:?}", other)); @@ -1548,15 +1675,40 @@ impl TestCase for Case { )); } + let market_pda = + result.resulting_accounts[RegisterMarketAccounts::Market as usize].0; + let base_mint_key = + result.resulting_accounts[RegisterMarketAccounts::BaseMint as usize].0; + let quote_mint_key = + result.resulting_accounts[RegisterMarketAccounts::QuoteMint as usize].0; + let base_vault = &result.resulting_accounts [RegisterMarketAccounts::BaseVault as usize] .1; - check_vault!(errors, "base vault", base_vault, &token_program_id, rent); + check_vault!( + errors, + "base vault", + base_vault, + &token_program_id, + rent, + base_mint_key, + market_pda, + TOKEN_ACCOUNT_SIZE + ); let quote_vault = &result.resulting_accounts [RegisterMarketAccounts::QuoteVault as usize] .1; - check_vault!(errors, "quote vault", quote_vault, &token_2022_id, rent); + check_vault!( + errors, + "quote vault", + quote_vault, + &token_2022_id, + rent, + quote_mint_key, + market_pda, + TOKEN_2022_ACCOUNT_SIZE_B + ); } other => { errors.push(format!("expected success, got {:?}", other)); @@ -1609,15 +1761,40 @@ impl TestCase for Case { )); } + let market_pda = + result.resulting_accounts[RegisterMarketAccounts::Market as usize].0; + let base_mint_key = + result.resulting_accounts[RegisterMarketAccounts::BaseMint as usize].0; + let quote_mint_key = + result.resulting_accounts[RegisterMarketAccounts::QuoteMint as usize].0; + let base_vault = &result.resulting_accounts [RegisterMarketAccounts::BaseVault as usize] .1; - check_vault!(errors, "base vault", base_vault, &token_2022_id, rent); + check_vault!( + errors, + "base vault", + base_vault, + &token_2022_id, + rent, + base_mint_key, + market_pda, + TOKEN_2022_ACCOUNT_SIZE_A + ); let quote_vault = &result.resulting_accounts [RegisterMarketAccounts::QuoteVault as usize] .1; - check_vault!(errors, "quote vault", quote_vault, &token_2022_id, rent); + check_vault!( + errors, + "quote vault", + quote_vault, + &token_2022_id, + rent, + quote_mint_key, + market_pda, + TOKEN_2022_ACCOUNT_SIZE_B + ); } other => { errors.push(format!("expected success, got {:?}", other)); @@ -1671,15 +1848,40 @@ impl TestCase for Case { )); } + let market_pda = + result.resulting_accounts[RegisterMarketAccounts::Market as usize].0; + let base_mint_key = + result.resulting_accounts[RegisterMarketAccounts::BaseMint as usize].0; + let quote_mint_key = + result.resulting_accounts[RegisterMarketAccounts::QuoteMint as usize].0; + let base_vault = &result.resulting_accounts [RegisterMarketAccounts::BaseVault as usize] .1; - check_vault!(errors, "base vault", base_vault, &token_2022_id, rent); + check_vault!( + errors, + "base vault", + base_vault, + &token_2022_id, + rent, + base_mint_key, + market_pda, + TOKEN_2022_ACCOUNT_SIZE_A + ); let quote_vault = &result.resulting_accounts [RegisterMarketAccounts::QuoteVault as usize] .1; - check_vault!(errors, "quote vault", quote_vault, &token_program_id, rent); + check_vault!( + errors, + "quote vault", + quote_vault, + &token_program_id, + rent, + quote_mint_key, + market_pda, + TOKEN_ACCOUNT_SIZE + ); } other => { errors.push(format!("expected success, got {:?}", other));