diff --git a/Cargo.lock b/Cargo.lock index c60e127c..aa30851c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -122,9 +122,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" [[package]] name = "asn1-rs" @@ -477,9 +483,9 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bigdecimal" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f31f3af01c5c65a07985c804d3366560e6fa7883d640a122819b14ec327482c" +checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013" dependencies = [ "autocfg", "libm", @@ -488,6 +494,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "binascii" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" + [[package]] name = "bindgen" version = "0.69.5" @@ -513,9 +525,9 @@ dependencies = [ [[package]] name = "bip39" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" +checksum = "43d193de1f7487df1914d3a568b772458861d33f9c54249612cc2893d6915054" dependencies = [ "bitcoin_hashes", "serde", @@ -565,6 +577,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -589,9 +610,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +checksum = "4fd49896f12ac9b6dcd7a5998466b9b58263a695a3dd1ecc1aaca2e12a90b080" dependencies = [ "cc", "glob", @@ -656,18 +677,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be75455e34f2a0e221f0e10bae7a4a066bdeee18b63fb92047d5d075eaf1044c" dependencies = [ "chia-bls 0.20.0", - "chia-client", - "chia-consensus", - "chia-protocol", - "chia-puzzle-types", - "chia-secp", - "chia-serde", + "chia-client 0.20.0", + "chia-consensus 0.20.0", + "chia-protocol 0.20.0", + "chia-puzzle-types 0.20.0", + "chia-secp 0.20.0", + "chia-serde 0.20.0", "chia-sha2 0.20.0", - "chia-ssl", + "chia-ssl 0.20.0", "chia-traits 0.20.0", - "clvm-traits", - "clvm-utils", - "clvmr", + "clvm-traits 0.20.0", + "clvm-utils 0.20.0", + "clvmr 0.12.1", +] + +[[package]] +name = "chia" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b27699b864f74bfe17216295e445db63f1aedbe3be9560833009a5890ce5d46d" +dependencies = [ + "chia-bls 0.26.0", + "chia-client 0.26.0", + "chia-consensus 0.26.0", + "chia-protocol 0.26.0", + "chia-puzzle-types 0.26.0", + "chia-secp 0.26.0", + "chia-serde 0.26.0", + "chia-sha2 0.26.0", + "chia-ssl 0.26.0", + "chia-traits 0.26.0", + "clvm-traits 0.26.0", + "clvm-utils 0.26.0", + "clvmr 0.14.0", ] [[package]] @@ -682,7 +724,7 @@ dependencies = [ "hex", "hkdf", "lru", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", ] @@ -693,14 +735,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d94b11e12208aa2bb8a76a05fc57f6e616efabf695e3fc2e6041a9d6df563ccb" dependencies = [ "blst", - "chia-serde", + "chia-serde 0.20.0", "chia-sha2 0.20.0", "chia-traits 0.20.0", "hex", "hkdf", "linked-hash-map", "serde", - "sha2", + "sha2 0.10.9", + "thiserror 1.0.69", +] + +[[package]] +name = "chia-bls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86eaaa00a83a7511e8eb74ccb1ebe4358d927f43e06d45da5350e19ef2df1ca" +dependencies = [ + "blst", + "chia-sha2 0.22.0", + "chia-traits 0.22.0", + "hex", + "hkdf", + "linked-hash-map", + "sha2 0.10.9", + "thiserror 1.0.69", +] + +[[package]] +name = "chia-bls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc9ac7e90ae816e814dc26fb332615a5449d1d26e965eb7ad068ae530f9c3c7b" +dependencies = [ + "blst", + "chia-serde 0.26.0", + "chia-sha2 0.26.0", + "chia-traits 0.26.0", + "hex", + "hkdf", + "linked-hash-map", + "serde", + "sha2 0.10.9", "thiserror 1.0.69", ] @@ -710,7 +786,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c318dc78d656cf8617a672e06af2da200b003603f0597e80363dc869502dc1ec" dependencies = [ - "chia-protocol", + "chia-protocol 0.20.0", "chia-traits 0.20.0", "futures-util", "thiserror 1.0.69", @@ -719,6 +795,21 @@ dependencies = [ "tungstenite 0.24.0", ] +[[package]] +name = "chia-client" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3874f2e4c87f246457a42890d4f8e0cae9d019131b54f80f66c561c8d05cd444" +dependencies = [ + "chia-protocol 0.26.0", + "chia-traits 0.26.0", + "futures-util", + "thiserror 1.0.69", + "tokio", + "tokio-tungstenite 0.24.0", + "tungstenite 0.24.0", +] + [[package]] name = "chia-consensus" version = "0.20.0" @@ -726,17 +817,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc7acfdaf6819c19bd61de9e6004312aa257a8df0e36caec81675e06112658b9" dependencies = [ "chia-bls 0.20.0", - "chia-protocol", - "chia-puzzle-types", + "chia-protocol 0.20.0", + "chia-puzzle-types 0.20.0", "chia-puzzles", "chia-sha2 0.20.0", "chia-traits 0.20.0", "chia_streamable_macro 0.20.0", - "clvm-traits", - "clvm-utils", - "clvmr", + "clvm-traits 0.20.0", + "clvm-utils 0.20.0", + "clvmr 0.12.1", "hex", - "hex-literal 0.4.1", + "hex-literal", + "thiserror 1.0.69", +] + +[[package]] +name = "chia-consensus" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "481208db317ed106dc249a5669a6916c565374633850584480a40b639409a940" +dependencies = [ + "chia-bls 0.26.0", + "chia-protocol 0.26.0", + "chia-puzzle-types 0.26.0", + "chia-puzzles", + "chia-sha2 0.26.0", + "chia-traits 0.26.0", + "chia_streamable_macro 0.26.0", + "clvm-traits 0.26.0", + "clvm-utils 0.26.0", + "clvmr 0.14.0", + "hex", + "hex-literal", "thiserror 1.0.69", ] @@ -747,13 +859,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3cced8dfdc4541d1e2b617e50c41028d2f318310df8060d0bf718a957ad5dcb" dependencies = [ "chia-bls 0.20.0", - "chia-serde", + "chia-serde 0.20.0", "chia-sha2 0.20.0", "chia-traits 0.20.0", "chia_streamable_macro 0.20.0", - "clvm-traits", - "clvm-utils", - "clvmr", + "clvm-traits 0.20.0", + "clvm-utils 0.20.0", + "clvmr 0.12.1", + "hex", + "serde", +] + +[[package]] +name = "chia-protocol" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9256179e4c912313532d7a47a50f67f6128313ee86a3798e54050afb73d6042" +dependencies = [ + "chia-bls 0.26.0", + "chia-serde 0.26.0", + "chia-sha2 0.26.0", + "chia-traits 0.26.0", + "chia_streamable_macro 0.26.0", + "clvm-traits 0.26.0", + "clvm-utils 0.26.0", + "clvmr 0.14.0", "hex", "serde", ] @@ -765,13 +895,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a6a5a6ab34939140c4211a8dbca3d816a30177e4ef62fda53c3142eaba2fe0a" dependencies = [ "chia-bls 0.20.0", - "chia-protocol", + "chia-protocol 0.20.0", "chia-puzzles", "chia-sha2 0.20.0", - "clvm-traits", - "clvm-utils", - "clvmr", - "hex-literal 0.4.1", + "clvm-traits 0.20.0", + "clvm-utils 0.20.0", + "clvmr 0.12.1", + "hex-literal", + "num-bigint", +] + +[[package]] +name = "chia-puzzle-types" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239406b55be27d99a6903057e6785e0279fe9fdc48270faf7ef9270dcfa05c8d" +dependencies = [ + "chia-bls 0.26.0", + "chia-protocol 0.26.0", + "chia-puzzles", + "chia-sha2 0.26.0", + "clvm-traits 0.26.0", + "clvm-utils 0.26.0", + "clvmr 0.14.0", + "hex-literal", "num-bigint", ] @@ -782,7 +929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7108a1597c78873f6c116b434db0bc7bfaf16f30828c35ce648a6ca49710c8" dependencies = [ "hex", - "hex-literal 0.4.1", + "hex-literal", ] [[package]] @@ -792,9 +939,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e79752f8c692ef3f74f94a902e91000cc8668a19c5e27c4142c44213a7a7b1" dependencies = [ "aws-lc-rs", - "chia-protocol", - "chia-sdk-types", - "chia-ssl", + "chia-protocol 0.20.0", + "chia-sdk-types 0.23.0", + "chia-ssl 0.20.0", "chia-traits 0.20.0", "futures-util", "once_cell", @@ -807,15 +954,46 @@ dependencies = [ "tungstenite 0.24.0", ] +[[package]] +name = "chia-sdk-client" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "chia-protocol 0.26.0", + "chia-sdk-types 0.27.0", + "chia-ssl 0.26.0", + "chia-traits 0.26.0", + "futures-util", + "once_cell", + "thiserror 2.0.12", + "tokio", + "tokio-tungstenite 0.24.0", + "tracing", + "tungstenite 0.24.0", +] + [[package]] name = "chia-sdk-coinset" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0df6e3ed139b6112cdbaf817c95c5cee9319f37f6df40e4547adb29687b33c96" dependencies = [ - "chia-protocol", + "chia-protocol 0.20.0", "hex", - "hex-literal 0.4.1", + "hex-literal", + "reqwest", + "serde", + "serde_json", +] + +[[package]] +name = "chia-sdk-coinset" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "chia-protocol 0.26.0", + "hex", + "hex-literal", "reqwest", "serde", "serde_json", @@ -832,6 +1010,16 @@ dependencies = [ "syn", ] +[[package]] +name = "chia-sdk-derive" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "convert_case", + "quote", + "syn", +] + [[package]] name = "chia-sdk-driver" version = "0.23.0" @@ -841,22 +1029,52 @@ dependencies = [ "bech32", "bigdecimal", "chia-bls 0.20.0", - "chia-consensus", - "chia-protocol", - "chia-puzzle-types", + "chia-consensus 0.20.0", + "chia-protocol 0.20.0", + "chia-puzzle-types 0.20.0", "chia-puzzles", - "chia-sdk-types", - "chia-secp", + "chia-sdk-types 0.23.0", + "chia-secp 0.20.0", "chia-sha2 0.20.0", "chia-traits 0.20.0", "chia_streamable_macro 0.21.2", - "clvm-traits", - "clvm-utils", - "clvmr", + "clvm-traits 0.20.0", + "clvm-utils 0.20.0", + "clvmr 0.12.1", + "flate2", + "hex", + "hex-literal", + "indexmap 2.10.0", + "num-bigint", + "once_cell", + "thiserror 2.0.12", +] + +[[package]] +name = "chia-sdk-driver" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "bech32", + "bigdecimal", + "chia-bls 0.26.0", + "chia-consensus 0.26.0", + "chia-protocol 0.26.0", + "chia-puzzle-types 0.26.0", + "chia-puzzles", + "chia-sdk-signer 0.27.0", + "chia-sdk-types 0.27.0", + "chia-secp 0.26.0", + "chia-sha2 0.26.0", + "chia-traits 0.26.0", + "chia_streamable_macro 0.26.0", + "clvm-traits 0.26.0", + "clvm-utils 0.26.0", + "clvmr 0.14.0", "flate2", "hex", - "hex-literal 0.4.1", - "indexmap 2.8.0", + "hex-literal", + "indexmap 2.10.0", "num-bigint", "once_cell", "thiserror 2.0.12", @@ -869,13 +1087,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80a7262ffc41549aeade067a278924114740fb01fefb76f66fba2a2efbc38883" dependencies = [ "chia-bls 0.20.0", - "chia-consensus", - "chia-protocol", - "chia-sdk-types", - "chia-secp", + "chia-consensus 0.20.0", + "chia-protocol 0.20.0", + "chia-sdk-types 0.23.0", + "chia-secp 0.20.0", "chia-sha2 0.20.0", - "clvm-traits", - "clvmr", + "clvm-traits 0.20.0", + "clvmr 0.12.1", + "k256", + "thiserror 2.0.12", +] + +[[package]] +name = "chia-sdk-signer" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "chia-bls 0.26.0", + "chia-consensus 0.26.0", + "chia-protocol 0.26.0", + "chia-sdk-types 0.27.0", + "chia-secp 0.26.0", + "chia-sha2 0.26.0", + "clvm-traits 0.26.0", + "clvmr 0.14.0", "k256", "thiserror 2.0.12", ] @@ -889,21 +1124,21 @@ dependencies = [ "anyhow", "bip39", "chia-bls 0.20.0", - "chia-consensus", - "chia-protocol", - "chia-puzzle-types", - "chia-sdk-client", - "chia-sdk-signer", - "chia-sdk-types", - "chia-secp", + "chia-consensus 0.20.0", + "chia-protocol 0.20.0", + "chia-puzzle-types 0.20.0", + "chia-sdk-client 0.23.0", + "chia-sdk-signer 0.23.0", + "chia-sdk-types 0.23.0", + "chia-secp 0.20.0", "chia-traits 0.20.0", - "clvm-traits", - "clvm-utils", - "clvmr", + "clvm-traits 0.20.0", + "clvm-utils 0.20.0", + "clvmr 0.12.1", "futures-channel", "futures-util", "hex", - "indexmap 2.8.0", + "indexmap 2.10.0", "itertools 0.13.0", "rand 0.8.5", "rand_chacha 0.3.1", @@ -914,6 +1149,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "chia-sdk-test" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "anyhow", + "bip39", + "chia-bls 0.26.0", + "chia-consensus 0.26.0", + "chia-protocol 0.26.0", + "chia-puzzle-types 0.26.0", + "chia-sdk-signer 0.27.0", + "chia-sdk-types 0.27.0", + "chia-secp 0.26.0", + "chia-traits 0.26.0", + "clvm-traits 0.26.0", + "clvm-utils 0.26.0", + "clvmr 0.14.0", + "hex", + "indexmap 2.10.0", + "rand 0.8.5", + "rand_chacha 0.3.1", + "thiserror 2.0.12", +] + [[package]] name = "chia-sdk-types" version = "0.23.0" @@ -921,20 +1181,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "896773b58dd6f8c509ea0956462371d7a03c2e13d2d8646136c6376667864606" dependencies = [ "chia-bls 0.20.0", - "chia-consensus", - "chia-protocol", - "chia-puzzle-types", + "chia-consensus 0.20.0", + "chia-protocol 0.20.0", + "chia-puzzle-types 0.20.0", "chia-puzzles", - "chia-sdk-derive", - "chia-secp", + "chia-sdk-derive 0.23.0", + "chia-secp 0.20.0", "chia-sha2 0.20.0", - "clvm-traits", - "clvm-utils", - "clvmr", - "hex-literal 0.4.1", + "clvm-traits 0.20.0", + "clvm-utils 0.20.0", + "clvmr 0.12.1", + "hex-literal", "once_cell", ] +[[package]] +name = "chia-sdk-types" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "chia-bls 0.26.0", + "chia-consensus 0.26.0", + "chia-protocol 0.26.0", + "chia-puzzle-types 0.26.0", + "chia-puzzles", + "chia-sdk-derive 0.27.0", + "chia-secp 0.26.0", + "chia-sha2 0.26.0", + "clvm-traits 0.26.0", + "clvm-utils 0.26.0", + "clvm_tools_rs", + "clvmr 0.14.0", + "hex-literal", + "once_cell", + "thiserror 2.0.12", +] + [[package]] name = "chia-sdk-utils" version = "0.23.0" @@ -942,8 +1224,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "659f1d4a9b91d9164b1953b0497baec080243830d4f573ea7388d7cd33fae459" dependencies = [ "bech32", - "chia-protocol", - "indexmap 2.8.0", + "chia-protocol 0.20.0", + "indexmap 2.10.0", + "rand 0.8.5", + "rand_chacha 0.3.1", + "thiserror 2.0.12", +] + +[[package]] +name = "chia-sdk-utils" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "bech32", + "chia-protocol 0.26.0", + "indexmap 2.10.0", "rand 0.8.5", "rand_chacha 0.3.1", "thiserror 2.0.12", @@ -961,6 +1256,18 @@ dependencies = [ "p256", ] +[[package]] +name = "chia-secp" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae00dfc70f7a3b20c5074ea3684b25f7b64225ad44ca3ea766b4e908f86c2d5" +dependencies = [ + "chia-sha2 0.26.0", + "hex", + "k256", + "p256", +] + [[package]] name = "chia-serde" version = "0.20.0" @@ -971,13 +1278,23 @@ dependencies = [ "serde", ] +[[package]] +name = "chia-serde" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b013e263888739bfecf7456552eb4a9f2260f920db8b46b0723fb553ab1e030" +dependencies = [ + "hex", + "serde", +] + [[package]] name = "chia-sha2" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7020f53eeae8b4c24c5666165738173a167c6478e0c0a9e1c428a491a2e1383d" dependencies = [ - "sha2", + "sha2 0.10.9", ] [[package]] @@ -986,7 +1303,25 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320474241a5e4b4eb7c7935ddac6e893cc4237d5fab58f1855c1aa48a97b1474" dependencies = [ - "sha2", + "sha2 0.10.9", +] + +[[package]] +name = "chia-sha2" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7b37c5362dfb1c9449902139e94a91bbd8d3773c13939972fd88e4f14c4f9d" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "chia-sha2" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3ab374b1f248d87516c34e4c128a91d2086e76a46bb44e386c96a71ea39129" +dependencies = [ + "sha2 0.10.9", ] [[package]] @@ -1003,6 +1338,19 @@ dependencies = [ "time", ] +[[package]] +name = "chia-ssl" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51af8606c8376d730d6607cb69fe5edd87f5d0d106e5620065f58a31e7f348a4" +dependencies = [ + "rand 0.8.5", + "rcgen", + "rsa", + "thiserror 1.0.69", + "time", +] + [[package]] name = "chia-traits" version = "0.15.0" @@ -1025,6 +1373,28 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "chia-traits" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340ad823ef953d2ab9f937deae99b04bab73c0bf1a6aea1353331a5f875192e0" +dependencies = [ + "chia-sha2 0.22.0", + "chia_streamable_macro 0.22.0", + "thiserror 1.0.69", +] + +[[package]] +name = "chia-traits" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440a88dfa8f685a87c4bae5f0b12c7bec1466ca1ff44dfc6b09acc605f7848fe" +dependencies = [ + "chia-sha2 0.26.0", + "chia_streamable_macro 0.26.0", + "thiserror 1.0.69", +] + [[package]] name = "chia-wallet-sdk" version = "0.23.0" @@ -1032,17 +1402,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb4e8041651d5dc6630307406b8e9e145a9325b293050edfab8006cccdb46d6b" dependencies = [ "chia-bls 0.20.0", - "chia-protocol", - "chia-sdk-client", - "chia-sdk-coinset", - "chia-sdk-driver", - "chia-sdk-signer", - "chia-sdk-test", - "chia-sdk-types", - "chia-sdk-utils", - "clvm-traits", - "clvm-utils", - "clvmr", + "chia-protocol 0.20.0", + "chia-sdk-client 0.23.0", + "chia-sdk-coinset 0.23.0", + "chia-sdk-driver 0.23.0", + "chia-sdk-signer 0.23.0", + "chia-sdk-test 0.23.0", + "chia-sdk-types 0.23.0", + "chia-sdk-utils 0.23.0", + "clvm-traits 0.20.0", + "clvm-utils 0.20.0", + "clvmr 0.12.1", +] + +[[package]] +name = "chia-wallet-sdk" +version = "0.27.0" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +dependencies = [ + "chia-bls 0.26.0", + "chia-protocol 0.26.0", + "chia-sdk-client 0.27.0", + "chia-sdk-coinset 0.27.0", + "chia-sdk-driver 0.27.0", + "chia-sdk-signer 0.27.0", + "chia-sdk-test 0.27.0", + "chia-sdk-types 0.27.0", + "chia-sdk-utils 0.27.0", + "clvm-traits 0.26.0", + "clvm-utils 0.26.0", + "clvmr 0.14.0", ] [[package]] @@ -1081,6 +1470,30 @@ dependencies = [ "syn", ] +[[package]] +name = "chia_streamable_macro" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed16ee21f14ed878cfc23b0354c8c6703190a5565d03625ea44324a3f21717f1" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "chia_streamable_macro" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068278c78a0c53786012f6330a088f3f6ffe83bd39cb8f21d308eeec2f43a3dc" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "chrono" version = "0.4.40" @@ -1156,6 +1569,17 @@ dependencies = [ "syn", ] +[[package]] +name = "clvm-derive" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ded863cb5482335498872e91989487283f012adb7ca4ddf54ad7c6995058db" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "clvm-traits" version = "0.20.0" @@ -1163,9 +1587,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71cd5dd7977b36416ea1f0b5917cbc9fd0e0a00539dc75f9edec4744b3be69a" dependencies = [ "chia-bls 0.20.0", - "chia-secp", - "clvm-derive", - "clvmr", + "chia-secp 0.20.0", + "clvm-derive 0.20.0", + "clvmr 0.12.1", + "num-bigint", + "thiserror 1.0.69", +] + +[[package]] +name = "clvm-traits" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469c44226c83de37509415482c89c00763f58de198844c34d2d62161b087d0ce" +dependencies = [ + "chia-bls 0.26.0", + "chia-secp 0.26.0", + "clvm-derive 0.26.0", + "clvmr 0.14.0", "num-bigint", "thiserror 1.0.69", ] @@ -1177,9 +1615,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8504b2255e7bd3eaf4c05abb88c4a1519235522b04b4bcbc7289cdda5380f7b" dependencies = [ "chia-sha2 0.20.0", - "clvm-traits", - "clvmr", + "clvm-traits 0.20.0", + "clvmr 0.12.1", + "hex", +] + +[[package]] +name = "clvm-utils" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5646cd8d02f9c55c76ef6ff7598df54e6c8361f27fe8c9122e3ae9ef55935fcd" +dependencies = [ + "chia-sha2 0.26.0", + "clvm-traits 0.26.0", + "clvmr 0.14.0", + "hex", +] + +[[package]] +name = "clvm_tools_rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00394d353154d726b10ca4f76056f4fac3ad37a3218c83ba3008b041e1398c3" +dependencies = [ + "binascii", + "chia-bls 0.22.0", + "clvmr 0.14.0", + "do-notation", + "getrandom 0.2.15", + "hashlink", "hex", + "indoc", + "js-sys", + "lazy_static", + "num", + "num-bigint", + "num-traits", + "pyo3-build-config", + "regex", + "serde", + "serde_json", + "sha2 0.9.9", + "tempfile", + "unicode-segmentation", + "wasm-bindgen", + "yaml-rust2", ] [[package]] @@ -1193,7 +1673,30 @@ dependencies = [ "chia-bls 0.15.0", "chia-sha2 0.15.0", "hex", - "hex-literal 0.4.1", + "hex-literal", + "k256", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "p256", + "rand 0.8.5", + "sha1", + "sha3", +] + +[[package]] +name = "clvmr" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6b7142674607f3a213addaf261bd70b07537297e460a9cc6a389068a62934f" +dependencies = [ + "bitvec", + "bumpalo", + "chia-bls 0.22.0", + "chia-sha2 0.22.0", + "hex", + "hex-literal", "k256", "lazy_static", "num-bigint", @@ -1429,21 +1932,30 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", @@ -1502,6 +2014,12 @@ dependencies = [ "syn", ] +[[package]] +name = "do-notation" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e16a80c1dda2cf52fa07106427d3d798b6331dca8155fcb8c39f7fc78f6dd2" + [[package]] name = "dotenvy" version = "0.15.7" @@ -1521,7 +2039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest", + "digest 0.10.7", "elliptic-curve", "rfc6979", "signature", @@ -1545,7 +2063,7 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "digest 0.10.7", "ff", "generic-array", "group", @@ -1580,12 +2098,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1653,9 +2171,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "libz-sys", @@ -1940,7 +2458,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.8.0", + "indexmap 2.10.0", "slab", "tokio", "tokio-util", @@ -2025,12 +2543,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" -[[package]] -name = "hex-literal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcaaec4551594c969335c98c903c1397853d4198408ea609190f420500f6be71" - [[package]] name = "hkdf" version = "0.12.4" @@ -2046,7 +2558,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -2140,7 +2652,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 0.26.8", ] [[package]] @@ -2161,21 +2673,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.10", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -2360,15 +2879,21 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown 0.15.2", "serde", ] +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + [[package]] name = "instant" version = "0.1.13" @@ -2395,6 +2920,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.16" @@ -2465,7 +3000,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", - "sha2", + "sha2 0.10.9", "signature", ] @@ -2504,9 +3039,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libloading" @@ -2515,7 +3050,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -2576,6 +3111,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "litemap" version = "0.7.5" @@ -2623,7 +3164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] @@ -2701,6 +3242,20 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -2709,6 +3264,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "serde", ] [[package]] @@ -2728,6 +3284,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2754,6 +3319,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2798,6 +3374,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl" version = "0.10.66" @@ -2867,7 +3449,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -3080,13 +3662,23 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] +[[package]] +name = "pyo3-build-config" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99636d423fa2ca130fa5acde3059308006d46f98caac629418e53f7ebb1e9999" +dependencies = [ + "once_cell", + "target-lexicon", +] + [[package]] name = "quinn" version = "0.11.7" @@ -3100,7 +3692,7 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.1", "rustls", - "socket2 0.5.7", + "socket2 0.5.10", "thiserror 2.0.12", "tokio", "tracing", @@ -3136,7 +3728,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.7", + "socket2 0.5.10", "tracing", "windows-sys 0.59.0", ] @@ -3269,9 +3861,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -3281,9 +3873,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3292,9 +3884,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -3304,15 +3896,14 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", - "futures-util", "h2", "http", "http-body", @@ -3321,34 +3912,30 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", "rustls", - "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", - "windows-registry", + "webpki-roots 1.0.1", ] [[package]] @@ -3383,7 +3970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" dependencies = [ "const-oid", - "digest", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", @@ -3489,6 +4076,19 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", +] + [[package]] name = "rustls" version = "0.23.27" @@ -3565,7 +4165,7 @@ name = "sage-api" version = "0.10.3" source = "git+https://github.com/xch-dev/sage.git#206ea6db50e4a36dcb0258f4e4554f0547efa011" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.10.0", "once_cell", "sage-config", "serde", @@ -3576,10 +4176,10 @@ name = "sage-config" version = "0.10.3" source = "git+https://github.com/xch-dev/sage.git#206ea6db50e4a36dcb0258f4e4554f0547efa011" dependencies = [ - "chia", - "chia-wallet-sdk", + "chia 0.20.0", + "chia-wallet-sdk 0.23.0", "hex", - "indexmap 2.8.0", + "indexmap 2.10.0", "once_cell", "serde", "serde_with", @@ -3721,7 +4321,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.8.0", + "indexmap 2.10.0", "serde", "serde_derive", "serde_json", @@ -3749,18 +4349,31 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] name = "sha2" -version = "0.10.8" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -3769,7 +4382,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest", + "digest 0.10.7", "keccak", ] @@ -3794,7 +4407,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -3815,20 +4428,20 @@ dependencies = [ "axum", "bech32", "bip39", - "chia", - "chia-puzzle-types", + "chia 0.26.0", + "chia-puzzle-types 0.26.0", "chia-puzzles", - "chia-wallet-sdk", + "chia-wallet-sdk 0.27.0", "clap", - "clvm-traits", - "clvmr", + "clvm-traits 0.26.0", + "clvmr 0.14.0", "csv", "dirs", "futures", "futures-util", "getrandom 0.3.2", "hex", - "hex-literal 1.0.0", + "hex-literal", "openssl", "openssl-sys", "prettytable-rs", @@ -3866,9 +4479,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3880,7 +4493,7 @@ version = "2.0.0-rc.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab7f01e9310a820edd31c80fde3cae445295adde21a3f9416517d7d65015b971" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.10.0", "specta-macros", "thiserror 1.0.69", ] @@ -3948,7 +4561,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.2", "hashlink", - "indexmap 2.8.0", + "indexmap 2.10.0", "log", "memchr", "native-tls", @@ -3956,7 +4569,7 @@ dependencies = [ "percent-encoding", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror 2.0.12", "tracing", @@ -3992,7 +4605,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -4014,7 +4627,7 @@ dependencies = [ "byteorder", "bytes", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -4035,7 +4648,7 @@ dependencies = [ "rsa", "serde", "sha1", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -4072,7 +4685,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -4135,9 +4748,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -4191,16 +4804,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "target-lexicon" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" + [[package]] name = "tempfile" -version = "3.13.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand 2.1.1", + "getrandom 0.3.2", "once_cell", - "rustix 0.38.37", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -4266,9 +4885,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -4281,15 +4900,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -4322,9 +4941,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.1" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -4333,7 +4952,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2 0.5.10", "tokio-macros", "windows-sys 0.52.0", ] @@ -4382,7 +5001,7 @@ dependencies = [ "tokio", "tokio-rustls", "tungstenite 0.24.0", - "webpki-roots", + "webpki-roots 0.26.8", ] [[package]] @@ -4426,7 +5045,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.10.0", "toml_datetime", "winnow 0.5.40", ] @@ -4437,7 +5056,7 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.10.0", "toml_datetime", "winnow 0.6.18", ] @@ -4460,14 +5079,18 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.2" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ "bitflags 2.6.0", "bytes", + "futures-util", "http", + "http-body", + "iri-string", "pin-project-lite", + "tower", "tower-layer", "tower-service", ] @@ -4596,9 +5219,9 @@ checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" @@ -4716,6 +5339,8 @@ dependencies = [ "cfg-if", "once_cell", "rustversion", + "serde", + "serde_json", "wasm-bindgen-macro", ] @@ -4806,6 +5431,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "which" version = "4.4.2" @@ -4860,7 +5494,7 @@ dependencies = [ "windows-interface", "windows-link", "windows-result", - "windows-strings 0.4.0", + "windows-strings", ] [[package]] @@ -4887,44 +5521,35 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ + "windows-link", "windows-result", - "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-strings", ] [[package]] name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -4980,29 +5605,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -5015,12 +5624,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -5033,12 +5636,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -5051,24 +5648,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -5081,12 +5666,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -5099,12 +5678,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -5117,12 +5690,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -5135,12 +5702,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" version = "0.5.40" @@ -5207,6 +5768,17 @@ dependencies = [ "time", ] +[[package]] +name = "yaml-rust2" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce2a4ff45552406d02501cea6c18d8a7e50228e7736a872951fe2fe75c91be7" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink", +] + [[package]] name = "yasna" version = "0.5.2" diff --git a/Cargo.toml b/Cargo.toml index 84049b10..e4d55453 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,11 +8,12 @@ homepage = "https://github.com/Yakuhito/slot-machine" repository = "https://github.com/Yakuhito/slot-machine" [dependencies] -clvmr = "0.12.1" -chia = "0.20.0" -clvm-traits = "0.20.0" -hex-literal = "1.0.0" -bip39 = "2.1.0" +clvmr = "0.14.0" +chia = "0.26.0" +clvm-traits = "0.26.0" +chia-puzzle-types = "0.26.0" +hex-literal = "0.4.1" +bip39 = "2.2.0" getrandom = "0.3.2" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" @@ -23,7 +24,7 @@ thiserror = "2.0.12" tokio = { version = "1.44.1", features = ["full"] } sqlx = { version = "0.8.3", features = ["sqlite", "runtime-async-std-native-tls"] } bech32 = "0.9.1" -reqwest = { version = "0.12.15", features = ["json", "rustls-tls"] } +reqwest = { version = "0.12.20", features = ["json", "rustls-tls"] } dirs = "6.0.0" rustls = { version = "0.23", features = ["ring","logging","tls12"], default-features = false } tokio-tungstenite ={ version = "0.26.2", features = ["rustls-tls-native-roots"] } @@ -31,13 +32,12 @@ futures-util = "0.3.31" axum = { version = "0.8.3", features = ["macros"]} tower-http = { version = "0.6.2", features = ["cors"] } futures = "0.3.31" -chia-wallet-sdk = { version="0.23.0", features=["offers"] } +chia-wallet-sdk = { git = "https://github.com/xch-dev/chia-wallet-sdk.git", rev = "2a056f03b92077fc0ce808ca2e7c01d707d04c43", features=["offer-compression"] } sage-api = { version = "0.10.3", git = "https://github.com/xch-dev/sage.git" } chia-puzzles = "0.20.1" -chia-puzzle-types = "0.20.0" [dev-dependencies] -anyhow = "1.0.86" +anyhow = "1.0.98" rstest = "0.22.0" prettytable-rs = "0.10.0" diff --git a/include/slots.clib b/include/slots.clib index c1f1d0ae..122142a8 100644 --- a/include/slots.clib +++ b/include/slots.clib @@ -21,7 +21,7 @@ ) ) - (defun create_slot (SLOT_1ST_CURRY_HASH slot_value_hash hint) + (defun create_slot (SLOT_1ST_CURRY_HASH slot_value_hash) (list CREATE_COIN (curry_hashes SLOT_1ST_CURRY_HASH @@ -54,7 +54,7 @@ ) ) - (defun create_slot_inline (SLOT_1ST_CURRY_HASH slot_value_hash hint) + (defun create_slot_inline (SLOT_1ST_CURRY_HASH slot_value_hash) (list CREATE_COIN (curry_hashes_inline SLOT_1ST_CURRY_HASH diff --git a/include/xchandles.clib b/include/xchandles.clib index 353a7146..0b5cbe20 100644 --- a/include/xchandles.clib +++ b/include/xchandles.clib @@ -13,7 +13,6 @@ pricing_puzzle_solution handle secret - start_time owner_launcher_id resolved_data ) @@ -25,7 +24,7 @@ ) (c (c handle secret) - (c start_time (c owner_launcher_id resolved_data)) + (c owner_launcher_id resolved_data) ) ) ) diff --git a/puzzles/actions/reward_distributor/nft/stake.clsp.hex b/puzzles/actions/reward_distributor/nft/stake.clsp.hex index 01ababce..e69de29b 100644 --- a/puzzles/actions/reward_distributor/nft/stake.clsp.hex +++ b/puzzles/actions/reward_distributor/nft/stake.clsp.hex @@ -1 +0,0 @@ -ff02ffff01ff04ffff04ffff10ff8209ffffff010180ffff04ff8215ffffff04ffff10ff822dffffff010180ffff04ff825dffffff04ff82bdffff808080808080ffff02ff3cffff04ff02ffff04ffff0bffff02ff3affff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ffff04ff09ffff04ffff02ff36ffff04ff02ffff04ffff30ff83047bffffff02ff3affff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff05ff80808080ffff04ff830a7bffff808080808080ff83167bff80ffff04ff83037bffff8080808080ff1d8080ff80808080ffff04ffff02ff3affff04ff02ffff04ff0bffff04ffff0bffff0101ff0b80ffff04ff822bffffff04ff825bffffff04ffff02ff3affff04ff02ffff04ff17ffff04ffff0bffff0101ff1780ffff04ff8192ffff04ff82bbffffff04ff2fff8080808080808080ff8080808080808080ff808080808080ffff02ff3effff04ff02ffff04ffff04ffff02ff3effff04ff02ffff04ffff04ff8209ffff8213ff80ff80808080ffff04ffff02ff2effff04ff02ffff04ffff02ff3affff04ff02ffff04ff5fffff04ffff0bffff0101ff8301fbff80ffff04ff81bfff808080808080ff80808080ff808080ff8080808080ffff04ffff04ffff04ff28ffff04ff8213ffff808080ffff04ffff02ff2affff04ff02ffff04ff82017fffff04ffff02ff3effff04ff02ffff04ffff04ff8301fbffffff04ff829dffffff01018080ff80808080ffff04ff8301fbffff808080808080ffff04ffff04ff10ffff04ffff10ff83013dffff8202ff80ff808080ff80808080ff808080808080ffff04ffff01ffffff55ff463fffff333eff02ff04ffff04ff38ffff04ff05ff808080ffff04ffff04ff34ffff04ff05ff808080ff0b8080ffffffff02ffff03ff05ffff01ff0bff81f2ffff02ff26ffff04ff02ffff04ff09ffff04ffff02ff22ffff04ff02ffff04ff0dff80808080ff808080808080ffff0181d280ff0180ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff24ffff04ffff02ff3affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ff0bff81b2ffff02ff26ffff04ff02ffff04ff05ffff04ffff02ff22ffff04ff02ffff04ff07ff80808080ff808080808080ffffff0bff2cffff0bff2cff81d2ff0580ffff0bff2cff0bff81928080ff02ffff03ff0bffff01ff30ffff02ff36ffff04ff02ffff04ff05ffff04ff1bff8080808080ff23ff3380ffff010580ff0180ffff04ff05ffff04ffff0101ffff04ffff04ff05ff8080ff80808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 diff --git a/puzzles/actions/xchandles/expire.clsp b/puzzles/actions/xchandles/expire.clsp index 2ddcb2f0..09094fc3 100644 --- a/puzzles/actions/xchandles/expire.clsp +++ b/puzzles/actions/xchandles/expire.clsp @@ -20,7 +20,7 @@ cat_maker_puzzle_reveal cat_maker_puzzle_solution expired_handle_pricing_puzzle_reveal - (@ expired_handle_pricing_puzzle_solution (buy_time current_expiration handle . rest_maybe)) + (@ expired_handle_pricing_puzzle_solution (buy_time current_expiration handle . expired_handle_pricing_puzzle_solution_rest)) refund_puzzle_hash_hash secret neighbors ; (c left right) @@ -73,7 +73,6 @@ expired_handle_pricing_puzzle_solution handle secret - buy_time new_owner_launcher_id new_resolved_data )) @@ -105,7 +104,7 @@ (if (all (= (sha256tree cat_maker_puzzle_reveal) Cat_Maker_Puzzle_Hash) (= (sha256tree expired_handle_pricing_puzzle_reveal) Expired_Handle_Pricing_Puzzle_Hash) - (= (strlen new_resolved_data) 32) + (= (strlen new_owner_launcher_id) 32) (> 65 (strlen new_resolved_data)) ) (main diff --git a/puzzles/actions/xchandles/expire.clsp.hex b/puzzles/actions/xchandles/expire.clsp.hex index 1aea97bc..6281e1b9 100644 --- a/puzzles/actions/xchandles/expire.clsp.hex +++ b/puzzles/actions/xchandles/expire.clsp.hex @@ -1 +1 @@ -ff02ffff01ff02ffff03ffff22ffff09ffff02ff16ffff04ff02ffff04ff4fff80808080ff5780ffff09ffff02ff16ffff04ff02ffff04ff82016fff80808080ff81f780ffff09ffff0dff827fef80ffff012080ffff15ffff0141ffff0dff827fef808080ffff01ff04ff17ffff02ff2effff04ff02ffff04ffff02ff4fffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff8205ef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff16ffff04ff02ffff04ffff04ffff04ffff04ff57ff81af80ffff04ff81f7ff8202ef8080ffff04ffff04ff8216efff820bef80ffff04ff8204efffff04ff825fefff827fef80808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff81af8080ffff04ffff05ffff02ff82016fff8202ef8080ffff04ffff04ffff04ff10ffff04ff8204efff808080ffff04ffff04ff10ffff04ff820aefff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ff820aefff822fef8080ff80808080ff8080808080ffff04ffff02ff1affff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ffff10ffff06ffff02ff82016fff8202ef8080ff8204ef80ff823fef8080ff80808080ff8080808080ff8080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ffff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0178ff0580ff808080ff178080ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080 +ff02ffff01ff02ffff03ffff22ffff09ffff02ff16ffff04ff02ffff04ff4fff80808080ff5780ffff09ffff02ff16ffff04ff02ffff04ff82016fff80808080ff81f780ffff09ffff0dff825fef80ffff012080ffff15ffff0141ffff0dff827fef808080ffff01ff04ff17ffff02ff2effff04ff02ffff04ffff02ff4fffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff8205ef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff16ffff04ff02ffff04ffff04ffff04ffff04ff57ff81af80ffff04ff81f7ff8202ef8080ffff04ffff04ff8216efff820bef80ffff04ff825fefff827fef808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff81af8080ffff04ffff05ffff02ff82016fff8202ef8080ffff04ffff04ffff04ff10ffff04ff8204efff808080ffff04ffff04ff10ffff04ff820aefff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ff820aefff822fef8080ff80808080ff8080808080ffff04ffff02ff1affff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ffff10ffff06ffff02ff82016fff8202ef8080ff8204ef80ff823fef8080ff80808080ff8080808080ff8080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ffff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0178ff0580ff808080ff178080ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080 diff --git a/puzzles/actions/xchandles/extend.clsp b/puzzles/actions/xchandles/extend.clsp index ed3aaf48..7e6d636b 100644 --- a/puzzles/actions/xchandles/extend.clsp +++ b/puzzles/actions/xchandles/extend.clsp @@ -19,7 +19,7 @@ ) ( pricing_puzzle_reveal - (@ pricing_solution (expiration handle . rest)) + (@ pricing_solution (buy_time expiration handle . rest)) cat_maker_puzzle_reveal cat_maker_solution neighbors . @@ -47,6 +47,9 @@ ; can't extend if expired (list ASSERT_BEFORE_SECONDS_ABSOLUTE expiration) + ; assert buy time + (list ASSERT_SECONDS_ABSOLUTE buy_time) + ; create new slot (create_slot_inline SLOT_1ST_CURRY_HASH (get_xchandles_slot_value_hash diff --git a/puzzles/actions/xchandles/extend.clsp.hex b/puzzles/actions/xchandles/extend.clsp.hex index 9cdb70a0..7b7ab7e2 100644 --- a/puzzles/actions/xchandles/extend.clsp.hex +++ b/puzzles/actions/xchandles/extend.clsp.hex @@ -1 +1 @@ -ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff8202dfff8080808080ffff09ff82016fffff02ff2effff04ff02ffff04ff819fff808080808080ffff01ff04ff2fffff04ffff02ff3effff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff82055f80ff820bdf80ffff04ff82025fff820fdf8080ff80808080ff8080808080ffff04ffff04ff2cffff04ffff0effff0165ffff02ff2effff04ff02ffff04ffff04ffff05ffff02ff819fff82015f8080ff82055f80ff8080808080ff808080ffff04ffff04ff10ffff04ff82025fff808080ffff04ffff02ff16ffff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff82055f80ff820bdf80ffff04ffff10ff82025fffff06ffff02ff819fff82015f808080ff820fdf8080ff80808080ff8080808080ffff04ffff04ff18ffff04ffff0bffff02ff8202dfffff04ff05ff8205df8080ffff02ff2effff04ff02ffff04ffff04ffff02ff2effff04ff02ffff04ffff04ff82055fff82025f80ff80808080ffff04ffff04ff0bffff04ffff05ffff02ff819fff82015f8080ffff04ffff04ff0bff8080ff80808080ff808080ff8080808080ff808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff553fff33ff3e42ffff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff14ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff3cffff04ffff0112ffff04ff80ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ff8080808080ff018080 +ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff8202dfff8080808080ffff09ff82016fffff02ff2effff04ff02ffff04ff819fff808080808080ffff01ff04ff2fffff04ffff02ff3effff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff820b5f80ff820bdf80ffff04ff82055fff820fdf8080ff80808080ff8080808080ffff04ffff04ff3cffff04ffff0effff0165ffff02ff2effff04ff02ffff04ffff04ffff05ffff02ff819fff82015f8080ff820b5f80ff8080808080ff808080ffff04ffff04ff10ffff04ff82055fff808080ffff04ffff04ff14ffff04ff82025fff808080ffff04ffff02ff16ffff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff820b5f80ff820bdf80ffff04ffff10ff82055fffff06ffff02ff819fff82015f808080ff820fdf8080ff80808080ff8080808080ffff04ffff04ff18ffff04ffff0bffff02ff8202dfffff04ff05ff8205df8080ffff02ff2effff04ff02ffff04ffff04ffff02ff2effff04ff02ffff04ffff04ff820b5fff82055f80ff80808080ffff04ffff04ff0bffff04ffff05ffff02ff819fff82015f8080ffff04ffff04ff0bff8080ff80808080ff808080ff8080808080ff808080ff8080808080808080ffff01ff088080ff0180ffff04ffff01ffffff553fff51ff333effff42ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff2cffff04ffff0bff81baffff0bff2affff0bff2aff81daff0580ffff0bff2affff0bff81faffff0bff2affff0bff2aff81daffff0bffff0101ff0b8080ffff0bff2aff81daff819a808080ff819a808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff12ffff04ffff0112ffff04ff80ffff04ffff0bff81baffff0bff2affff0bff2aff81daff0580ffff0bff2affff0bff81faffff0bff2affff0bff2aff81daffff0bffff0101ff0b8080ffff0bff2aff81daff819a808080ff819a808080ff8080808080ff018080 diff --git a/puzzles/actions/xchandles/refund.clsp b/puzzles/actions/xchandles/refund.clsp index 0adaf32c..7b4c3b92 100644 --- a/puzzles/actions/xchandles/refund.clsp +++ b/puzzles/actions/xchandles/refund.clsp @@ -28,7 +28,6 @@ precommited_pricing_puzzle_solution handle secret - precommited_start_time precommited_owner_launcher_id precommited_resolved_data refund_puzzle_hash_hash @@ -89,19 +88,16 @@ (all ; not (a) (= precommited_cat_maker_reveal_hash Cat_Maker_Puzzle_Hash) - ; not (b) - (if (= precommited_pricing_puzzle_reveal_hash Pricing_Puzzle_Hash) - (= handle (f (r precommited_pricing_puzzle_solution))) - ; else - (if (= precommited_pricing_puzzle_reveal_hash Expired_Handle_Pricing_Puzzle_Hash) - (= handle (f (r (r precommited_pricing_puzzle_solution)))) - ; else - () - ) - ) ; not (c) + (= handle (f (r (r precommited_pricing_puzzle_solution)))) + (any + (= precommited_pricing_puzzle_reveal_hash Pricing_Puzzle_Hash) + (= precommited_pricing_puzzle_reveal_hash Expired_Handle_Pricing_Puzzle_Hash) + ) + ; not (b) (= precommit_amount (f (a precommited_pricing_puzzle_reveal precommited_pricing_puzzle_solution))) - ) ; slot spend needed if (a), (b), and (c) are not met - we need (d) + ) ; slot spend needed if the precommit coin looks valid after checking (a), (b), (c) & it could be used + ; to register a handle unless we're in situation (d) (a precommited_cat_maker_reveal (c @@ -114,7 +110,6 @@ precommited_pricing_puzzle_solution handle secret - precommited_start_time precommited_owner_launcher_id precommited_resolved_data )) ; hash of precommit value, which is itself a hash :) diff --git a/puzzles/actions/xchandles/refund.clsp.hex b/puzzles/actions/xchandles/refund.clsp.hex index b30748cf..a3e6b779 100644 --- a/puzzles/actions/xchandles/refund.clsp.hex +++ b/puzzles/actions/xchandles/refund.clsp.hex @@ -1 +1 @@ -ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff4fff8080808080ffff09ff8205efffff02ff2effff04ff02ffff04ff8202efff8080808080ffff02ffff03ff8307ffefffff01ff09ff8313ffefffff0bffff0101ff8217ef8080ffff01ff010180ff018080ffff01ff04ff17ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ff8307ffefff80808080ffff04ffff22ffff09ff81afff5780ffff02ffff03ffff09ff8205efff81b780ffff01ff09ff8217efff822bef80ffff01ff02ffff03ffff09ff8205efff81f780ffff01ff09ff8217efff825bef80ff8080ff018080ff0180ffff09ff8305ffefffff05ffff02ff8202efff820bef80808080ffff04ffff02ff4fffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ff8302ffef80ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff81afff82016f80ffff04ff8205efff820bef8080ffff04ffff04ff8217efff822fef80ffff04ff825fefffff04ff82bfefff83017fef80808080ff808080808080ffff0bff1cff62ff42808080ff42808080ff42808080ff82016f8080ffff04ff8305ffefff808080808080808080ffff01ff088080ff0180ffff04ffff01ffffff333eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff10ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff04ffff04ff14ffff04ffff0113ffff04ff80ffff04ff2fffff04ff5fff808080808080ffff04ffff04ff18ffff04ffff0effff0124ff2f80ff808080ffff02ffff03ff17ffff01ff04ffff02ff3effff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ff0bff8080808080ff808080ff8080ff01808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ff8080808080ff018080 +ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff4fff8080808080ffff09ff8205efffff02ff2effff04ff02ffff04ff8202efff8080808080ffff02ffff03ff8303ffefffff01ff09ff8309ffefffff0bffff0101ff8217ef8080ffff01ff010180ff018080ffff01ff04ff17ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ff8303ffefff80808080ffff04ffff22ffff09ff81afff5780ffff09ff8217efff825bef80ffff21ffff09ff8205efff81b780ffff09ff8205efff81f78080ffff09ff8302ffefffff05ffff02ff8202efff820bef80808080ffff04ffff02ff4fffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ff83017fef80ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff81afff82016f80ffff04ff8205efff820bef8080ffff04ffff04ff8217efff822fef80ffff04ff825fefff82bfef808080ff808080808080ffff0bff1cff62ff42808080ff42808080ff42808080ff82016f8080ffff04ff8302ffefff808080808080808080ffff01ff088080ff0180ffff04ffff01ffffff333eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff10ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff04ffff04ff14ffff04ffff0113ffff04ff80ffff04ff2fffff04ff5fff808080808080ffff04ffff04ff18ffff04ffff0effff0124ff2f80ff808080ffff02ffff03ff17ffff01ff04ffff02ff3effff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ff0bff8080808080ff808080ff8080ff01808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ff8080808080ff018080 diff --git a/puzzles/actions/xchandles/register.clsp b/puzzles/actions/xchandles/register.clsp index b71c777e..5f11d0ed 100644 --- a/puzzles/actions/xchandles/register.clsp +++ b/puzzles/actions/xchandles/register.clsp @@ -26,11 +26,11 @@ ) ) ) - ; pricing_solution's first element MUST be handle_reveal + ; pricing_solution has 3 Truths: Start_Time, Current_Expiration, and Handle_Reveal ( handle_hash pricing_puzzle_reveal - (@ pricing_solution (this_is_zero handle . solution_rest)) + (@ pricing_solution (start_time this_is_zero handle . solution_rest)) cat_maker_puzzle_reveal cat_maker_solution ; start neighbor slots info @@ -42,7 +42,6 @@ right_expiration right_data ; end neighbor slots info - start_time (@ data (owner_launcher_id . resolved_data)) ; info needed to compute precommit coin puzzle hash refund_puzzle_hash_hash @@ -94,7 +93,6 @@ pricing_solution handle secret - start_time owner_launcher_id resolved_data )) diff --git a/puzzles/actions/xchandles/register.clsp.hex b/puzzles/actions/xchandles/register.clsp.hex index 9c826934..c5600429 100644 --- a/puzzles/actions/xchandles/register.clsp.hex +++ b/puzzles/actions/xchandles/register.clsp.hex @@ -1 +1 @@ -ff02ffff01ff02ffff03ffff22ffff09ff4fffff0bffff0101ff82056f8080ffff20ff82026f80ffff0aff4fff8213ef80ffff0aff821befff4f80ffff09ff57ffff02ff2effff04ff02ffff04ff8202efff8080808080ffff09ff81b7ffff02ff2effff04ff02ffff04ff81afff8080808080ffff09ffff0dff8313ffef80ffff012080ffff15ffff0141ffff0dff831bffef808080ffff01ff04ff17ffff02ff1affff04ff02ffff04ffff02ff8202efffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff8317ffef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff57ff8205ef80ffff04ff81b7ff82016f8080ffff04ffff04ff82056fff832fffef80ffff04ff8305ffefffff04ff8313ffefff831bffef80808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff8205ef8080ffff04ffff05ffff02ff81afff82016f8080ffff04ffff04ffff04ff10ffff04ff8305ffefff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff821bef8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff8213efff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff4fff820bef80ffff04ffff10ff8305ffefffff06ffff02ff81afff82016f808080ff830bffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff4f8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff4fff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ff80808080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0172ff0580ff808080ff178080ffff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080 +ff02ffff01ff02ffff03ffff22ffff09ff4fffff0bffff0101ff820b6f8080ffff20ff82056f80ffff0aff4fff8213ef80ffff0aff821befff4f80ffff09ff57ffff02ff2effff04ff02ffff04ff8202efff8080808080ffff09ff81b7ffff02ff2effff04ff02ffff04ff81afff8080808080ffff09ffff0dff8309ffef80ffff012080ffff15ffff0141ffff0dff830dffef808080ffff01ff04ff17ffff02ff1affff04ff02ffff04ffff02ff8202efffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff830bffef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff57ff8205ef80ffff04ff81b7ff82016f8080ffff04ffff04ff820b6fff8317ffef80ffff04ff8309ffefff830dffef808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff8205ef8080ffff04ffff05ffff02ff81afff82016f8080ffff04ffff04ffff04ff10ffff04ff82026fff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff821bef8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff8213efff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff4fff820bef80ffff04ffff10ff82026fffff06ffff02ff81afff82016f808080ff8305ffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff4f8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff4fff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ff80808080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0172ff0580ff808080ff178080ffff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080 diff --git a/puzzles/default_puzzles/default_cat_maker.clsp b/puzzles/default_puzzles/default_cat_maker.clsp index 7e232962..6256de50 100644 --- a/puzzles/default_puzzles/default_cat_maker.clsp +++ b/puzzles/default_puzzles/default_cat_maker.clsp @@ -5,6 +5,8 @@ ;; The default CAT maker assumes no intermediary layers between the CAT outer puzzle and the inner puzzle. +;; Note: Truths (Inner_Puzzle_Hash) are trusted and should be verified by the outer puzzle. + (mod ( CAT_MOD_HASH TAIL_HASH_HASH ; (sha256 1 TAIL_HASH) diff --git a/puzzles/default_puzzles/exponential_premium.clsp b/puzzles/default_puzzles/exponential_premium.clsp index 7340064f..ada3cf22 100644 --- a/puzzles/default_puzzles/exponential_premium.clsp +++ b/puzzles/default_puzzles/exponential_premium.clsp @@ -8,16 +8,25 @@ ;; Inspired by ExponentialPremiumPirceOracle: https://github.com/ensdomains/ens-contracts/blob/master/contracts/ethregistrar/ExponentialPremiumPriceOracle.sol +;; Note: Truths (Buy_Time & Expiration) are trusted and should be verified by the outer puzzle. + (mod ( BASE_PROGRAM ; compute base price using this program HALVING_PERIOD ; one day = 86400 = 60 * 60 * 24 seconds START_PREMIUM - END_VALUE ; premium at the very end of the expiry auction + END_VALUE ; value returned by the premium function at the end of the reverse auction + ; to make premium = 0 at the end, we subtract this small value from all + ; values returned by the function, effectively moving the graph a bit + ; down on the y-axis so f(auction_end_time) = 0 PRECISION ; 10 ** 18 - BITS_LIST ; (list bit1 bit2 bit3 ...) - Buy_Time ; 'time now' - assumes user is interested in passing in a value as late as possible - Expiration . - rest_of_pricing_program_solution ; pricing_program_solution passed to BASE_PROGRAM (r expiration handle . num_years) = (handle . num_years) + BITS_LIST . ; (list bit1 bit2 bit3 ...) + (@ solution + ( + Buy_Time ; 'time now' - assumes user is interested in passing in a value as late as possible + Current_Expiration + rest_of_pricing_program_solution ; pricing_program_solution passed to BASE_PROGRAM (e.g., (Handle . num_periods)) + ) + ) ) (defun add_fractional_part (PRECISION bits_list acc fraction_part premium) (if bits_list @@ -50,8 +59,8 @@ PRECISION BITS_LIST 1 - (/ (* 65536 (% (- Buy_Time Expiration) HALVING_PERIOD)) HALVING_PERIOD) ; fractional part of n with 16 bits of precision (2 ** 16 = 65536) - (/ START_PREMIUM (lsh 1 (/ (- Buy_Time Expiration) HALVING_PERIOD))) ; premium from whole periods = START_PREMIUM / 2^p + (/ (* 65536 (% (- Buy_Time Current_Expiration) HALVING_PERIOD)) HALVING_PERIOD) ; fractional part of n with 16 bits of precision (2 ** 16 = 65536) + (/ START_PREMIUM (lsh 1 (/ (- Buy_Time Current_Expiration) HALVING_PERIOD))) ; premium from whole periods = START_PREMIUM / 2^p ) END_VALUE) ; premium ) registered_time @@ -59,6 +68,6 @@ ) (main - (a BASE_PROGRAM (c Expiration rest_of_pricing_program_solution)) + (a BASE_PROGRAM solution) ) ) \ No newline at end of file diff --git a/puzzles/default_puzzles/exponential_premium.clsp.hex b/puzzles/default_puzzles/exponential_premium.clsp.hex index f9b3273e..c1d66d62 100644 --- a/puzzles/default_puzzles/exponential_premium.clsp.hex +++ b/puzzles/default_puzzles/exponential_premium.clsp.hex @@ -1 +1 @@ -ff02ffff01ff04ffff10ffff05ffff02ff05ffff04ff8202ffff8203ff808080ffff02ff06ffff04ff02ffff04ffff02ff04ffff04ff02ffff04ff5fffff04ff81bfffff04ffff0101ffff04ffff05ffff14ffff12ffff0183010000ffff3dffff11ff82017fff8202ff80ff0b8080ff0b8080ffff04ffff05ffff14ff17ffff17ffff0101ffff05ffff14ffff11ff82017fff8202ff80ff0b8080808080ff8080808080808080ffff04ff2fff808080808080ffff06ffff02ff05ffff04ff8202ffff8203ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ff04ffff04ff02ffff04ff05ffff04ff1bffff04ffff17ff17ffff010180ffff04ff2fffff04ffff02ffff03ffff18ff2fff1780ffff01ff05ffff14ffff12ff5fff1380ff058080ffff015f80ff0180ff8080808080808080ffff015f80ff0180ff02ffff03ffff15ff05ff0b80ffff01ff11ff05ff0b80ff8080ff0180ff018080 +ff02ffff01ff04ffff10ffff05ffff02ff05ff81ff8080ffff02ff06ffff04ff02ffff04ffff02ff04ffff04ff02ffff04ff5fffff04ff81bfffff04ffff0101ffff04ffff05ffff14ffff12ffff0183010000ffff3dffff11ff82017fff8202ff80ff0b8080ff0b8080ffff04ffff05ffff14ff17ffff17ffff0101ffff05ffff14ffff11ff82017fff8202ff80ff0b8080808080ff8080808080808080ffff04ff2fff808080808080ffff06ffff02ff05ff81ff808080ffff04ffff01ffff02ffff03ff0bffff01ff02ff04ffff04ff02ffff04ff05ffff04ff1bffff04ffff17ff17ffff010180ffff04ff2fffff04ffff02ffff03ffff18ff2fff1780ffff01ff05ffff14ffff12ff5fff1380ff058080ffff015f80ff0180ff8080808080808080ffff015f80ff0180ff02ffff03ffff15ff05ff0b80ffff01ff11ff05ff0b80ff8080ff0180ff018080 diff --git a/puzzles/default_puzzles/factor_pricing.clsp b/puzzles/default_puzzles/factor_pricing.clsp index 97b579eb..581f2cbc 100644 --- a/puzzles/default_puzzles/factor_pricing.clsp +++ b/puzzles/default_puzzles/factor_pricing.clsp @@ -12,11 +12,19 @@ ;; - 3 characters with no numbers: 128 ;; If the handle contains a number, the price is halved. +;; Note: Truths (Buy_Time, Current_Expiration, Handle) are trusted and should be verified by the outer puzzle. + (mod ( BASE_PRICE ; base price = price per month of a 6+ character handle with at least one number REGISTRATION_PERIOD ; number of seconds to register a handle for, in seconds ; most likely 31622400 = 366 days * 24 hours/day * 60 minutes/hour * 60 seconds/minute + Buy_Time ; 'time now' - assumes user is interested in passing in a value as late as possible + ; This Truth is unused in this puzzle, but can be used to price handles differently + ; Generally, the outer puzzle will just verify it with an ASSERT_SECONDS_ABSOLUTE + ; but with no matching ASSERT_BEFORE_SECONDS_ABSOLUTE & delay Current_Expiration ; 0 if the handle is being registered, != 0 if extension + ; this Truth is unused in this puzzle, but can be used to price renewals differently + ; in custom ones Handle . num_periods ; number of periods to register the handle for (e.g., 1 year, 2 years, and so on) ) @@ -26,7 +34,7 @@ (if (> length 4) (if (= length 5) 16 - ; else length > 6 + ; else length >= 6 (if (> length 31) (x) 2) ) ; else 2 < length < 5 @@ -55,7 +63,7 @@ ) ) - ;; this function will return 1 if the handle contains numbers and 0 otherwise + ;; this function will return the number of numbers in a handle ;; PLUS it will (x) if the handle contains invalid characters (defun count_numbers_plus_validate (handle) (if handle diff --git a/puzzles/default_puzzles/factor_pricing.clsp.hex b/puzzles/default_puzzles/factor_pricing.clsp.hex index 0db57ef0..88c5aa0b 100644 --- a/puzzles/default_puzzles/factor_pricing.clsp.hex +++ b/puzzles/default_puzzles/factor_pricing.clsp.hex @@ -1 +1 @@ -ff02ffff01ff02ffff03ffff15ff3fff8080ffff01ff04ffff12ff3fff05ffff02ff06ffff04ff02ffff04ffff0dff2f80ffff04ffff02ff04ffff04ff02ffff04ff2fff80808080ff808080808080ffff12ff3fff0b8080ffff01ff088080ff0180ffff04ffff01ffff02ffff03ff05ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff016080ffff15ffff017bffff0cff05ff80ffff0101808080ffff01ff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff80808080ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff012f80ffff15ffff013affff0cff05ff80ffff0101808080ffff01ff10ffff0101ffff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff8080808080ffff01ff088080ff018080ff0180ff8080ff0180ff05ffff14ffff02ffff03ffff15ff05ffff010280ffff01ff02ffff03ffff15ff05ffff010480ffff01ff02ffff03ffff09ff05ffff010580ffff01ff0110ffff01ff02ffff03ffff15ff05ffff011f80ffff01ff0880ffff01ff010280ff018080ff0180ffff01ff02ffff03ffff09ff05ffff010380ffff01ff01820080ffff01ff014080ff018080ff0180ffff01ff088080ff0180ffff03ff0bffff0102ffff0101808080ff018080 +ff02ffff01ff02ffff03ffff15ff7fff8080ffff01ff04ffff12ff7fff05ffff02ff06ffff04ff02ffff04ffff0dff5f80ffff04ffff02ff04ffff04ff02ffff04ff5fff80808080ff808080808080ffff12ff7fff0b8080ffff01ff088080ff0180ffff04ffff01ffff02ffff03ff05ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff016080ffff15ffff017bffff0cff05ff80ffff0101808080ffff01ff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff80808080ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff012f80ffff15ffff013affff0cff05ff80ffff0101808080ffff01ff10ffff0101ffff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff8080808080ffff01ff088080ff018080ff0180ff8080ff0180ff05ffff14ffff02ffff03ffff15ff05ffff010280ffff01ff02ffff03ffff15ff05ffff010480ffff01ff02ffff03ffff09ff05ffff010580ffff01ff0110ffff01ff02ffff03ffff15ff05ffff011f80ffff01ff0880ffff01ff010280ff018080ff0180ffff01ff02ffff03ffff09ff05ffff010380ffff01ff01820080ffff01ff014080ff018080ff0180ffff01ff088080ff0180ffff03ff0bffff0102ffff0101808080ff018080 diff --git a/src/cli/catalog/broadcast_catalog_state_update.rs b/src/cli/catalog/broadcast_catalog_state_update.rs index 17a28dfc..497298b8 100644 --- a/src/cli/catalog/broadcast_catalog_state_update.rs +++ b/src/cli/catalog/broadcast_catalog_state_update.rs @@ -89,13 +89,13 @@ pub async fn catalog_broadcast_state_update( new_state, medieval_vault_inner_ph.into(), )?; - catalog.insert(inner_spend); - let mut _new_catalog = catalog.finish_spend(&mut ctx)?; + catalog.insert_action_spend(&mut ctx, inner_spend)?; + let (_new_catalog, pending_sig) = catalog.finish_spend(&mut ctx)?; multisig_broadcast_thing_finish( client, &mut ctx, - signature_from_signers, + signature_from_signers + &pending_sig, fee_str, testnet11, medieval_vault_coin_id, diff --git a/src/cli/catalog/continue_launch.rs b/src/cli/catalog/continue_launch.rs index 3c7a3648..3e6d6fa2 100644 --- a/src/cli/catalog/continue_launch.rs +++ b/src/cli/catalog/continue_launch.rs @@ -5,21 +5,23 @@ use chia::{ protocol::{Bytes32, SpendBundle}, puzzles::{cat::CatArgs, singleton::SingletonStruct, CoinProof, LineageProof}, }; -use chia_puzzle_types::offer::{NotarizedPayment, Payment}; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{CatLayer, DriverError, Layer, Offer, Puzzle, SingleCatSpend, Spend, SpendContext}, + driver::{ + decode_offer, CatLayer, DriverError, Layer, Offer, Puzzle, SingleCatSpend, Spend, + SpendContext, + }, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; use clvm_traits::clvm_quote; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - assets_xch_and_cat, assets_xch_only, hex_string_to_bytes32, load_catalog_premine_csv, new_sk, - no_assets, parse_amount, parse_one_sided_offer, spend_security_coin, sync_catalog, - wait_for_coin, yes_no_prompt, CatNftMetadata, CatalogPrecommitValue, CatalogPremineRecord, - CatalogRegisterAction, CatalogRegistryConstants, CliError, Db, PrecommitCoin, PrecommitLayer, - SageClient, + assets_xch_and_cat, assets_xch_only, create_security_coin, hex_string_to_bytes32, + load_catalog_premine_csv, no_assets, parse_amount, spend_security_coin, spend_settlement_cats, + sync_catalog, wait_for_coin, yes_no_prompt, CatNftMetadata, CatalogPrecommitValue, + CatalogPremineRecord, CatalogRegisterAction, CatalogRegistryConstants, CliError, Db, + PrecommitCoin, PrecommitLayer, SageClient, }; pub fn initial_cat_inner_puzzle_ptr( @@ -219,53 +221,34 @@ pub async fn catalog_continue_launch( let mut cat_creator_conds = Conditions::new(); for inner_ph in precommitment_inner_puzzle_hashes_to_launch { - cat_creator_conds = cat_creator_conds.create_coin( - inner_ph.into(), - 1, - Some(ctx.hint(inner_ph.into())?), - ); + cat_creator_conds = + cat_creator_conds.create_coin(inner_ph.into(), 1, ctx.hint(inner_ph.into())?); } let cat_destination_puzzle_ptr = ctx.alloc(&clvm_quote!(cat_creator_conds))?; let cat_destination_puzzle_hash: Bytes32 = ctx.tree_hash(cat_destination_puzzle_ptr).into(); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - // Parse one-sided offer - let one_sided_offer = parse_one_sided_offer( + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; + let (created_cats, cat_assert) = spend_settlement_cats( &mut ctx, - offer, - security_coin_sk.public_key(), - Some(NotarizedPayment { - nonce: constants.launcher_id, - payments: vec![Payment::with_memos( - cat_destination_puzzle_hash, - cat_amount, - vec![cat_destination_puzzle_hash.into()], - )], - }), - None, + &offer, + payment_asset_id, + constants.launcher_id, + vec![(cat_destination_puzzle_hash, cat_amount)], )?; - let Some(created_cat) = one_sided_offer.created_cat else { - eprintln!("No CAT was created in one-sided offer - aborting..."); - return Ok(()); - }; - one_sided_offer - .coin_spends - .into_iter() - .for_each(|cs| ctx.insert(cs)); - - let security_coin_conditions = one_sided_offer - .security_base_conditions + let created_cat = created_cats[0]; + let security_coin_conditions = cat_assert .assert_concurrent_spend(created_cat.coin.coin_id()) .reserve_fee(1); // Spend security coin let security_coin_sig = spend_security_coin( &mut ctx, - one_sided_offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, if testnet11 { @@ -281,28 +264,26 @@ pub async fn catalog_continue_launch( SingleCatSpend { next_coin_proof: CoinProof { parent_coin_info: created_cat.coin.parent_coin_info, - inner_puzzle_hash: created_cat.p2_puzzle_hash, + inner_puzzle_hash: created_cat.info.p2_puzzle_hash, amount: created_cat.coin.amount, }, prev_coin_id: created_cat.coin.coin_id(), prev_subtotal: 0, extra_delta: 0, - inner_spend: Spend::new(cat_destination_puzzle_ptr, NodePtr::NIL), + p2_spend: Spend::new(cat_destination_puzzle_ptr, NodePtr::NIL), + revoke: false, }, )?; // Build spend bundle - let sb = SpendBundle::new( - ctx.take(), - one_sided_offer.aggregated_signature + &security_coin_sig, - ); + let sb = offer.take(SpendBundle::new(ctx.take(), security_coin_sig)); println!("Submitting transaction..."); let resp = client.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, one_sided_offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); return Ok(()); @@ -467,12 +448,11 @@ pub async fn catalog_continue_launch( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let mut security_coin_conditions = offer.security_base_conditions; + let mut security_coin_conditions = Conditions::new(); for (i, precommit_value) in precommit_values.iter().enumerate() { let precommit_ph = precommit_puzzle_hashes[i]; @@ -510,7 +490,7 @@ pub async fn catalog_continue_launch( let eve_nft_inner_puzzle = initial_cat_inner_puzzle_ptr(&mut ctx, &cats[i])?; - let (sec_conds, new_slots) = catalog.new_action::().spend( + let sec_conds = catalog.new_action::().spend( &mut ctx, &mut catalog, tail_hash, @@ -524,14 +504,13 @@ pub async fn catalog_continue_launch( )?; security_coin_conditions = security_coin_conditions.extend(sec_conds); - catalog.add_pending_slots(new_slots); } - let _new_catalog = catalog.finish_spend(&mut ctx)?; + let (_new_catalog, pending_sig) = catalog.finish_spend(&mut ctx)?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, if testnet11 { @@ -541,13 +520,16 @@ pub async fn catalog_continue_launch( }, )?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let resp = client.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/catalog/initiate_launch.rs b/src/cli/catalog/initiate_launch.rs index ec5cd452..4fe50e4b 100644 --- a/src/cli/catalog/initiate_launch.rs +++ b/src/cli/catalog/initiate_launch.rs @@ -18,8 +18,7 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Cat, DriverError, Launcher, Offer, SpendContext}, - prelude::Memos, + driver::{decode_offer, Cat, DriverError, Launcher, Offer, SpendContext}, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, utils::Address, }; @@ -72,18 +71,18 @@ fn get_additional_info_for_launch( )?; conditions = conditions.extend(price_singleton_launch_conds); - let cat_memos = Memos::some(ctx.alloc(&vec![cat_destination_puzzle_hash])?); - let (cat_creation_conds, eve_cat) = Cat::single_issuance_eve( + let hint = ctx.hint(cat_destination_puzzle_hash)?; + let (cat_creation_conds, eve_cat) = Cat::issue_with_coin( ctx, security_coin.coin_id(), cat_amount, - Conditions::new().create_coin(cat_destination_puzzle_hash, cat_amount, cat_memos), + Conditions::new().create_coin(cat_destination_puzzle_hash, cat_amount, hint), )?; conditions = conditions.extend(cat_creation_conds); println!( "Premine payment asset id: {}", - hex::encode(eve_cat.asset_id) + hex::encode(eve_cat[0].info.asset_id) ); println!( "Price singleton id (SAVE THIS): {}", @@ -95,7 +94,7 @@ fn get_additional_info_for_launch( catalog_constants .with_price_singleton(price_singleton_launcher_id) .with_launcher_id(catalog_launcher_id), - eve_cat.asset_id, + eve_cat[0].info.asset_id, )) } @@ -188,10 +187,7 @@ pub async fn catalog_initiate_launch( println!("Default constants will be used:"); println!(" royalty address: {}", royalty_address); - println!( - " royalty ten thousandths: {}", - constants.royalty_ten_thousandths - ); + println!(" royalty basis points: {}", constants.royalty_basis_points); println!(" precommit payout address: {}", precommit_payout_address); println!( " relative block height: {}", @@ -236,9 +232,10 @@ pub async fn catalog_initiate_launch( let mut ctx = SpendContext::new(); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; let (sig, _, _registry, slots, security_coin) = launch_catalog_registry( &mut ctx, - Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?, + &offer, 1, get_additional_info_for_launch, if testnet11 { diff --git a/src/cli/catalog/quick_sync.rs b/src/cli/catalog/quick_sync.rs index b0db20d3..fc3ae859 100644 --- a/src/cli/catalog/quick_sync.rs +++ b/src/cli/catalog/quick_sync.rs @@ -1,11 +1,10 @@ use chia::protocol::CoinSpend; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{Puzzle, SpendContext}, + driver::SpendContext, }; -use clvmr::serde::node_from_bytes; -use crate::{CatalogRegistry, CatalogRegistryConstants, CliError}; +use crate::{mempool_catalog_maybe, CatalogRegistry, CatalogRegistryConstants, CliError}; pub async fn quick_sync_catalog( client: &CoinsetClient, @@ -42,34 +41,20 @@ pub async fn quick_sync_catalog( ))?; let mut temp_ctx = SpendContext::new(); - let puzzle_ptr = node_from_bytes(&mut temp_ctx, &next_spend.puzzle_reveal)?; - let puzzle = Puzzle::parse(&temp_ctx, puzzle_ptr); - let solution_ptr = node_from_bytes(&mut temp_ctx, &next_spend.solution)?; - - let catalog_maybe = CatalogRegistry::from_parent_spend( - &mut temp_ctx, - next_spend.coin, - puzzle, - solution_ptr, - constants, - ) - .unwrap_or_default(); + let catalog_maybe = + CatalogRegistry::from_parent_spend(&mut temp_ctx, &next_spend, constants)?; if catalog_maybe.is_some() { coin_spend = Some(next_spend); break; } } - if let Some(coin_spend) = coin_spend { - let puzzle_ptr = node_from_bytes(ctx, &coin_spend.puzzle_reveal)?; - let puzzle = Puzzle::parse(ctx, puzzle_ptr); - let solution_ptr = node_from_bytes(ctx, &coin_spend.solution)?; + let Some(coin_spend) = coin_spend else { + return Err(CliError::Custom("Could not find CATalog coin".to_string())); + }; + let on_chain_catalog = CatalogRegistry::from_parent_spend(ctx, &coin_spend, constants)?.ok_or( + CliError::Custom("Could not parse CATalog spend".to_string()), + )?; - CatalogRegistry::from_parent_spend(ctx, coin_spend.coin, puzzle, solution_ptr, constants)? - .ok_or(CliError::Custom( - "Tried to unwrap CATalog but couldn't".to_string(), - )) - } else { - Err(CliError::Custom("Could not find CATalog coin".to_string())) - } + mempool_catalog_maybe(ctx, on_chain_catalog, client).await } diff --git a/src/cli/catalog/register.rs b/src/cli/catalog/register.rs index 0b1e18e3..fdcc9fdb 100644 --- a/src/cli/catalog/register.rs +++ b/src/cli/catalog/register.rs @@ -5,14 +5,14 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{CatLayer, Layer, Offer, Puzzle, Spend, SpendContext}, + driver::{decode_offer, CatLayer, Layer, Offer, Puzzle, Spend, SpendContext}, utils::Address, }; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - assets_xch_only, get_coinset_client, get_constants, get_prefix, hex_string_to_bytes, - hex_string_to_bytes32, new_sk, no_assets, parse_amount, parse_one_sided_offer, + assets_xch_only, create_security_coin, get_coinset_client, get_constants, get_prefix, + hex_string_to_bytes, hex_string_to_bytes32, no_assets, parse_amount, print_spend_bundle_to_file, quick_sync_catalog, spend_security_coin, sync_catalog, wait_for_coin, yes_no_prompt, CatNftMetadata, CatalogApiClient, CatalogPrecommitValue, CatalogRefundAction, CatalogRegisterAction, CatalogRegistryConstants, CatalogSlotValue, @@ -278,11 +278,9 @@ pub async fn catalog_register( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = - parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let sec_conds = if refund { let slot: Option> = if DefaultCatMakerArgs::curry_tree_hash( @@ -369,34 +367,34 @@ pub async fn catalog_register( .await? }; - catalog - .new_action::() - .spend( - &mut ctx, - &mut catalog, - registered_asset_id, - left_slot, - right_slot, - precommit_coin, - Spend { - puzzle: initial_nft_puzzle_ptr, - solution: NodePtr::NIL, - }, - )? - .0 + catalog.new_action::().spend( + &mut ctx, + &mut catalog, + registered_asset_id, + left_slot, + right_slot, + precommit_coin, + Spend { + puzzle: initial_nft_puzzle_ptr, + solution: NodePtr::NIL, + }, + )? }; - let _new_catalog = catalog.finish_spend(&mut ctx)?; + let (_new_catalog, pending_sig) = catalog.finish_spend(&mut ctx)?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds, &security_coin_sk, get_constants(testnet11), )?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); if log { @@ -409,7 +407,7 @@ pub async fn catalog_register( let resp = cli.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&cli, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&cli, security_coin.coin_id(), true).await?; println!("Confirmed!"); return Ok(()); diff --git a/src/cli/catalog/sync.rs b/src/cli/catalog/sync.rs index 09fe1933..37d2b6c4 100644 --- a/src/cli/catalog/sync.rs +++ b/src/cli/catalog/sync.rs @@ -1,11 +1,14 @@ +use std::collections::HashSet; + use chia::{ clvm_utils::{tree_hash, ToTreeHash}, protocol::{Bytes32, Coin}, puzzles::{singleton::LauncherSolution, LineageProof, Proof}, }; +use chia_puzzle_types::Memos; use chia_wallet_sdk::{ - coinset::{ChiaRpcClient, CoinRecord, CoinsetClient}, - driver::{Layer, Puzzle, SingletonLayer, SpendContext}, + coinset::{ChiaRpcClient, CoinsetClient}, + driver::{DriverError, Layer, Puzzle, SingletonLayer, SpendContext}, types::{Condition, Conditions}, }; use clvmr::NodePtr; @@ -21,110 +24,67 @@ pub async fn sync_catalog( ctx: &mut SpendContext, constants: CatalogRegistryConstants, ) -> Result { - let last_unspent_coin_info = db - .get_last_unspent_singleton_coin(constants.launcher_id) - .await?; - - let last_spent_coin_id: Bytes32 = - if let Some((_coin_id, parent_coin_id)) = last_unspent_coin_info { - parent_coin_id - } else { - constants.launcher_id - }; - - let mut last_coin_id = last_spent_coin_id; - let mut catalog: Option = None; - loop { - let coin_record_response = client.get_coin_record_by_name(last_coin_id).await?; - let Some(coin_record) = coin_record_response.coin_record else { - return Err(CliError::CoinNotFound(last_coin_id)); - }; - if !coin_record.spent { - break; - } + let (mut catalog, mut skip_save): (CatalogRegistry, bool) = + if let Some((_coin_id, parent_coin_id)) = db + .get_last_unspent_singleton_coin(constants.launcher_id) + .await? + { + let parent_record = client + .get_coin_record_by_name(parent_coin_id) + .await? + .coin_record + .ok_or(CliError::CoinNotFound(parent_coin_id))?; - let skip_db_save = last_coin_id == last_spent_coin_id; - if !skip_db_save { - db.save_singleton_coin(constants.launcher_id, coin_record) - .await?; - } + let parent_spend = client + .get_puzzle_and_solution(parent_coin_id, Some(parent_record.spent_block_index)) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(parent_coin_id))?; - let puzzle_and_solution_resp = client - .get_puzzle_and_solution( - coin_record.coin.coin_id(), - Some(coin_record.spent_block_index), + ( + CatalogRegistry::from_parent_spend(ctx, &parent_spend, constants)?.ok_or( + CliError::Custom("Could not parse latest spent CATalog registry".to_string()), + )?, + false, ) - .await?; - let Some(coin_spend) = puzzle_and_solution_resp.coin_solution else { - return Err(CliError::CoinNotSpent(last_coin_id)); - }; + } else { + // No result -> sync from launcher + let launcher_record = client + .get_coin_record_by_name(constants.launcher_id) + .await? + .coin_record + .ok_or(CliError::CoinNotFound(constants.launcher_id))?; - let puzzle_ptr = ctx.alloc(&coin_spend.puzzle_reveal)?; - let parent_puzzle = Puzzle::parse(ctx, puzzle_ptr); - let solution_ptr = ctx.alloc(&coin_spend.solution)?; - if !skip_db_save { - if let Some(ref prev_catalog) = catalog { - let new_slots = prev_catalog.get_new_slots_from_spend(ctx, solution_ptr)?; - - for slot in new_slots.iter() { - let asset_id = slot.info.value.asset_id; - - if let Some(previous_value_hash) = - db.get_catalog_indexed_slot_value(asset_id).await? - { - db.mark_slot_as_spent( - constants.launcher_id, - 0, - previous_value_hash, - coin_record.spent_block_index, - ) - .await?; - } - } - - for slot in new_slots { - db.save_catalog_indexed_slot_value( - slot.info.value.asset_id, - slot.info.value_hash, - ) - .await?; - db.save_slot(ctx, slot, 0).await?; - } - } - } + let launcher_spend = client + .get_puzzle_and_solution( + constants.launcher_id, + Some(launcher_record.spent_block_index), + ) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(constants.launcher_id))?; - if let Some(some_catalog) = CatalogRegistry::from_parent_spend( - ctx, - coin_record.coin, - parent_puzzle, - solution_ptr, - constants, - )? { - last_coin_id = some_catalog.coin.coin_id(); - catalog = Some(some_catalog); - } else if coin_record.coin.coin_id() == constants.launcher_id { + let solution_ptr = ctx.alloc(&launcher_spend.solution)?; let solution = ctx.extract::>(solution_ptr)?; let catalog_eve_coin = Coin::new(constants.launcher_id, solution.singleton_puzzle_hash, 1); let catalog_eve_coin_id = catalog_eve_coin.coin_id(); - let eve_coin_puzzle_and_solution_resp = client + let eve_coin_spend = client .get_puzzle_and_solution( catalog_eve_coin_id, - Some(coin_record.confirmed_block_index), + Some(launcher_record.confirmed_block_index), ) - .await?; - let Some(eve_coin_spend) = eve_coin_puzzle_and_solution_resp.coin_solution else { - break; - }; + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(catalog_eve_coin_id))?; let eve_coin_puzzle_ptr = ctx.alloc(&eve_coin_spend.puzzle_reveal)?; let eve_coin_puzzle = Puzzle::parse(ctx, eve_coin_puzzle_ptr); - let Some(eve_coin_puzzle) = - SingletonLayer::::parse_puzzle(ctx, eve_coin_puzzle)? - else { - break; - }; + let eve_coin_puzzle = SingletonLayer::::parse_puzzle(ctx, eve_coin_puzzle)? + .ok_or(DriverError::Custom( + "Could not parse eve CATalog coin puzzle".to_string(), + ))?; let eve_coin_inner_puzzle_hash = tree_hash(ctx, eve_coin_puzzle.inner_puzzle); @@ -142,15 +102,18 @@ pub async fn sync_catalog( } }) else { - break; + return Err(CliError::Custom( + "Could not find odd create coin in CATalog eve coin".to_string(), + )); }; + let Memos::Some(memos) = odd_create_coin.memos else { + return Err(CliError::Driver(DriverError::MissingHint)); + }; let (decoded_launcher_id, (_decoded_asset_id, (initial_state, ()))) = - ctx.extract::<(Bytes32, (Bytes32, (CatalogRegistryState, ())))>( - odd_create_coin.memos.unwrap().value, - )?; + ctx.extract::<(Bytes32, (Bytes32, (CatalogRegistryState, ())))>(memos)?; if decoded_launcher_id != constants.launcher_id { - break; + return Err(CliError::Custom("CATalog launcher ID mismatch".to_string())); } let new_coin = Coin::new( @@ -206,31 +169,154 @@ pub async fn sync_catalog( ) .await?; - db.save_singleton_coin( - constants.launcher_id, - CoinRecord { - coin: new_coin, - coinbase: false, - confirmed_block_index: coin_record.spent_block_index, - spent: false, - spent_block_index: 0, - timestamp: 0, - }, - ) - .await?; + // do NOT save eve coin - we're going through this path until + // first CATalog is spent + // db.save_singleton_coin( + // constants.launcher_id, + // CoinRecord { + // coin: new_coin, + // coinbase: false, + // confirmed_block_index: launcher_record.confirmed_block_index, + // spent: false, + // spent_block_index: 0, + // timestamp: 0, + // }, + // ) + // .await?; + + (new_catalog, true) + }; + + loop { + let coin_record = client + .get_coin_record_by_name(catalog.coin.coin_id()) + .await? + .coin_record + .ok_or(CliError::CoinNotFound(catalog.coin.coin_id()))?; - last_coin_id = new_catalog.coin.coin_id(); - catalog = Some(new_catalog); - } else if coin_record.coin.parent_coin_info == constants.launcher_id { - last_coin_id = constants.launcher_id; + if skip_save { + skip_save = false; } else { + db.save_singleton_coin(constants.launcher_id, coin_record) + .await?; + } + + if !coin_record.spent { break; - }; + } + + let coin_spend = client + .get_puzzle_and_solution( + coin_record.coin.coin_id(), + Some(coin_record.spent_block_index), + ) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(coin_record.coin.coin_id()))?; + + catalog = CatalogRegistry::from_spend(ctx, &coin_spend, constants)?.ok_or( + CliError::Custom("Could not parse new CATalog registry spend".to_string()), + )?; + + for slot_value in catalog.pending_spend.spent_slots.iter() { + let asset_id = slot_value.asset_id; + + if let Some(previous_value_hash) = db.get_catalog_indexed_slot_value(asset_id).await? { + db.mark_slot_as_spent( + constants.launcher_id, + 0, + previous_value_hash, + coin_record.spent_block_index, + ) + .await?; + } + } + + let mut processed_values = HashSet::::new(); + for slot_value in catalog.pending_spend.created_slots.iter() { + let slot_value_hash: Bytes32 = slot_value.tree_hash().into(); + if processed_values.contains(&slot_value_hash) { + continue; + } + processed_values.insert(slot_value_hash); + + // same slot can be created and spent mutliple times in the same block + let no_spent = catalog + .pending_spend + .spent_slots + .iter() + .filter(|sv| sv == &slot_value) + .count(); + let no_created = catalog + .pending_spend + .created_slots + .iter() + .filter(|sv| sv == &slot_value) + .count(); + if no_spent >= no_created { + continue; + } + + db.save_catalog_indexed_slot_value(slot_value.asset_id, slot_value_hash) + .await?; + db.save_slot(ctx, catalog.created_slot_value_to_slot(*slot_value), 0) + .await?; + } + + catalog = catalog.child(catalog.pending_spend.latest_state.1); } - if let Some(catalog) = catalog { - Ok(catalog) - } else { - Err(CliError::CoinNotFound(last_coin_id)) + mempool_catalog_maybe(ctx, catalog, client).await +} + +pub async fn mempool_catalog_maybe( + ctx: &mut SpendContext, + on_chain_catalog: CatalogRegistry, + client: &CoinsetClient, +) -> Result { + let Some(mut mempool_items) = client + .get_mempool_items_by_coin_name(on_chain_catalog.coin.coin_id()) + .await? + .mempool_items + else { + return Ok(on_chain_catalog); + }; + + if mempool_items.is_empty() { + return Ok(on_chain_catalog); } + + let mempool_item = mempool_items.remove(0); + let mut catalog = on_chain_catalog; + let mut parent_id_to_look_for = catalog.coin.parent_coin_info; + loop { + let Some(catalog_spend) = mempool_item + .spend_bundle + .coin_spends + .iter() + .find(|c| c.coin.parent_coin_info == parent_id_to_look_for) + else { + break; + }; + + let Some(new_catalog) = + CatalogRegistry::from_spend(ctx, catalog_spend, catalog.info.constants)? + else { + break; + }; + catalog = new_catalog; + parent_id_to_look_for = catalog.coin.coin_id(); + } + + mempool_item + .spend_bundle + .coin_spends + .into_iter() + .for_each(|coin_spend| { + if coin_spend.coin != catalog.coin { + ctx.insert(coin_spend); + } + }); + catalog.set_pending_signature(mempool_item.spend_bundle.aggregated_signature); + Ok(catalog) } diff --git a/src/cli/catalog/unroll_state_scheduler.rs b/src/cli/catalog/unroll_state_scheduler.rs index fb37e7ce..aca3f04a 100644 --- a/src/cli/catalog/unroll_state_scheduler.rs +++ b/src/cli/catalog/unroll_state_scheduler.rs @@ -1,12 +1,12 @@ use chia::protocol::{Bytes32, SpendBundle}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Offer, SpendContext}, - types::{MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, + driver::{decode_offer, Offer, SpendContext}, + types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; use crate::{ - assets_xch_only, get_coinset_client, new_sk, no_assets, parse_amount, parse_one_sided_offer, + assets_xch_only, create_security_coin, get_coinset_client, no_assets, parse_amount, spend_security_coin, sync_multisig_singleton, wait_for_coin, yes_no_prompt, CatalogRegistryConstants, CatalogRegistryState, CliError, Db, DelegatedStateAction, MultisigSingleton, SageClient, @@ -89,30 +89,27 @@ pub async fn catalog_unroll_state_scheduler( new_state, state_scheduler.info.inner_puzzle_hash().into(), )?; - catalog.insert(catalog_action_spend); + catalog.insert_action_spend(&mut ctx, catalog_action_spend)?; let catalog_inner_ph = catalog.info.inner_puzzle_hash(); - let _new_catalog = catalog.finish_spend(&mut ctx)?; + let (_new_catalog, pending_sig) = catalog.finish_spend(&mut ctx)?; let offer_resp = sage .make_offer(no_assets(), assets_xch_only(1), fee, None, None, false) .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); - - let security_coin_conditions = offer - .security_base_conditions + let security_coin_conditions = Conditions::new() .assert_concurrent_spend(state_scheduler.coin.coin_id()) .reserve_fee(1); let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, if testnet11 { @@ -124,14 +121,17 @@ pub async fn catalog_unroll_state_scheduler( state_scheduler.spend(&mut ctx, catalog_inner_ph.into())?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let resp = cli.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&cli, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&cli, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/catalog/verify_deployment.rs b/src/cli/catalog/verify_deployment.rs index 994c47ce..6ca02854 100644 --- a/src/cli/catalog/verify_deployment.rs +++ b/src/cli/catalog/verify_deployment.rs @@ -3,7 +3,9 @@ use chia::protocol::{Bytes32, Coin}; use chia::puzzles::nft::{NftOwnershipLayerArgs, NftRoyaltyTransferPuzzleArgs, NftStateLayerArgs}; use chia::puzzles::singleton::SingletonArgs; use chia::puzzles::{LineageProof, Proof}; +use chia_puzzle_types::Memos; use chia_puzzles::{NFT_STATE_LAYER_HASH, SINGLETON_LAUNCHER_HASH}; +use chia_wallet_sdk::driver::DriverError; use chia_wallet_sdk::{ coinset::ChiaRpcClient, driver::{Layer, Puzzle, SingletonLayer, SpendContext}, @@ -143,10 +145,11 @@ pub async fn catalog_verify_deployment(testnet11: bool) -> Result<(), CliError> )); } - let (hinted_launcher_id, (initial_registration_asset_id, (initial_state, ()))) = ctx - .extract::<(Bytes32, (Bytes32, (CatalogRegistryState, ())))>( - catalog_cc.memos.unwrap().value, - )?; + let Memos::Some(memos) = catalog_cc.memos else { + return Err(CliError::Driver(DriverError::MissingHint)); + }; + let (hinted_launcher_id, (initial_registration_asset_id, (initial_state, ()))) = + ctx.extract::<(Bytes32, (Bytes32, (CatalogRegistryState, ())))>(memos)?; let catalog_info = CatalogRegistryInfo::new(initial_state, catalog_constants); let catalog_full_ph = SingletonArgs::curry_tree_hash( @@ -204,14 +207,15 @@ pub async fn catalog_verify_deployment(testnet11: bool) -> Result<(), CliError> break; }; - let solution = node_from_bytes(&mut ctx, &coin_spend.solution)?; - let new_slots = catalog.get_new_slots_from_spend(&mut ctx, solution)?; + catalog = + CatalogRegistry::from_spend(&mut ctx, &coin_spend, catalog.info.constants)?.unwrap(); + let new_slot_values = &catalog.pending_spend.created_slots; while cat_index < cats_to_launch.len() { let top_cat = &cats_to_launch[cat_index]; - let found = new_slots + let found = new_slot_values .iter() - .find(|slot| slot.info.value.asset_id == top_cat.asset_id); + .find(|slot_value| slot_value.asset_id == top_cat.asset_id); if found.is_some() { cat_index += 1; @@ -243,7 +247,7 @@ pub async fn catalog_verify_deployment(testnet11: bool) -> Result<(), CliError> NftRoyaltyTransferPuzzleArgs::curry_tree_hash( cat_nft_launcher_id, catalog_constants.royalty_address, - catalog_constants.royalty_ten_thousandths, + catalog_constants.royalty_basis_points, ), eve_nft_inner_puzzle_hash, ), @@ -269,16 +273,8 @@ pub async fn catalog_verify_deployment(testnet11: bool) -> Result<(), CliError> } } - let puzzle_ptr = node_from_bytes(&mut ctx, &coin_spend.puzzle_reveal)?; - let parent_puzzle = Puzzle::parse(&ctx, puzzle_ptr); - catalog = CatalogRegistry::from_parent_spend( - &mut ctx, - catalog.coin, - parent_puzzle, - solution, - catalog.info.constants, - )? - .unwrap(); + // this coin's confirmed, move to the child + catalog = catalog.child(catalog.pending_spend.latest_state.1); } if cat_index < cats_to_launch.len() { diff --git a/src/cli/commands.rs b/src/cli/commands.rs index 55d5591d..a363e703 100644 --- a/src/cli/commands.rs +++ b/src/cli/commands.rs @@ -511,9 +511,9 @@ enum XchandlesCliAction { #[arg(long)] handle: String, - /// Number of years to extend the handle for + /// Number of periods (e.g., years) to extend the handle for #[arg(long, default_value = "1")] - years: u64, + num_periods: u64, /// Use testnet11 #[arg(long, default_value_t = false)] @@ -1331,7 +1331,7 @@ pub async fn run_cli() { XchandlesCliAction::Extend { launcher_id, handle, - years, + num_periods, testnet11, payment_asset_id, payment_cat_base_price, @@ -1342,7 +1342,7 @@ pub async fn run_cli() { xchandles_extend( launcher_id, handle, - years, + num_periods, testnet11, payment_asset_id, payment_cat_base_price, diff --git a/src/cli/database.rs b/src/cli/database.rs index f967ccc8..10cef3bd 100644 --- a/src/cli/database.rs +++ b/src/cli/database.rs @@ -112,24 +112,9 @@ impl Db { sqlx::query( " - CREATE TABLE IF NOT EXISTS dig_indexed_slot_values_by_epoch_start ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - epoch_start INTEGER NOT NULL, - nonce INTEGER NOT NULL, - slot_value_hash BLOB NOT NULL - ) - ", - ) - .execute(&pool) - .await?; - - sqlx::query( - " - CREATE TABLE IF NOT EXISTS dig_indexed_slot_values_by_puzzle_hash ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - puzzle_hash BLOB NOT NULL, - nonce INTEGER NOT NULL, - slot_value_hash BLOB NOT NULL + CREATE TABLE IF NOT EXISTS xchandles_configurations ( + launcher_id BLOB PRIMARY KEY, + constants BLOB NOT NULL ) ", ) @@ -137,17 +122,6 @@ impl Db { .await?; } - sqlx::query( - " - CREATE TABLE IF NOT EXISTS xchandles_configurations ( - launcher_id BLOB PRIMARY KEY, - constants BLOB NOT NULL - ) - ", - ) - .execute(&pool) - .await?; - Ok(Self { pool }) } @@ -818,124 +792,6 @@ impl Db { Ok(Some(constants)) } - - pub async fn save_dig_indexed_slot_value_by_epoch_start( - &self, - epoch_start: u64, - nonce: u64, - slot_value_hash: Bytes32, - ) -> Result<(), CliError> { - sqlx::query( - " - INSERT INTO dig_indexed_slot_values_by_epoch_start (epoch_start, nonce, slot_value_hash) VALUES (?1, ?2, ?3) - ", - ) - .bind(epoch_start as i64) - .bind(nonce as i64) - .bind(slot_value_hash.to_vec()) - .execute(&self.pool) - .await - .map_err(CliError::Sqlx)?; - - Ok(()) - } - - pub async fn save_dig_indexed_slot_value_by_puzzle_hash( - &self, - puzzle_hash: Bytes32, - nonce: u64, - slot_value_hash: Bytes32, - ) -> Result<(), CliError> { - sqlx::query( - " - INSERT INTO dig_indexed_slot_values_by_puzzle_hash (puzzle_hash, nonce, slot_value_hash) VALUES (?1, ?2, ?3) - ", - ) - .bind(puzzle_hash.to_vec()) - .bind(nonce as i64) - .bind(slot_value_hash.to_vec()) - .execute(&self.pool) - .await - .map_err(CliError::Sqlx)?; - - Ok(()) - } - - pub async fn get_dig_indexed_slot_values_by_epoch_start( - &self, - epoch_start: u64, - nonce: u64, - ) -> Result, CliError> { - let row = sqlx::query( - " - SELECT slot_value_hash FROM dig_indexed_slot_values_by_epoch_start WHERE epoch_start = ?1 AND nonce = ?2 - ", - ) - .bind(epoch_start as i64) - .bind(nonce as i64) - .fetch_all(&self.pool) - .await - .map_err(CliError::Sqlx)?; - - row.into_iter() - .map(|row| column_to_bytes32(row.get::<&[u8], _>("slot_value_hash"))) - .collect::, _>>() - } - - pub async fn get_dig_indexed_slot_values_by_puzzle_hash( - &self, - puzzle_hash: Bytes32, - nonce: u64, - ) -> Result, CliError> { - let row = sqlx::query( - " - SELECT slot_value_hash FROM dig_indexed_slot_values_by_puzzle_hash WHERE puzzle_hash = ?1 AND nonce = ?2 - ", - ) - .bind(puzzle_hash.to_vec()) - .bind(nonce as i64) - .fetch_all(&self.pool) - .await - .map_err(CliError::Sqlx)?; - - row.into_iter() - .map(|row| column_to_bytes32(row.get::<&[u8], _>("slot_value_hash"))) - .collect::, _>>() - } - - pub async fn delete_dig_indexed_slot_values_by_epoch_start_using_value_hash( - &self, - value_hash: Bytes32, - ) -> Result<(), CliError> { - sqlx::query( - " - DELETE FROM dig_indexed_slot_values_by_epoch_start WHERE slot_value_hash = ?1 - ", - ) - .bind(value_hash.to_vec()) - .execute(&self.pool) - .await - .map_err(CliError::Sqlx)?; - - Ok(()) - } - - pub async fn delete_dig_indexed_slot_values_by_puzzle_hash_using_value_hash( - &self, - value_hash: Bytes32, - ) -> Result<(), CliError> { - sqlx::query( - " - DELETE FROM dig_indexed_slot_values_by_puzzle_hash WHERE slot_value_hash = ?1 - ", - ) - .bind(value_hash.to_vec()) - .execute(&self.pool) - .await - .map_err(CliError::Sqlx)?; - - Ok(()) - } } pub fn column_to_bytes32(column_value: &[u8]) -> Result { diff --git a/src/cli/multisig/broadcast_thing.rs b/src/cli/multisig/broadcast_thing.rs index 86f869ae..e2e07fe0 100644 --- a/src/cli/multisig/broadcast_thing.rs +++ b/src/cli/multisig/broadcast_thing.rs @@ -4,13 +4,13 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{Offer, SpendContext}, + driver::{decode_offer, Offer, SpendContext}, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; use crate::{ - assets_xch_only, get_coinset_client, hex_string_to_bytes32, hex_string_to_signature, new_sk, - no_assets, parse_amount, parse_one_sided_offer, print_medieval_vault_configuration, + assets_xch_only, create_security_coin, get_coinset_client, hex_string_to_bytes32, + hex_string_to_signature, no_assets, parse_amount, print_medieval_vault_configuration, spend_security_coin, sync_multisig_singleton, wait_for_coin, yes_no_prompt, CliError, MedievalVault, MultisigSingleton, SageClient, StateSchedulerHintedState, }; @@ -101,21 +101,18 @@ pub async fn multisig_broadcast_thing_finish( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(ctx, offer.offered_coins().xch[0])?; - let mut conditions = offer - .security_base_conditions - .assert_concurrent_spend(medieval_vault_coin_id); + let mut conditions = Conditions::new().assert_concurrent_spend(medieval_vault_coin_id); if let Some(additional_security_conditions) = additional_security_conditions { conditions = conditions.extend(additional_security_conditions); } let security_coin_sig = spend_security_coin( ctx, - offer.security_coin, + security_coin, conditions, &security_coin_sk, if testnet11 { @@ -125,16 +122,16 @@ pub async fn multisig_broadcast_thing_finish( }, )?; - let sb = SpendBundle::new( + let sb = offer.take(SpendBundle::new( ctx.take(), - offer.aggregated_signature + &security_coin_sig + &signature_from_signers, - ); + security_coin_sig + &signature_from_signers, + )); println!("Submitting transaction..."); let resp = client.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/multisig/launch.rs b/src/cli/multisig/launch.rs index bce4a1a1..4cc9ce70 100644 --- a/src/cli/multisig/launch.rs +++ b/src/cli/multisig/launch.rs @@ -1,12 +1,12 @@ use chia::{bls::PublicKey, protocol::SpendBundle}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Launcher, Offer, SpendContext}, + driver::{decode_offer, Launcher, Offer, SpendContext}, }; use crate::{ - assets_xch_only, get_coinset_client, get_constants, new_sk, no_assets, parse_amount, - parse_one_sided_offer, print_medieval_vault_configuration, spend_security_coin, wait_for_coin, + assets_xch_only, create_security_coin, get_coinset_client, get_constants, no_assets, + parse_amount, print_medieval_vault_configuration, spend_security_coin, wait_for_coin, yes_no_prompt, CliError, MedievalVaultHint, P2MOfNDelegateDirectArgs, SageClient, }; @@ -46,12 +46,11 @@ pub async fn multisig_launch( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let launcher = Launcher::new(offer.security_coin.coin_id(), 1); + let launcher = Launcher::new(security_coin.coin_id(), 1); let launcher_coin = launcher.coin(); let launch_hints = MedievalVaultHint { my_launcher_id: launcher_coin.coin_id(), @@ -71,13 +70,13 @@ pub async fn multisig_launch( let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(create_conditions), + security_coin, + create_conditions, &security_coin_sk, get_constants(testnet11), )?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new(ctx.take(), security_coin_sig)); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -85,7 +84,7 @@ pub async fn multisig_launch( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/reward_distributor.rs b/src/cli/reward_distributor.rs index 581dff68..889cc103 100644 --- a/src/cli/reward_distributor.rs +++ b/src/cli/reward_distributor.rs @@ -2,7 +2,6 @@ mod add_rewards; mod broadcast_entry_update; mod clawback_rewards; mod commit_rewards; -mod find_slot; mod initiate_payout; mod launch; mod new_epoch; @@ -17,7 +16,6 @@ pub use add_rewards::*; pub use broadcast_entry_update::*; pub use clawback_rewards::*; pub use commit_rewards::*; -pub use find_slot::*; pub use initiate_payout::*; pub use launch::*; pub use new_epoch::*; diff --git a/src/cli/reward_distributor/add_rewards.rs b/src/cli/reward_distributor/add_rewards.rs index e248391e..2d086131 100644 --- a/src/cli/reward_distributor/add_rewards.rs +++ b/src/cli/reward_distributor/add_rewards.rs @@ -1,15 +1,14 @@ -use chia::protocol::{Bytes32, SpendBundle}; -use chia_puzzle_types::offer::{NotarizedPayment, Payment}; +use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{CatSpend, Offer, Spend, SpendContext}, - types::Conditions, + driver::{decode_offer, CatSpend, Offer, Spend, SpendContext}, + types::{puzzles::SettlementPayment, Conditions}, }; use clvmr::NodePtr; use crate::{ - assets_xch_and_cat, get_coinset_client, get_constants, get_last_onchain_timestamp, - hex_string_to_bytes32, new_sk, no_assets, parse_amount, parse_one_sided_offer, + assets_xch_and_cat, create_security_coin, get_coinset_client, get_constants, + get_last_onchain_timestamp, hex_string_to_bytes32, no_assets, parse_amount, spend_security_coin, sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, RewardDistributorAddIncentivesAction, RewardDistributorSyncAction, SageClient, }; @@ -72,26 +71,9 @@ pub async fn reward_distributor_add_rewards( .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let cat_destination_inner_puzzle = ctx.alloc(&(1, ()))?; - let cat_destination_inner_puzzle_hash: Bytes32 = - ctx.tree_hash(cat_destination_inner_puzzle).into(); - let offer = parse_one_sided_offer( - &mut ctx, - offer, - security_coin_sk.public_key(), - Some(NotarizedPayment { - nonce: launcher_id, - payments: vec![Payment::with_memos( - cat_destination_inner_puzzle_hash, - reward_amount, - vec![cat_destination_inner_puzzle_hash.into()], - )], - }), - None, - )?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let mut sec_conds = if also_sync { distributor @@ -106,25 +88,37 @@ pub async fn reward_distributor_add_rewards( .new_action::() .spend(&mut ctx, &mut distributor, reward_amount)?, ); - let _new_distributor = distributor.finish_spend( + + let settlement_cat = offer + .offered_coins() + .cats + .get(&distributor.info.constants.reserve_asset_id) + .ok_or(CliError::Custom( + "Reward CAT not found in offer".to_string(), + ))?[0]; + let offer_puzzle = ctx.alloc_mod::()?; + + let (_new_distributor, pending_sig) = distributor.finish_spend( &mut ctx, vec![CatSpend { - cat: offer.created_cat.unwrap(), - inner_spend: Spend::new(cat_destination_inner_puzzle, NodePtr::NIL), - extra_delta: 0, + cat: settlement_cat, + spend: Spend::new(offer_puzzle, NodePtr::NIL), + hidden: false, }], )?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds, &security_coin_sk, get_constants(testnet11), )?; - let spend_bundle = - SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let spend_bundle = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -132,7 +126,7 @@ pub async fn reward_distributor_add_rewards( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/reward_distributor/broadcast_entry_update.rs b/src/cli/reward_distributor/broadcast_entry_update.rs index bce4b7ce..cad740ee 100644 --- a/src/cli/reward_distributor/broadcast_entry_update.rs +++ b/src/cli/reward_distributor/broadcast_entry_update.rs @@ -3,10 +3,10 @@ use chia::{clvm_utils::ToTreeHash, protocol::Bytes}; use clvmr::{Allocator, NodePtr}; use crate::{ - find_entry_slot_for_puzzle_hash, get_constants, get_last_onchain_timestamp, - hex_string_to_bytes32, multisig_broadcast_thing_finish, multisig_broadcast_thing_start, - sync_distributor, CliError, Db, MedievalVault, RewardDistributorAddEntryAction, - RewardDistributorRemoveEntryAction, RewardDistributorSyncAction, StateSchedulerLayerSolution, + find_entry_slots, get_constants, get_last_onchain_timestamp, hex_string_to_bytes32, + multisig_broadcast_thing_finish, multisig_broadcast_thing_start, sync_distributor, CliError, + Db, MedievalVault, RewardDistributorAddEntryAction, RewardDistributorRemoveEntryAction, + RewardDistributorSyncAction, StateSchedulerLayerSolution, }; pub async fn reward_distributor_broadcast_entry_update( @@ -104,14 +104,17 @@ pub async fn reward_distributor_broadcast_entry_update( if remove_entry { println!("Finding entry slot..."); - let entry_slot = find_entry_slot_for_puzzle_hash( + let entry_slot = find_entry_slots( &mut ctx, - &db, - launcher_id, + &client, + reward_distributor.info.constants, entry_payout_puzzle_hash, + None, Some(entry_shares), ) .await? + .into_iter() + .next() .ok_or(CliError::SlotNotFound("Mirror"))?; let (_conds, last_payment_amount) = reward_distributor @@ -127,7 +130,7 @@ pub async fn reward_distributor_broadcast_entry_update( last_payment_amount ); } else { - let (_conds, _new_slot) = reward_distributor + let _conds = reward_distributor .new_action::() .spend( &mut ctx, @@ -137,12 +140,12 @@ pub async fn reward_distributor_broadcast_entry_update( medieval_vault_inner_ph.into(), )?; } - let mut _new_distributor = reward_distributor.finish_spend(&mut ctx, vec![])?; + let (_new_distributor, pending_sig) = reward_distributor.finish_spend(&mut ctx, vec![])?; multisig_broadcast_thing_finish( client, &mut ctx, - signature_from_signers, + signature_from_signers + &pending_sig, fee_str, testnet11, medieval_vault_coin_id, diff --git a/src/cli/reward_distributor/clawback_rewards.rs b/src/cli/reward_distributor/clawback_rewards.rs index 081bbc37..9d36cf47 100644 --- a/src/cli/reward_distributor/clawback_rewards.rs +++ b/src/cli/reward_distributor/clawback_rewards.rs @@ -1,18 +1,20 @@ use chia::protocol::{Coin, SpendBundle}; +use chia_puzzle_types::Memos; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Offer, Spend, SpendContext, StandardLayer}, + driver::{decode_offer, Offer, Spend, SpendContext, StandardLayer}, + types::Conditions, utils::Address, }; use clvm_traits::clvm_quote; use clvmr::NodePtr; use crate::{ - assets_xch_only, find_commitment_slot_for_puzzle_hash, find_reward_slot_for_epoch, + assets_xch_only, create_security_coin, find_commitment_slots, find_reward_slot, get_coin_public_key, get_coinset_client, get_constants, hex_string_to_bytes32, - hex_string_to_signature, new_sk, no_assets, parse_amount, parse_one_sided_offer, - spend_security_coin, spend_to_coin_spend, sync_distributor, wait_for_coin, yes_no_prompt, - CliError, Db, RewardDistributorWithdrawIncentivesAction, SageClient, + hex_string_to_signature, no_assets, parse_amount, spend_security_coin, spend_to_coin_spend, + sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, + RewardDistributorWithdrawIncentivesAction, SageClient, }; pub async fn reward_distributor_clawback_rewards( @@ -37,25 +39,26 @@ pub async fn reward_distributor_clawback_rewards( println!("Fetching slots..."); let clawback_ph = Address::decode(&clawback_address)?.puzzle_hash; - let commitment_slot = find_commitment_slot_for_puzzle_hash( + + let commitment_slot = find_commitment_slots( &mut ctx, - &db, - launcher_id, + &client, + distributor.info.constants, clawback_ph, epoch_start, reward_amount, ) .await? + .into_iter() + .next() .ok_or(CliError::SlotNotFound("Commitment"))?; - let reward_slot = find_reward_slot_for_epoch( + let reward_slot = find_reward_slot( &mut ctx, - &db, - launcher_id, + &client, + distributor.info.constants, commitment_slot.info.value.epoch_start, - distributor.info.constants.epoch_seconds, ) - .await? - .ok_or(CliError::SlotNotFound("Reward"))?; + .await?; println!( "Will use commitment slot with rewards={} for epoch_start={}", @@ -76,31 +79,28 @@ pub async fn reward_distributor_clawback_rewards( .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let (send_message_conds, _slot1, returned_amount) = distributor + let (send_message_conds, returned_amount) = distributor .new_action::() .spend(&mut ctx, &mut distributor, commitment_slot, reward_slot)?; - let _new_distributor = distributor.finish_spend(&mut ctx, vec![])?; + let (_new_distributor, pending_sig) = distributor.finish_spend(&mut ctx, vec![])?; println!("Returned amount: {} CAT mojos", returned_amount); let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer - .security_base_conditions - .create_coin(clawback_ph, 0, None), + security_coin, + Conditions::new().create_coin(clawback_ph, 0, Memos::None), &security_coin_sk, get_constants(testnet11), )?; println!("Fetching clawback public key..."); let wallet_pk = get_coin_public_key(&sage, &clawback_address, 10000).await?; - let message_coin = Coin::new(offer.security_coin.coin_id(), clawback_ph, 0); + let message_coin = Coin::new(security_coin.coin_id(), clawback_ph, 0); let p2 = StandardLayer::new(wallet_pk); let inner_spend = Spend::new(ctx.alloc(&clvm_quote!(send_message_conds))?, NodePtr::NIL); let spend = p2.delegated_inner_spend(&mut ctx, inner_spend)?; @@ -123,10 +123,10 @@ pub async fn reward_distributor_clawback_rewards( let message_sig = hex_string_to_signature(&resp.spend_bundle.aggregated_signature)?; - let spend_bundle = SpendBundle::new( + let spend_bundle = offer.take(SpendBundle::new( ctx.take(), - offer.aggregated_signature + &security_coin_sig + &message_sig, - ); + security_coin_sig + &message_sig + &pending_sig, + )); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -134,7 +134,7 @@ pub async fn reward_distributor_clawback_rewards( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/reward_distributor/commit_rewards.rs b/src/cli/reward_distributor/commit_rewards.rs index 1d19ea9c..b8040436 100644 --- a/src/cli/reward_distributor/commit_rewards.rs +++ b/src/cli/reward_distributor/commit_rewards.rs @@ -1,17 +1,17 @@ -use chia::protocol::{Bytes32, SpendBundle}; -use chia_puzzle_types::offer::{NotarizedPayment, Payment}; +use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{CatSpend, Offer, Spend, SpendContext}, + driver::{decode_offer, CatSpend, Offer, Spend, SpendContext}, + types::puzzles::SettlementPayment, utils::Address, }; use clvmr::NodePtr; use crate::{ - assets_xch_and_cat, find_reward_slot_for_epoch, get_coinset_client, get_constants, - hex_string_to_bytes32, new_sk, no_assets, parse_amount, parse_one_sided_offer, - spend_security_coin, sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, - RewardDistributorCommitIncentivesAction, SageClient, + assets_xch_and_cat, create_security_coin, find_reward_slot, get_coinset_client, get_constants, + hex_string_to_bytes32, no_assets, parse_amount, spend_security_coin, sync_distributor, + wait_for_coin, yes_no_prompt, CliError, Db, RewardDistributorCommitIncentivesAction, + SageClient, }; pub async fn reward_distributor_commit_rewards( @@ -61,38 +61,14 @@ pub async fn reward_distributor_commit_rewards( .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let cat_destination_inner_puzzle = ctx.alloc(&(1, ()))?; - let cat_destination_inner_puzzle_hash: Bytes32 = - ctx.tree_hash(cat_destination_inner_puzzle).into(); - let offer = parse_one_sided_offer( - &mut ctx, - offer, - security_coin_sk.public_key(), - Some(NotarizedPayment { - nonce: launcher_id, - payments: vec![Payment::with_memos( - cat_destination_inner_puzzle_hash, - reward_amount, - vec![cat_destination_inner_puzzle_hash.into()], - )], - }), - None, - )?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let reward_slot = find_reward_slot_for_epoch( - &mut ctx, - &db, - launcher_id, - epoch_start, - distributor.info.constants.epoch_seconds, - ) - .await? - .ok_or(CliError::SlotNotFound("Reward"))?; - - let (sec_conds, _slot1, _slot2) = distributor + let reward_slot = + find_reward_slot(&mut ctx, &client, distributor.info.constants, epoch_start).await?; + + let sec_conds = distributor .new_action::() .spend( &mut ctx, @@ -102,25 +78,35 @@ pub async fn reward_distributor_commit_rewards( clawback_ph, reward_amount, )?; - let _new_distributor = distributor.finish_spend( + let settlement_cat = offer + .offered_coins() + .cats + .get(&distributor.info.constants.reserve_asset_id) + .ok_or(CliError::Custom( + "Reward CAT not found in offer".to_string(), + ))?[0]; + let offer_puzzle = ctx.alloc_mod::()?; + let (_new_distributor, pending_sig) = distributor.finish_spend( &mut ctx, vec![CatSpend { - cat: offer.created_cat.unwrap(), - inner_spend: Spend::new(cat_destination_inner_puzzle, NodePtr::NIL), - extra_delta: 0, + cat: settlement_cat, + spend: Spend::new(offer_puzzle, NodePtr::NIL), + hidden: false, }], )?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds, &security_coin_sk, get_constants(testnet11), )?; - let spend_bundle = - SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let spend_bundle = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -128,7 +114,7 @@ pub async fn reward_distributor_commit_rewards( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/reward_distributor/find_slot.rs b/src/cli/reward_distributor/find_slot.rs deleted file mode 100644 index 261b9b5c..00000000 --- a/src/cli/reward_distributor/find_slot.rs +++ /dev/null @@ -1,129 +0,0 @@ -use chia::protocol::Bytes32; -use chia_wallet_sdk::driver::SpendContext; - -use crate::{ - CliError, Db, RewardDistributorCommitmentSlotValue, RewardDistributorEntrySlotValue, - RewardDistributorRewardSlotValue, RewardDistributorSlotNonce, Slot, -}; - -pub async fn find_reward_slot_for_epoch( - ctx: &mut SpendContext, - db: &Db, - launcher_id: Bytes32, - epoch_start: u64, - epoch_seconds: u64, -) -> Result>, CliError> { - let mut next_slot_epoch = epoch_start; - let mut reward_slot = None; - - let mut n = 0; - while reward_slot.is_none() && n <= 52 { - let nonce = RewardDistributorSlotNonce::REWARD.to_u64(); - let reward_slot_value_hashes = db - .get_dig_indexed_slot_values_by_epoch_start(next_slot_epoch, nonce) - .await?; - - // 0 or 1 value hashes per epoch - for reward_slot_value_hash in reward_slot_value_hashes { - if let Some(found_reward_slot) = db - .get_slot::( - ctx, - launcher_id, - nonce, - reward_slot_value_hash, - 0, - ) - .await? - { - reward_slot = Some(found_reward_slot); - break; - } - } - - next_slot_epoch -= epoch_seconds; - n += 1; - } - - Ok(reward_slot) -} - -pub async fn find_commitment_slot_for_puzzle_hash( - ctx: &mut SpendContext, - db: &Db, - launcher_id: Bytes32, - clawback_ph: Bytes32, - epoch_start: Option, - reward_amount: Option, -) -> Result>, CliError> { - let nonce = RewardDistributorSlotNonce::COMMITMENT.to_u64(); - let value_hashes = db - .get_dig_indexed_slot_values_by_puzzle_hash(clawback_ph, nonce) - .await?; - - let mut slot = None; - for value_hash in value_hashes { - let Some(commitment_slot) = db - .get_slot::( - ctx, - launcher_id, - nonce, - value_hash, - 0, - ) - .await? - else { - continue; - }; - - if let Some(reward_amount) = reward_amount { - if commitment_slot.info.value.rewards != reward_amount { - continue; - } - } - - if let Some(epoch_start) = epoch_start { - if commitment_slot.info.value.epoch_start != epoch_start { - continue; - } - } - - slot = Some(commitment_slot); - break; - } - - Ok(slot) -} - -pub async fn find_entry_slot_for_puzzle_hash( - ctx: &mut SpendContext, - db: &Db, - launcher_id: Bytes32, - entry_payout_puzzle_hash: Bytes32, - entry_shares: Option, -) -> Result>, CliError> { - let nonce = RewardDistributorSlotNonce::ENTRY.to_u64(); - let value_hashes = db - .get_dig_indexed_slot_values_by_puzzle_hash(entry_payout_puzzle_hash, nonce) - .await?; - - let mut slot = None; - for value_hash in value_hashes { - let Some(entry_slot) = db - .get_slot::(ctx, launcher_id, nonce, value_hash, 0) - .await? - else { - continue; - }; - - if let Some(entry_shares) = entry_shares { - if entry_slot.info.value.shares != entry_shares { - continue; - } - } - - slot = Some(entry_slot); - break; - } - - Ok(slot) -} diff --git a/src/cli/reward_distributor/initiate_payout.rs b/src/cli/reward_distributor/initiate_payout.rs index d5c4292e..347af80a 100644 --- a/src/cli/reward_distributor/initiate_payout.rs +++ b/src/cli/reward_distributor/initiate_payout.rs @@ -1,15 +1,15 @@ use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Offer, SpendContext}, + driver::{decode_offer, Offer, SpendContext}, types::Conditions, }; use crate::{ - assets_xch_only, find_entry_slot_for_puzzle_hash, get_coinset_client, get_constants, - get_last_onchain_timestamp, hex_string_to_bytes32, new_sk, no_assets, parse_amount, - parse_one_sided_offer, spend_security_coin, sync_distributor, wait_for_coin, yes_no_prompt, - CliError, Db, RewardDistributorInitiatePayoutAction, RewardDistributorSyncAction, SageClient, + assets_xch_only, create_security_coin, find_entry_slots, get_coinset_client, get_constants, + get_last_onchain_timestamp, hex_string_to_bytes32, no_assets, parse_amount, + spend_security_coin, sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, + RewardDistributorInitiatePayoutAction, RewardDistributorSyncAction, SageClient, }; pub async fn reward_distributor_initiate_payout( @@ -44,11 +44,19 @@ pub async fn reward_distributor_initiate_payout( ); } - println!("Finding reward slot..."); - let slot = - find_entry_slot_for_puzzle_hash(&mut ctx, &db, launcher_id, payout_puzzle_hash, None) - .await? - .ok_or(CliError::SlotNotFound("Mirror reward"))?; + println!("Finding entry slot..."); + let slot = find_entry_slots( + &mut ctx, + &client, + distributor.info.constants, + payout_puzzle_hash, + None, + None, + ) + .await? + .into_iter() + .next() + .ok_or(CliError::SlotNotFound("Entry"))?; println!("A one-sided offer will be created. It will contain:"); println!(" 1 mojo",); @@ -63,10 +71,9 @@ pub async fn reward_distributor_initiate_payout( .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let mut sec_conds = if also_sync { distributor @@ -76,24 +83,26 @@ pub async fn reward_distributor_initiate_payout( Conditions::new() }; - let (new_conds, _new_slot, payout_amount) = distributor + let (new_conds, payout_amount) = distributor .new_action::() .spend(&mut ctx, &mut distributor, slot)?; sec_conds = sec_conds.extend(new_conds); - let _new_distributor = distributor.finish_spend(&mut ctx, vec![])?; + let (_new_distributor, pending_sig) = distributor.finish_spend(&mut ctx, vec![])?; println!("Payout amount: {} CAT mojos", payout_amount); let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds, &security_coin_sk, get_constants(testnet11), )?; - let spend_bundle = - SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let spend_bundle = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -101,7 +110,7 @@ pub async fn reward_distributor_initiate_payout( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/reward_distributor/launch.rs b/src/cli/reward_distributor/launch.rs index 4f94421d..1c3b1de9 100644 --- a/src/cli/reward_distributor/launch.rs +++ b/src/cli/reward_distributor/launch.rs @@ -1,7 +1,7 @@ use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Offer, SpendContext}, + driver::{decode_offer, Offer, SpendContext}, utils::Address, }; @@ -82,9 +82,10 @@ pub async fn reward_distributor_launch( let mut ctx = SpendContext::new(); - let (sig, _sk, reward_distributor, _slot) = launch_dig_reward_distributor( + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (sig, _sk, reward_distributor, _slot, _change_cat) = launch_dig_reward_distributor( &mut ctx, - Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?, + &offer, first_epoch_start_timestamp, user_puzzle_hash, RewardDistributorConstants::without_launcher_id( diff --git a/src/cli/reward_distributor/new_epoch.rs b/src/cli/reward_distributor/new_epoch.rs index fe0c99e9..6af9b8f6 100644 --- a/src/cli/reward_distributor/new_epoch.rs +++ b/src/cli/reward_distributor/new_epoch.rs @@ -1,13 +1,13 @@ use crate::{ - assets_xch_only, find_reward_slot_for_epoch, get_coinset_client, get_constants, - hex_string_to_bytes32, new_sk, no_assets, parse_amount, parse_one_sided_offer, - spend_security_coin, sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, - RewardDistributorNewEpochAction, RewardDistributorSyncAction, SageClient, + assets_xch_only, create_security_coin, find_reward_slot, get_coinset_client, get_constants, + hex_string_to_bytes32, no_assets, parse_amount, spend_security_coin, sync_distributor, + wait_for_coin, yes_no_prompt, CliError, Db, RewardDistributorNewEpochAction, + RewardDistributorSyncAction, SageClient, }; use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Offer, SpendContext}, + driver::{decode_offer, Offer, SpendContext}, }; pub async fn reward_distributor_new_epoch( @@ -40,15 +40,13 @@ pub async fn reward_distributor_new_epoch( } println!("Finding appropriate reward slot..."); - let reward_slot = find_reward_slot_for_epoch( + let reward_slot = find_reward_slot( &mut ctx, - &db, - launcher_id, + &client, + distributor.info.constants, next_epoch_start, - distributor.info.constants.epoch_seconds, ) - .await? - .ok_or(CliError::SlotNotFound("Reward"))?; + .await?; println!("A one-sided offer will be created. It will contain:"); println!(" 1 mojo",); @@ -63,28 +61,29 @@ pub async fn reward_distributor_new_epoch( .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let (sec_conds, _new_slot, fee) = distributor + let (sec_conds, fee) = distributor .new_action::() .spend(&mut ctx, &mut distributor, reward_slot)?; - let _new_distributor = distributor.finish_spend(&mut ctx, vec![])?; + let (_new_distributor, pending_sig) = distributor.finish_spend(&mut ctx, vec![])?; println!("Fee for new epoch: {} CAT mojos", fee); let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds, &security_coin_sk, get_constants(testnet11), )?; - let spend_bundle = - SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let spend_bundle = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -92,7 +91,7 @@ pub async fn reward_distributor_new_epoch( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/reward_distributor/stake.rs b/src/cli/reward_distributor/stake.rs index c4c0d64a..fb3c4e78 100644 --- a/src/cli/reward_distributor/stake.rs +++ b/src/cli/reward_distributor/stake.rs @@ -2,18 +2,17 @@ use chia::protocol::SpendBundle; use chia_puzzle_types::{standard::StandardArgs, LineageProof}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{HashedPtr, Layer, Nft, Offer, Puzzle, SingletonLayer, SpendContext}, + driver::{decode_offer, HashedPtr, Layer, Offer, Puzzle, SingletonLayer, SpendContext}, types::Conditions, utils::Address, }; -use clvmr::NodePtr; use crate::{ - assets_xch_and_nft, get_coinset_client, get_constants, get_last_onchain_timestamp, get_prefix, - hex_string_to_bytes32, hex_string_to_pubkey, new_sk, no_assets, parse_amount, - parse_one_sided_offer, spend_security_coin, sync_distributor, wait_for_coin, yes_no_prompt, - CliError, Db, IntermediaryCoinProof, NftLauncherProof, RewardDistributorStakeAction, - RewardDistributorSyncAction, SageClient, + assets_xch_and_nft, create_security_coin, get_coinset_client, get_constants, + get_last_onchain_timestamp, get_prefix, hex_string_to_bytes32, hex_string_to_pubkey, no_assets, + parse_amount, spend_security_coin, spend_settlement_nft, sync_distributor, wait_for_coin, + yes_no_prompt, CliError, Db, IntermediaryCoinProof, NftLauncherProof, + RewardDistributorStakeAction, RewardDistributorSyncAction, SageClient, }; pub async fn reward_distributor_stake( @@ -142,8 +141,9 @@ pub async fn reward_distributor_stake( .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let sec_conds = if also_sync { distributor @@ -154,75 +154,43 @@ pub async fn reward_distributor_stake( }; // find NFT - let mut current_nft = None; - for coin_spend in offer.clone().parse(&mut ctx)?.coin_spends { - let puzzle_ptr = ctx.alloc(&coin_spend.puzzle_reveal)?; - let puzzle = Puzzle::parse(&ctx, puzzle_ptr); - if let Ok(Some(layer)) = SingletonLayer::::parse_puzzle(&ctx, puzzle) { - if layer.launcher_id != nft_launcher_id { - continue; - } - - let parent_record = client - .get_coin_record_by_name(coin_spend.coin.parent_coin_info) - .await? - .coin_record - .ok_or(CliError::CoinNotFound(coin_spend.coin.parent_coin_info))?; - let parent_coin_spend = client - .get_puzzle_and_solution( - coin_spend.coin.parent_coin_info, - Some(parent_record.spent_block_index), - ) - .await? - .coin_solution - .ok_or(CliError::CoinNotSpent(coin_spend.coin.parent_coin_info))?; - - let parent_puzzle = ctx.alloc(&parent_coin_spend.puzzle_reveal)?; - let parent_puzzle = Puzzle::parse(&ctx, parent_puzzle); - let parent_solution = ctx.alloc(&parent_coin_spend.solution)?; - current_nft = Nft::parse_child( - &mut ctx, - parent_coin_spend.coin, - parent_puzzle, - parent_solution, - )?; - break; - } - } + let current_nft = offer + .offered_coins() + .nfts + .get(&nft_launcher_id) + .ok_or(CliError::Custom("NFT not found in offer".to_string()))?; // accept offer - let (conds, notarized_payment, _slot, _locked_nft) = distributor + let (conds, notarized_payment, _locked_nft) = distributor .new_action::() .spend( &mut ctx, &mut distributor, - current_nft.unwrap(), + *current_nft, nft_launcher_proof, custody_puzzle_hash, )?; - let offer = parse_one_sided_offer( + let (_new_nft, nft_assert) = spend_settlement_nft( &mut ctx, - offer, - security_coin_sk.public_key(), - None, - Some(notarized_payment), + &offer, + nft_launcher_id, + notarized_payment.nonce, + notarized_payment.payments[0].puzzle_hash, )?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); - - let sec_conds = sec_conds.extend(conds).reserve_fee(1); - - let _new_distributor = distributor.finish_spend(&mut ctx, vec![])?; + let (_new_distributor, pending_sig) = distributor.finish_spend(&mut ctx, vec![])?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds.extend(conds).extend(nft_assert).reserve_fee(1), &security_coin_sk, get_constants(testnet11), )?; - let spend_bundle = - SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let spend_bundle = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -230,7 +198,7 @@ pub async fn reward_distributor_stake( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/reward_distributor/sync.rs b/src/cli/reward_distributor/sync.rs index e2ce06a4..90f6eb90 100644 --- a/src/cli/reward_distributor/sync.rs +++ b/src/cli/reward_distributor/sync.rs @@ -1,12 +1,12 @@ use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Offer, SpendContext}, + driver::{decode_offer, Offer, SpendContext}, }; use crate::{ - assets_xch_only, get_coinset_client, get_constants, get_last_onchain_timestamp, - hex_string_to_bytes32, new_sk, no_assets, parse_amount, parse_one_sided_offer, + assets_xch_only, create_security_coin, get_coinset_client, get_constants, + get_last_onchain_timestamp, hex_string_to_bytes32, no_assets, parse_amount, spend_security_coin, sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, RewardDistributorSyncAction, SageClient, }; @@ -59,26 +59,27 @@ pub async fn reward_distributor_sync( .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let sec_conds = distributor .new_action::() .spend(&mut ctx, &mut distributor, update_time)?; - let _new_distributor = distributor.finish_spend(&mut ctx, vec![])?; + let (_new_distributor, pending_sig) = distributor.finish_spend(&mut ctx, vec![])?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds, &security_coin_sk, get_constants(testnet11), )?; - let spend_bundle = - SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let spend_bundle = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -86,7 +87,7 @@ pub async fn reward_distributor_sync( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/reward_distributor/sync_distributor.rs b/src/cli/reward_distributor/sync_distributor.rs index 9e34080f..575620e2 100644 --- a/src/cli/reward_distributor/sync_distributor.rs +++ b/src/cli/reward_distributor/sync_distributor.rs @@ -1,17 +1,23 @@ use chia::{ clvm_utils::ToTreeHash, - protocol::Bytes32, + protocol::{Bytes32, CoinSpend}, puzzles::{cat::CatArgs, singleton::SingletonStruct, LineageProof}, }; +use chia_puzzle_types::cat::CatSolution; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{CatLayer, Layer, Puzzle, SpendContext}, + driver::{ + Cat, CatInfo, CatLayer, CatSpend, DriverError, HashedPtr, Layer, Puzzle, SingletonLayer, + Spend, SpendContext, + }, }; use clvmr::NodePtr; use crate::{ CliError, Db, P2DelegatedBySingletonLayerArgs, Reserve, RewardDistributor, - RewardDistributorSlotNonce, + RewardDistributorCommitmentSlotValue, RewardDistributorConstants, + RewardDistributorEntrySlotValue, RewardDistributorRewardSlotValue, RewardDistributorSlotNonce, + Slot, SlotInfo, SlotProof, }; pub async fn sync_distributor( @@ -20,248 +26,128 @@ pub async fn sync_distributor( ctx: &mut SpendContext, launcher_id: Bytes32, ) -> Result { - let last_unspent_coin_info = db.get_last_unspent_singleton_coin(launcher_id).await?; - - let (last_spent_coin_id, constants, mut skip_db_save, prev_distributor) = - if let Some((_coin_id, parent_coin_id)) = last_unspent_coin_info { - let constants_from_db = db - .get_reward_distributor_configuration(ctx, launcher_id) - .await? - .ok_or(CliError::Custom( - "Reward distributor configuration not found in database".to_string(), - ))?; - - (parent_coin_id, constants_from_db, true, None) - } else { - let Some(launcher_coin_record) = client - .get_coin_record_by_name(launcher_id) - .await? - .coin_record - else { - return Err(CliError::CoinNotFound(launcher_id)); - }; - if !launcher_coin_record.spent { - return Err(CliError::CoinNotSpent(launcher_id)); - } - - let Some(launcher_coin_spend) = client - .get_puzzle_and_solution( - launcher_coin_record.coin.coin_id(), - Some(launcher_coin_record.spent_block_index), - ) - .await? - .coin_solution - else { - return Err(CliError::CoinNotSpent(launcher_id)); - }; - - let launcher_solution_ptr = ctx.alloc(&launcher_coin_spend.solution)?; - let Some((constants, initial_state, distributor_eve_coin)) = - RewardDistributor::from_launcher_solution( - ctx, - launcher_coin_spend.coin, - launcher_solution_ptr, - )? - else { - return Err(CliError::Custom( - "Could not parse launcher spend".to_string(), - )); - }; - - let Some(distributor_eve_coin_spend) = client - .get_puzzle_and_solution( - distributor_eve_coin.coin_id(), - Some(launcher_coin_record.spent_block_index), - ) - .await? - .coin_solution - else { - return Err(CliError::CoinNotSpent(distributor_eve_coin.coin_id())); - }; - - let reserve = find_reserve( - ctx, - client, - launcher_id, - constants.reserve_asset_id, - 0, - 0, - true, - ) - .await?; + let constants = if let Some(cached_constants) = db + .get_reward_distributor_configuration(ctx, launcher_id) + .await? + { + cached_constants + } else { + // configuration not in database, so we need to fetch the launcher + let launcher_coin_record = client + .get_coin_record_by_name(launcher_id) + .await? + .coin_record + .ok_or(CliError::CoinNotFound(launcher_id))?; + let launcher_coin_spend = client + .get_puzzle_and_solution(launcher_id, Some(launcher_coin_record.spent_block_index)) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(launcher_id))?; - let Some((new_distributor, slot)) = RewardDistributor::from_eve_coin_spend( + let launcher_solution_ptr = ctx.alloc(&launcher_coin_spend.solution)?; + let Some((constants, _initial_state, _distributor_eve_coin)) = + RewardDistributor::from_launcher_solution( ctx, - constants, - initial_state, - distributor_eve_coin_spend, - reserve.coin.parent_coin_info, - reserve.proof, + launcher_coin_spend.coin, + launcher_solution_ptr, )? - else { - return Err(CliError::Custom( - "Could not parse eve coin spend".to_string(), - )); - }; - - let slot_value = slot.info.value; - db.save_slot(ctx, slot, 0).await?; - db.save_dig_indexed_slot_value_by_epoch_start( - slot_value.epoch_start, - RewardDistributorSlotNonce::REWARD.to_u64(), - slot_value.tree_hash().into(), - ) - .await?; - db.save_reward_distributor_configuration(ctx, constants.launcher_id, constants) - .await?; - - let Some(distributor_record) = client - .get_coin_record_by_name(new_distributor.coin.coin_id()) - .await? - .coin_record - else { - return Err(CliError::CoinNotFound(new_distributor.coin.coin_id())); - }; - if !distributor_record.spent { - return Ok(new_distributor); - } - - ( - new_distributor.coin.coin_id(), - new_distributor.info.constants, - false, - Some(new_distributor), - ) + else { + return Err(CliError::Custom( + "Could not parse launcher spend".to_string(), + )); }; - let mut last_coin_id = last_spent_coin_id; - let mut distributor: Option = prev_distributor; - loop { - let coin_record_response = client.get_coin_record_by_name(last_coin_id).await?; - let Some(coin_record) = coin_record_response.coin_record else { - return Err(CliError::CoinNotFound(last_coin_id)); - }; - if !coin_record.spent { - break; - } + constants + }; + + let mut records = client + .get_coin_records_by_hint(constants.launcher_id, None, None, Some(false)) + .await? + .coin_records + .ok_or(CliError::Custom( + "No unspent coin records found".to_string(), + ))?; - if !skip_db_save { - db.save_singleton_coin(constants.launcher_id, coin_record) - .await?; + while !records.is_empty() { + let coin_record = records.remove(0); + if coin_record.spent { + continue; } - let puzzle_and_solution_resp = client + let next_spend = client .get_puzzle_and_solution( - coin_record.coin.coin_id(), - Some(coin_record.spent_block_index), + coin_record.coin.parent_coin_info, + Some(coin_record.confirmed_block_index), ) - .await?; - let Some(coin_spend) = puzzle_and_solution_resp.coin_solution else { - return Err(CliError::CoinNotSpent(last_coin_id)); - }; + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(coin_record.coin.parent_coin_info))?; - let puzzle_ptr = ctx.alloc(&coin_spend.puzzle_reveal)?; - let parent_puzzle = Puzzle::parse(ctx, puzzle_ptr); - let solution_ptr = ctx.alloc(&coin_spend.solution)?; - if !skip_db_save { - if let Some(ref prev_distributor) = distributor { - let pending_items = - prev_distributor.get_pending_items_from_spend(ctx, solution_ptr)?; - - for (nonce, value_hash) in pending_items.pending_spent_slots.iter() { - db.mark_slot_as_spent( - constants.launcher_id, - nonce.to_u64(), - *value_hash, - coin_record.spent_block_index, - ) - .await?; - - db.delete_dig_indexed_slot_values_by_epoch_start_using_value_hash(*value_hash) - .await?; - db.delete_dig_indexed_slot_values_by_puzzle_hash_using_value_hash(*value_hash) - .await?; - } + if let Ok(Some(distributor)) = + RewardDistributor::from_parent_spend(ctx, &next_spend, constants) + { + return mempool_distributor_maybe(ctx, distributor, client).await; + } + } - for slot in prev_distributor.created_slot_values_to_slots( - pending_items.pending_commitment_slot_values, - RewardDistributorSlotNonce::COMMITMENT, - ) { - let spent_block_index = if pending_items.pending_spent_slots.contains(&( - RewardDistributorSlotNonce::from_u64(slot.info.nonce).unwrap(), - slot.info.value_hash, - )) { - coin_record.spent_block_index - } else { - 0 - }; - - if spent_block_index == 0 { - // ephemeral slot for this spend - db.save_dig_indexed_slot_value_by_puzzle_hash( - slot.info.value.clawback_ph, - RewardDistributorSlotNonce::COMMITMENT.to_u64(), - slot.info.value_hash, - ) - .await?; - db.save_dig_indexed_slot_value_by_epoch_start( - slot.info.value.epoch_start, - RewardDistributorSlotNonce::COMMITMENT.to_u64(), - slot.info.value_hash, - ) - .await?; - } - db.save_slot(ctx, slot, spent_block_index).await?; - } + // Could not find distributor, so we're just after the eve spend and need to do special parsing + let launcher_coin_record = client + .get_coin_record_by_name(launcher_id) + .await? + .coin_record + .ok_or(CliError::CoinNotFound(launcher_id))?; + let launcher_coin_spend = client + .get_puzzle_and_solution(launcher_id, Some(launcher_coin_record.spent_block_index)) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(launcher_id))?; - for slot in prev_distributor.created_slot_values_to_slots( - pending_items.pending_entry_slot_values, - RewardDistributorSlotNonce::ENTRY, - ) { - db.save_dig_indexed_slot_value_by_puzzle_hash( - slot.info.value.payout_puzzle_hash, - RewardDistributorSlotNonce::ENTRY.to_u64(), - slot.info.value_hash, - ) - .await?; - db.save_slot(ctx, slot, 0).await?; - } + let launcher_solution_ptr = ctx.alloc(&launcher_coin_spend.solution)?; + let Some((constants, initial_state, distributor_eve_coin)) = + RewardDistributor::from_launcher_solution( + ctx, + launcher_coin_spend.coin, + launcher_solution_ptr, + )? + else { + return Err(CliError::Custom( + "Could not parse launcher spend".to_string(), + )); + }; - for slot in prev_distributor.created_slot_values_to_slots( - pending_items.pending_reward_slot_values, - RewardDistributorSlotNonce::REWARD, - ) { - db.save_dig_indexed_slot_value_by_epoch_start( - slot.info.value.epoch_start, - RewardDistributorSlotNonce::REWARD.to_u64(), - slot.info.value_hash, - ) - .await?; - db.save_slot(ctx, slot, 0).await?; - } - } - } + let distributor_eve_coin_spend = client + .get_puzzle_and_solution( + distributor_eve_coin.coin_id(), + Some(launcher_coin_record.spent_block_index), + ) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(distributor_eve_coin.coin_id()))?; - if let Some(some_distributor) = RewardDistributor::from_parent_spend( - ctx, - coin_record.coin, - parent_puzzle, - solution_ptr, - constants, - )? { - last_coin_id = some_distributor.coin.coin_id(); - distributor = Some(some_distributor); - skip_db_save = false; - } else { - break; - }; - } + let reserve = find_reserve( + ctx, + client, + launcher_id, + constants.reserve_asset_id, + 0, + 0, + false, + ) + .await?; - if let Some(distributor) = distributor { - Ok(distributor) - } else { - Err(CliError::CoinNotFound(last_coin_id)) - } + let (new_distributor, _slot) = RewardDistributor::from_eve_coin_spend( + ctx, + constants, + initial_state, + distributor_eve_coin_spend, + reserve.coin.parent_coin_info, + reserve.proof, + )? + .ok_or(CliError::Custom( + "Could not parse eve coin spend".to_string(), + ))?; + + Ok(new_distributor) } pub async fn find_reserve( @@ -326,3 +212,339 @@ pub async fn find_reserve( nonce, }) } + +pub async fn mempool_distributor_maybe( + ctx: &mut SpendContext, + on_chain_distributor: RewardDistributor, + client: &CoinsetClient, +) -> Result { + let Some(mut mempool_items) = client + .get_mempool_items_by_coin_name(on_chain_distributor.coin.coin_id()) + .await? + .mempool_items + else { + return Ok(on_chain_distributor); + }; + + if mempool_items.is_empty() { + return Ok(on_chain_distributor); + } + + let mempool_item = mempool_items.remove(0); + let mut distributor = on_chain_distributor; + let mut parent_id_to_look_for = distributor.coin.parent_coin_info; + loop { + let Some(distributor_spend) = mempool_item + .spend_bundle + .coin_spends + .iter() + .find(|c| c.coin.parent_coin_info == parent_id_to_look_for) + else { + break; + }; + + let Some(new_distributor) = RewardDistributor::from_spend( + ctx, + distributor_spend, + Some(distributor.reserve.child(1).proof), + distributor.info.constants, + )? + else { + break; + }; + distributor = new_distributor; + parent_id_to_look_for = distributor.coin.coin_id(); + } + + let reserve_spend = mempool_item + .spend_bundle + .coin_spends + .iter() + .find(|coin_spend| coin_spend.coin == distributor.reserve.coin) + .ok_or(DriverError::Custom("Reserve spend not found".to_string()))? + .clone(); + let spends_to_add: Vec = mempool_item + .spend_bundle + .coin_spends + .into_iter() + .filter(|coin_spend| { + coin_spend.coin != distributor.coin && coin_spend.coin != distributor.reserve.coin + }) + .collect(); + + // CATs spent with reserve are stored in the pending spend info item + // since they need to be spent to form a ring (in finish_spend) + let mut other_cats = Vec::new(); + #[allow(unused_assignments)] + let (mut cat_spend, mut cat_solution) = spend_to_cat_spend(ctx, reserve_spend)?; + loop { + let cat_to_find = cat_solution.prev_coin_id; + if cat_to_find == distributor.reserve.coin.coin_id() { + break; + } + + let cat_coin_spend = spends_to_add + .iter() + .find(|coin_spend| coin_spend.coin.coin_id() == cat_to_find) + .ok_or(DriverError::Custom("CAT spend not found".to_string()))? + .clone(); + (cat_spend, cat_solution) = spend_to_cat_spend(ctx, cat_coin_spend)?; + other_cats.push(cat_spend); + } + + // finally, set things up for RBF + spends_to_add.into_iter().for_each(|coin_spend| { + if other_cats + .iter() + .all(|cat_spend| cat_spend.cat.coin != coin_spend.coin) + { + ctx.insert(coin_spend); + } + }); + distributor.set_pending_signature(mempool_item.spend_bundle.aggregated_signature); + distributor.set_pending_other_cats(other_cats); + + Ok(distributor) +} + +pub fn spend_to_cat_spend( + ctx: &mut SpendContext, + spend: CoinSpend, +) -> Result<(CatSpend, CatSolution), DriverError> { + let puzzle_ptr = ctx.alloc(&spend.puzzle_reveal)?; + let solution_ptr = ctx.alloc(&spend.solution)?; + + let puzzle = Puzzle::parse(ctx, puzzle_ptr); + let cat = CatLayer::::parse_puzzle(ctx, puzzle)? + .ok_or(DriverError::Custom("Not a CAT".to_string()))?; + + let solution = ctx.extract::>(solution_ptr)?; + + Ok(( + CatSpend { + cat: Cat::new( + spend.coin, + solution.lineage_proof, + CatInfo::new(cat.asset_id, None, cat.inner_puzzle.tree_hash().into()), + ), + spend: Spend::new(cat.inner_puzzle.ptr(), solution.inner_puzzle_solution), + hidden: false, + }, + solution, + )) +} + +pub async fn find_reward_slot( + ctx: &mut SpendContext, + client: &CoinsetClient, + constants: RewardDistributorConstants, + epoch_start: u64, +) -> Result, CliError> { + let mut epoch_start = epoch_start; + + loop { + let mut possible_records = client + .get_coin_records_by_hint(epoch_start.tree_hash().into(), None, None, Some(false)) + .await? + .coin_records + .ok_or(DriverError::MissingHint)?; + + while !possible_records.is_empty() { + let coin_record = possible_records.remove(0); + let distributor_spent = client + .get_puzzle_and_solution( + coin_record.coin.parent_coin_info, + Some(coin_record.confirmed_block_index), + ) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(coin_record.coin.parent_coin_info))?; + + let Some(distributor) = + RewardDistributor::from_spend(ctx, &distributor_spent, None, constants)? + else { + // eve spend + let slot_value = RewardDistributorRewardSlotValue { + epoch_start, + next_epoch_initialized: false, + rewards: 0, + }; + let slot_info = SlotInfo::::from_value( + constants.launcher_id, + RewardDistributorSlotNonce::REWARD.to_u64(), + slot_value, + ); + + let puzzle_ptr = ctx.alloc(&distributor_spent.puzzle_reveal)?; + let puzzle = Puzzle::parse(ctx, puzzle_ptr); + let puzzle = SingletonLayer::::parse_puzzle(ctx, puzzle)?.unwrap(); + let slot = Slot::::new( + SlotProof { + parent_parent_info: distributor_spent.coin.parent_coin_info, + parent_inner_puzzle_hash: puzzle.inner_puzzle.tree_hash().into(), + }, + slot_info, + ); + return Ok(slot); + }; + + if let Some(slot) = distributor + .pending_spend + .created_reward_slots + .iter() + .find_map(|slot| { + if slot.epoch_start == epoch_start { + let slot = distributor + .created_slot_value_to_slot(*slot, RewardDistributorSlotNonce::REWARD); + if slot.coin == coin_record.coin { + Some(slot) + } else { + None + } + } else { + None + } + }) + { + return Ok(slot); + }; + } + epoch_start -= constants.epoch_seconds; + } +} + +pub async fn find_commitment_slots( + ctx: &mut SpendContext, + client: &CoinsetClient, + constants: RewardDistributorConstants, + clawback_ph: Bytes32, + epoch_start: Option, + rewards: Option, +) -> Result>, CliError> { + let mut possible_records = client + .get_coin_records_by_hint(clawback_ph, None, None, Some(false)) + .await? + .coin_records + .ok_or(DriverError::MissingHint)?; + + let mut slots = Vec::new(); + + while !possible_records.is_empty() { + let coin_record = possible_records.remove(0); + let distributor_spent = client + .get_puzzle_and_solution( + coin_record.coin.parent_coin_info, + Some(coin_record.confirmed_block_index), + ) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(coin_record.coin.parent_coin_info))?; + + let Some(distributor) = + RewardDistributor::from_spend(ctx, &distributor_spent, None, constants)? + else { + continue; + }; + + if let Some(slot) = distributor + .pending_spend + .created_commitment_slots + .iter() + .find_map(|slot| { + if slot.clawback_ph == clawback_ph { + if let Some(epoch_start) = epoch_start { + if slot.epoch_start != epoch_start { + return None; + } + } + if let Some(rewards) = rewards { + if slot.rewards != rewards { + return None; + } + } + let slot = distributor + .created_slot_value_to_slot(*slot, RewardDistributorSlotNonce::COMMITMENT); + if slot.coin == coin_record.coin { + Some(slot) + } else { + None + } + } else { + None + } + }) + { + slots.push(slot); + }; + } + + Ok(slots) +} + +pub async fn find_entry_slots( + ctx: &mut SpendContext, + client: &CoinsetClient, + constants: RewardDistributorConstants, + payout_puzzle_hash: Bytes32, + initial_cumulative_payout: Option, + shares: Option, +) -> Result>, CliError> { + let mut possible_records = client + .get_coin_records_by_hint(payout_puzzle_hash, None, None, Some(false)) + .await? + .coin_records + .ok_or(DriverError::MissingHint)?; + + let mut slots = Vec::new(); + + while !possible_records.is_empty() { + let coin_record = possible_records.remove(0); + let distributor_spent = client + .get_puzzle_and_solution( + coin_record.coin.parent_coin_info, + Some(coin_record.confirmed_block_index), + ) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(coin_record.coin.parent_coin_info))?; + + let Some(distributor) = + RewardDistributor::from_spend(ctx, &distributor_spent, None, constants)? + else { + continue; + }; + + if let Some(slot) = distributor + .pending_spend + .created_entry_slots + .iter() + .find_map(|slot| { + if let Some(initial_cumulative_payout) = initial_cumulative_payout { + if initial_cumulative_payout != slot.initial_cumulative_payout { + return None; + } + } + if let Some(shares) = shares { + if shares != slot.shares { + return None; + } + } + if slot.payout_puzzle_hash == payout_puzzle_hash { + let slot = distributor + .created_slot_value_to_slot(*slot, RewardDistributorSlotNonce::ENTRY); + if slot.coin == coin_record.coin { + Some(slot) + } else { + None + } + } else { + None + } + }) + { + slots.push(slot); + }; + } + + Ok(slots) +} diff --git a/src/cli/reward_distributor/unstake.rs b/src/cli/reward_distributor/unstake.rs index 84ad2a50..2b6958c2 100644 --- a/src/cli/reward_distributor/unstake.rs +++ b/src/cli/reward_distributor/unstake.rs @@ -1,22 +1,28 @@ use chia::{ clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes32, SpendBundle}, + protocol::{Bytes32, Coin, SpendBundle}, +}; +use chia_puzzle_types::{ + offer::{NotarizedPayment, Payment, SettlementPaymentsSolution}, + standard::StandardArgs, + Memos, }; -use chia_puzzle_types::standard::StandardArgs; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{HashedPtr, Nft, Offer, Puzzle, SpendContext, SpendWithConditions, StandardLayer}, - types::Conditions, + driver::{ + decode_offer, HashedPtr, Nft, Offer, Puzzle, Spend, SpendContext, SpendWithConditions, + StandardLayer, + }, + types::{puzzles::SettlementPayment, Conditions}, utils::Address, }; use crate::{ - assets_xch_only, get_coinset_client, get_last_onchain_timestamp, get_prefix, + assets_xch_only, find_entry_slots, get_coinset_client, get_last_onchain_timestamp, get_prefix, hex_string_to_bytes32, hex_string_to_pubkey, hex_string_to_signature, no_assets, parse_amount, - parse_one_sided_offer, prompt_for_value, spend_to_coin_spend, sync_distributor, wait_for_coin, - yes_no_prompt, CliError, Db, NonceWrapperArgs, RewardDistributorEntrySlotValue, - RewardDistributorSlotNonce, RewardDistributorStakeActionArgs, RewardDistributorSyncAction, - RewardDistributorUnstakeAction, SageClient, Slot, NONCE_WRAPPER_PUZZLE_HASH, + prompt_for_value, spend_to_coin_spend, sync_distributor, wait_for_coin, yes_no_prompt, + CliError, Db, NonceWrapperArgs, RewardDistributorStakeActionArgs, RewardDistributorSyncAction, + RewardDistributorUnstakeAction, SageClient, NONCE_WRAPPER_PUZZLE_HASH, }; pub async fn reward_distributor_unstake( @@ -64,29 +70,18 @@ pub async fn reward_distributor_unstake( ); println!("Getting entry slot..."); - let entry_slot_value_hashes = db - .get_dig_indexed_slot_values_by_puzzle_hash( - custody_puzzle_hash, - RewardDistributorSlotNonce::ENTRY.to_u64(), - ) - .await?; - if entry_slot_value_hashes.is_empty() { - return Err(CliError::Custom( - "No entry slot found - you may be using the wrong custody address/puzzle hash" - .to_string(), - )); - } - - let entry_slot: Slot = db - .get_slot( - &mut ctx, - launcher_id, - RewardDistributorSlotNonce::ENTRY.to_u64(), - entry_slot_value_hashes[0], - 0, - ) - .await? - .unwrap(); + let entry_slot = find_entry_slots( + &mut ctx, + &client, + distributor.info.constants, + custody_puzzle_hash, + None, + None, + ) + .await? + .into_iter() + .next() + .ok_or(CliError::SlotNotFound("Entry"))?; println!("Fetching locked NFT..."); let locked_nft_hint: Bytes32 = CurriedProgram { @@ -175,7 +170,32 @@ pub async fn reward_distributor_unstake( .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let xch_settlement_coin = offer.offered_coins().xch[0]; + let security_coin_puzzle_hash: Bytes32 = + StandardArgs::curry_tree_hash(custody_public_key).into(); + let notarized_payment = NotarizedPayment { + nonce: xch_settlement_coin.coin_id(), + payments: vec![Payment::new( + security_coin_puzzle_hash, + xch_settlement_coin.amount, + Memos::None, + )], + }; + let settlement_puzzle = ctx.alloc_mod::()?; + let settlement_solution = ctx.alloc(&SettlementPaymentsSolution { + notarized_payments: vec![notarized_payment], + })?; + ctx.spend( + xch_settlement_coin, + Spend::new(settlement_puzzle, settlement_solution), + )?; + + let security_coin = Coin::new( + xch_settlement_coin.coin_id(), + security_coin_puzzle_hash, + xch_settlement_coin.amount, + ); let sec_conds = if also_sync { distributor @@ -189,8 +209,6 @@ pub async fn reward_distributor_unstake( let (conds, last_payment_amount) = distributor .new_action::() .spend(&mut ctx, &mut distributor, entry_slot, locked_nft)?; - let offer = parse_one_sided_offer(&mut ctx, offer, custody_public_key, None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); println!( "Last reward payment amount: {:.3} CATs", @@ -199,20 +217,20 @@ pub async fn reward_distributor_unstake( let sec_conds = sec_conds.extend(conds).reserve_fee(1); - let _new_distributor = distributor.finish_spend(&mut ctx, vec![])?; + let (_new_distributor, pending_sig) = distributor.finish_spend(&mut ctx, vec![])?; // security coin has custody puzzle! println!("Signing custody coin..."); - let security_coin_spend = StandardLayer::new(custody_public_key) - .spend_with_conditions(&mut ctx, offer.security_base_conditions.extend(sec_conds))?; - ctx.spend(offer.security_coin, security_coin_spend)?; + let security_coin_spend = + StandardLayer::new(custody_public_key).spend_with_conditions(&mut ctx, sec_conds)?; + ctx.spend(security_coin, security_coin_spend)?; let security_coin_sig = hex_string_to_signature( &sage .sign_coin_spends( vec![spend_to_coin_spend( &mut ctx, - offer.security_coin, + security_coin, security_coin_spend, )?], false, @@ -224,8 +242,10 @@ pub async fn reward_distributor_unstake( .replace("0x", ""), )?; - let spend_bundle = - SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let spend_bundle = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let client = get_coinset_client(testnet11); @@ -233,7 +253,7 @@ pub async fn reward_distributor_unstake( println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/utils.rs b/src/cli/utils.rs index a6215d48..50e8d5a0 100644 --- a/src/cli/utils.rs +++ b/src/cli/utils.rs @@ -6,7 +6,7 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{DriverError, OfferError, Spend, SpendContext}, + driver::{DriverError, Spend, SpendContext}, types::{MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, utils::AddressError, }; @@ -67,9 +67,6 @@ pub enum CliError { #[error("Data directory could not be found")] DataDirNotFound, - #[error("offer: {0}")] - Offer(#[from] OfferError), - #[error("could not parse db column")] DbColumnParse(), diff --git a/src/cli/verifications/broadcast_launch.rs b/src/cli/verifications/broadcast_launch.rs index 61f60ad7..17c43615 100644 --- a/src/cli/verifications/broadcast_launch.rs +++ b/src/cli/verifications/broadcast_launch.rs @@ -1,18 +1,11 @@ -use bech32::Variant; use chia::{ clvm_utils::ToTreeHash, - protocol::{Bytes, Bytes32, Coin, SpendBundle}, - traits::Streamable, + protocol::{Bytes32, Coin}, }; -use chia_puzzle_types::{ - cat::CatArgs, - offer::{NotarizedPayment, Payment, SettlementPaymentsSolution}, - LineageProof, -}; -use chia_puzzles::{CAT_PUZZLE_HASH, SETTLEMENT_PAYMENT_HASH}; +use chia_puzzle_types::LineageProof; use chia_wallet_sdk::{ - driver::{decompress_offer_bytes, Cat, CatSpend, HashedPtr, Launcher, Puzzle, Spend}, - types::{announcement_id, puzzles::SettlementPayment, Condition, Conditions}, + driver::{decode_offer, Launcher, Offer}, + types::Conditions, utils::Address, }; use clvm_traits::clvm_quote; @@ -20,8 +13,9 @@ use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ get_constants, get_latest_data_for_asset_id, hex_string_to_bytes32, - multisig_broadcast_thing_finish, multisig_broadcast_thing_start, yes_no_prompt, CliError, - MedievalVault, Verification, VerificationAsserter, VerificationLauncherKVList, VerifiedData, + multisig_broadcast_thing_finish, multisig_broadcast_thing_start, spend_settlement_cats, + yes_no_prompt, CatNftMetadata, CliError, MedievalVault, Verification, VerificationAsserter, + VerificationLauncherKVList, VerifiedData, }; #[allow(clippy::too_many_arguments)] @@ -80,7 +74,7 @@ pub async fn verifications_broadcast_launch( let launch_conds_with_recreate = launch_conds.create_coin( medieval_vault.info.inner_puzzle_hash().into(), medieval_vault.coin.amount, - Some(ctx.hint(medieval_vault.info.launcher_id)?), + ctx.hint(medieval_vault.info.launcher_id)?, ); let delegated_puzzle = ctx.alloc(&clvm_quote!(MedievalVault::delegated_conditions( launch_conds_with_recreate, @@ -105,23 +99,39 @@ pub async fn verifications_broadcast_launch( ); verification.spend(&mut ctx, None)?; - let (hrp, data, variant) = bech32::decode(&request_offer)?; - if variant != Variant::Bech32m || hrp.as_str() != "verificationrequest" { + let offer = Offer::from_spend_bundle( + &mut ctx, + &decode_offer(&request_offer.replace("verificationrequest1", "offer1"))?, + )?; + + let special_parent = Bytes32::from([1; 32]); + let special_coin_spend = offer + .spend_bundle() + .coin_spends + .iter() + .find(|cs| cs.coin.parent_coin_info == special_parent) + .ok_or(CliError::Custom("Special coin spend not found".to_string()))?; + offer.spend_bundle().coin_spends.iter().for_each(|cs| { + if cs.coin.parent_coin_info != special_parent { + ctx.insert(cs.clone()) + }; + }); + signature_from_signers += &offer.spend_bundle().aggregated_signature; + + let asset_id_verif = special_coin_spend.coin.puzzle_hash; + if asset_id_verif != asset_id { return Err(CliError::Custom( - "Invalid verification request offer provided".to_string(), + "Verification request offer made for another asset id :(".to_string(), )); } - let bytes = bech32::convert_bits(&data, 5, 8, false)?; - let decompressed = decompress_offer_bytes(&bytes)?; - let ptr = node_from_bytes(&mut ctx, &decompressed)?; - let (asset_id_verif, (spend_bundle_bytes, ())) = - ctx.extract::<(Bytes32, (Bytes, ()))>(ptr)?; - if asset_id_verif != asset_id { + + let special_puzzle = node_from_bytes(&mut ctx, &special_coin_spend.puzzle_reveal)?; + let (_thing, nft_metadata_verif) = ctx.extract::<(u64, CatNftMetadata)>(special_puzzle)?; + if latest_data != nft_metadata_verif { return Err(CliError::Custom( - "Verification request offer made for another asset id :(".to_string(), + "Verification request offer made for a different version of metadata".to_string(), )); } - let spend_bundle = SpendBundle::from_bytes(&spend_bundle_bytes).unwrap(); let verification_asserter = VerificationAsserter::from( launcher_id, @@ -136,124 +146,39 @@ pub async fn verifications_broadcast_launch( )?)? .puzzle_hash; - let mut payment_sent = false; - let mut verification_asserter_spent = false; let mut conds = Conditions::new(); - for coin_spend in spend_bundle.coin_spends.into_iter() { - let puzzle_ptr = ctx.alloc(&coin_spend.puzzle_reveal)?; - let solution_ptr = ctx.alloc(&coin_spend.solution)?; - let output = ctx.run(puzzle_ptr, solution_ptr)?; - let output = ctx.extract::(output)?; - - let puzzle = Puzzle::parse(&ctx, puzzle_ptr); - match puzzle { - Puzzle::Curried(puzzle) => { - if puzzle.mod_hash == CAT_PUZZLE_HASH.into() { - let spent_cat_args = ctx.extract::>(puzzle.args)?; - let payment_cat_asset_id = spent_cat_args.asset_id; - let offer_puzzle_hash: Bytes32 = CatArgs::curry_tree_hash( - payment_cat_asset_id, - SETTLEMENT_PAYMENT_HASH.into(), - ) - .into(); - - if let Some(cc) = output.iter().find_map(|c| match c { - Condition::CreateCoin(cc) => { - if cc.puzzle_hash == offer_puzzle_hash { - Some(cc) - } else { - None - } - } - _ => None, - }) { - yes_no_prompt(format!("{} CAT mojos (asset id: {}) will be transferred to the specified recipient. Continue?", cc.amount, hex::encode(payment_cat_asset_id)).as_str())?; - let notarized_payment = NotarizedPayment { - nonce: coin_spend.coin.coin_id(), - payments: vec![Payment::with_memos( - recipient_puzzle_hash, - cc.amount, - vec![recipient_puzzle_hash.into()], - )], - }; - - let offer_cat = Cat::new( - Coin::new(coin_spend.coin.coin_id(), offer_puzzle_hash, cc.amount), - Some(LineageProof { - parent_parent_coin_info: coin_spend.coin.parent_coin_info, - parent_inner_puzzle_hash: spent_cat_args - .inner_puzzle - .tree_hash() - .into(), - parent_amount: coin_spend.coin.amount, - }), - payment_cat_asset_id, - SETTLEMENT_PAYMENT_HASH.into(), - ); - - let offer_cat_inner_solution = - ctx.alloc(&SettlementPaymentsSolution { - notarized_payments: vec![notarized_payment.clone()], - })?; - - let offer_cat_spend = CatSpend::new( - offer_cat, - Spend::new( - ctx.alloc_mod::()?, - offer_cat_inner_solution, - ), - ); - - Cat::spend_all(&mut ctx, &[offer_cat_spend])?; - - payment_sent = true; - let msg: Bytes32 = notarized_payment.tree_hash().into(); - conds = conds.assert_puzzle_announcement(announcement_id( - offer_puzzle_hash, - msg, - )); - } - } - } - Puzzle::Raw(_puzzle) => { - if let Some(cc) = output.iter().find_map(|c| match c { - Condition::CreateCoin(cc) => { - if cc.puzzle_hash == verification_asserter_puzzle_hash { - Some(cc) - } else { - None - } - } - _ => None, - }) { - verification_asserter.spend( - &mut ctx, - Coin::new(coin_spend.coin.coin_id(), cc.puzzle_hash, cc.amount), - verifier_proof, - launcher_coin.amount, - comment.clone(), - )?; - verification_asserter_spent = true; - } - } - }; - - ctx.insert(coin_spend); - } - - if !payment_sent { - return Err(CliError::Custom( - "Payment in offer could not be found".to_string(), - )); - } - if !verification_asserter_spent { - return Err(CliError::Custom( - "Verification asserter could not be found in offer - it is likely invalid" - .to_string(), - )); + for (asset_id, cats) in offer.offered_coins().cats.iter() { + let total_cat_amount = cats.iter().map(|c| c.coin.amount).sum::(); + println!( + "Offer contains {} CAT mojos (asset id: {})", + total_cat_amount, + hex::encode(asset_id) + ); + let (_new_cats, assert_cond) = spend_settlement_cats( + &mut ctx, + &offer, + *asset_id, + recipient_puzzle_hash, + vec![(recipient_puzzle_hash, total_cat_amount)], + )?; + conds = conds.extend(assert_cond); } - signature_from_signers += &spend_bundle.aggregated_signature; + let solution_ptr = node_from_bytes(&mut ctx, &special_coin_spend.solution)?; + let (verification_asserter_parent, ()) = ctx.extract::<(Bytes32, ())>(solution_ptr)?; + verification_asserter.spend( + &mut ctx, + Coin::new( + verification_asserter_parent, + verification_asserter_puzzle_hash, + 0, + ), + verifier_proof, + launcher_coin.amount, + comment.clone(), + )?; + + yes_no_prompt("Accept the payments above?")?; Some(conds) } else { None diff --git a/src/cli/verifications/create_offer.rs b/src/cli/verifications/create_offer.rs index 5c7560a0..2c374b33 100644 --- a/src/cli/verifications/create_offer.rs +++ b/src/cli/verifications/create_offer.rs @@ -1,22 +1,19 @@ -use bech32::{u5, Variant}; use chia::{ clvm_utils::ToTreeHash, - protocol::{Bytes32, SpendBundle}, - traits::Streamable, + protocol::{Bytes, Bytes32, Coin, CoinSpend, Program, SpendBundle}, }; -use chia_puzzle_types::offer::{NotarizedPayment, Payment}; -use chia_puzzles::SETTLEMENT_PAYMENT_HASH; +use chia_puzzle_types::Memos; use chia_wallet_sdk::{ - driver::{compress_offer_bytes, Offer, SpendContext}, - types::{MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, + driver::{decode_offer, encode_offer, Offer, SpendContext}, + types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; -use clvm_traits::clvm_list; +use clvm_traits::{clvm_list, clvm_quote}; use clvmr::serde::node_to_bytes; use crate::{ - assets_xch_and_cat, get_coinset_client, get_latest_data_for_asset_id, hex_string_to_bytes32, - new_sk, no_assets, parse_amount, parse_one_sided_offer, spend_security_coin, yes_no_prompt, - CliError, SageClient, VerificationAsserter, VerifiedData, + assets_xch_and_cat, create_security_coin, get_coinset_client, get_latest_data_for_asset_id, + hex_string_to_bytes32, no_assets, parse_amount, spend_security_coin, yes_no_prompt, CliError, + SageClient, VerificationAsserter, VerifiedData, }; pub async fn verifications_create_offer( @@ -75,34 +72,18 @@ pub async fn verifications_create_offer( ); let verification_asserter_puzzle_hash: Bytes32 = verification_asserter.tree_hash().into(); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer( - &mut ctx, - offer, - security_coin_sk.public_key(), - Some(NotarizedPayment { - nonce: Bytes32::default(), - payments: vec![Payment::with_memos( - SETTLEMENT_PAYMENT_HASH.into(), - payment_amount, - vec![SETTLEMENT_PAYMENT_HASH.to_vec().into()], - )], - }), - None, - )?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let security_coin_conditions = offer - .security_base_conditions + let security_coin_conditions = Conditions::new() .reserve_fee(1) - .assert_concurrent_spend(offer.created_cat.unwrap().coin.coin_id()) - .create_coin(verification_asserter_puzzle_hash, 0, None) + .create_coin(verification_asserter_puzzle_hash, 0, Memos::None) .assert_concurrent_puzzle(verification_asserter_puzzle_hash); let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, if testnet11 { @@ -112,28 +93,22 @@ pub async fn verifications_create_offer( }, )?; - let whole_sig = offer.aggregated_signature + &security_coin_sig; - let data = clvm_list!( - asset_id, - SpendBundle::new(ctx.take(), whole_sig) - .to_bytes() - .map_err(|_| CliError::Custom( - "Verification request serialization error 2".to_string() - ))?, + let latest_data_bytes = ctx.alloc(&clvm_quote!(latest_data))?; + let latest_data_bytes: Bytes = node_to_bytes(&ctx, latest_data_bytes)?.into(); + let solution_bytes = ctx.alloc(&clvm_list!(security_coin.coin_id()))?; + let solution_bytes: Bytes = node_to_bytes(&ctx, solution_bytes)?.into(); + ctx.insert(CoinSpend::new( + Coin::new(Bytes32::new([1; 32]), asset_id, 0), + Program::new(latest_data_bytes), + Program::new(solution_bytes), + )); + let sb = offer.take(SpendBundle::new(ctx.take(), security_coin_sig)); + + let verification_request = encode_offer(&sb)?; + println!( + "Verification request: {}", + verification_request.replace("offer1", "verificationrequest1") ); - let data = ctx.alloc(&data)?; - - let bytes = node_to_bytes(&ctx, data)? - .to_bytes() - .map_err(|_| CliError::Custom("Verification request serialization error 3".to_string()))?; - let bytes = compress_offer_bytes(&bytes)?; - let bytes = bech32::convert_bits(&bytes, 8, 5, true)? - .into_iter() - .map(u5::try_from_u8) - .collect::, bech32::Error>>()?; - let verification_request = bech32::encode("verificationrequest", bytes, Variant::Bech32m)?; - - println!("Verification request: {}", verification_request); Ok(()) } diff --git a/src/cli/verifications/sign_launch.rs b/src/cli/verifications/sign_launch.rs index 87bd1815..bb4d3987 100644 --- a/src/cli/verifications/sign_launch.rs +++ b/src/cli/verifications/sign_launch.rs @@ -58,7 +58,7 @@ pub async fn verifications_sign_launch( let launch_conds_with_recreate = launch_conds.create_coin( medieval_vault.info.inner_puzzle_hash().into(), medieval_vault.coin.amount, - Some(ctx.hint(medieval_vault.info.launcher_id)?), + ctx.hint(medieval_vault.info.launcher_id)?, ); let delegated_puzzle = ctx.alloc(&clvm_quote!(MedievalVault::delegated_conditions( launch_conds_with_recreate, diff --git a/src/cli/verifications/sync_data.rs b/src/cli/verifications/sync_data.rs index 0a52b260..8e1fec84 100644 --- a/src/cli/verifications/sync_data.rs +++ b/src/cli/verifications/sync_data.rs @@ -41,14 +41,9 @@ pub async fn get_latest_data_for_asset_id( possible_prelauncher_record.coin.parent_coin_info, ))?; - let puzzle_ptr = ctx.alloc(&catalog_spend_maybe.puzzle_reveal)?; - let puzzle = Puzzle::parse(ctx, puzzle_ptr); - let solution_ptr = ctx.alloc(&catalog_spend_maybe.solution)?; if let Ok(Some(_reg)) = CatalogRegistry::from_parent_spend( ctx, - catalog_spend_maybe.coin, - puzzle, - solution_ptr, + &catalog_spend_maybe, CatalogRegistryConstants::get(testnet11), ) { prelauncher_coin_id = Some(possible_prelauncher_record.coin.coin_id()); diff --git a/src/cli/xchandles/continue_launch.rs b/src/cli/xchandles/continue_launch.rs index 6bc59b52..36c9b5fe 100644 --- a/src/cli/xchandles/continue_launch.rs +++ b/src/cli/xchandles/continue_launch.rs @@ -5,10 +5,9 @@ use chia::{ protocol::{Bytes32, SpendBundle}, puzzles::{cat::CatArgs, singleton::SingletonStruct, CoinProof, LineageProof}, }; -use chia_puzzle_types::offer::{NotarizedPayment, Payment}; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{CatLayer, Layer, Offer, Puzzle, SingleCatSpend, Spend, SpendContext}, + driver::{decode_offer, CatLayer, Layer, Offer, Puzzle, SingleCatSpend, Spend, SpendContext}, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, utils::Address, }; @@ -16,12 +15,12 @@ use clvm_traits::clvm_quote; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - assets_xch_and_cat, assets_xch_only, get_last_onchain_timestamp, hex_string_to_bytes32, - load_xchandles_premine_csv, new_sk, no_assets, parse_amount, parse_one_sided_offer, - spend_security_coin, sync_xchandles, wait_for_coin, yes_no_prompt, CatalogPrecommitValue, - CliError, Db, PrecommitCoin, PrecommitLayer, SageClient, XchandlesFactorPricingPuzzleArgs, - XchandlesFactorPricingSolution, XchandlesPrecommitValue, XchandlesPremineRecord, - XchandlesRegisterAction, + assets_xch_and_cat, assets_xch_only, create_security_coin, get_last_onchain_timestamp, + hex_string_to_bytes32, load_xchandles_premine_csv, no_assets, parse_amount, + spend_security_coin, spend_settlement_cats, sync_xchandles, wait_for_coin, yes_no_prompt, + CatalogPrecommitValue, CliError, Db, PrecommitCoin, PrecommitLayer, SageClient, + XchandlesFactorPricingPuzzleArgs, XchandlesPrecommitValue, XchandlesPremineRecord, + XchandlesPricingSolution, XchandlesRegisterAction, }; fn precommit_value_for_handle( @@ -35,7 +34,8 @@ fn precommit_value_for_handle( Ok(XchandlesPrecommitValue::for_normal_registration( payment_asset_id.tree_hash(), XchandlesFactorPricingPuzzleArgs::curry_tree_hash(1, registration_period), - XchandlesFactorPricingSolution { + XchandlesPricingSolution { + buy_time: start_time, current_expiration: 0, handle: handle.handle.clone(), num_periods: 1, @@ -43,7 +43,6 @@ fn precommit_value_for_handle( .tree_hash(), handle.handle.clone(), Bytes32::default(), - start_time, owner_nft_launcher_id, owner_nft_launcher_id.into(), )) @@ -226,50 +225,34 @@ pub async fn xchandles_continue_launch( cat_creator_conds = cat_creator_conds.create_coin( inner_ph.into(), amount, - Some(ctx.hint(inner_ph.into())?), + ctx.hint(inner_ph.into())?, ); } let cat_destination_puzzle_ptr = ctx.alloc(&clvm_quote!(cat_creator_conds))?; let cat_destination_puzzle_hash: Bytes32 = ctx.tree_hash(cat_destination_puzzle_ptr).into(); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - // Parse one-sided offer - let one_sided_offer = parse_one_sided_offer( + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; + let (created_cats, cat_assert) = spend_settlement_cats( &mut ctx, - offer, - security_coin_sk.public_key(), - Some(NotarizedPayment { - nonce: launcher_id, - payments: vec![Payment::with_memos( - cat_destination_puzzle_hash, - handles_payment_total, - vec![cat_destination_puzzle_hash.into()], - )], - }), - None, + &offer, + payment_asset_id, + launcher_id, + vec![(cat_destination_puzzle_hash, handles_payment_total)], )?; - let Some(created_cat) = one_sided_offer.created_cat else { - eprintln!("No CAT was created in one-sided offer - aborting..."); - return Ok(()); - }; - one_sided_offer - .coin_spends - .into_iter() - .for_each(|cs| ctx.insert(cs)); - - let security_coin_conditions = one_sided_offer - .security_base_conditions + let created_cat = created_cats[0]; + let security_coin_conditions = cat_assert .assert_concurrent_spend(created_cat.coin.coin_id()) .reserve_fee(1); // Spend security coin let security_coin_sig = spend_security_coin( &mut ctx, - one_sided_offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, if testnet11 { @@ -285,28 +268,26 @@ pub async fn xchandles_continue_launch( SingleCatSpend { next_coin_proof: CoinProof { parent_coin_info: created_cat.coin.parent_coin_info, - inner_puzzle_hash: created_cat.p2_puzzle_hash, + inner_puzzle_hash: created_cat.info.p2_puzzle_hash, amount: created_cat.coin.amount, }, prev_coin_id: created_cat.coin.coin_id(), prev_subtotal: 0, extra_delta: 0, - inner_spend: Spend::new(cat_destination_puzzle_ptr, NodePtr::NIL), + p2_spend: Spend::new(cat_destination_puzzle_ptr, NodePtr::NIL), + revoke: false, }, )?; // Build spend bundle - let sb = SpendBundle::new( - ctx.take(), - one_sided_offer.aggregated_signature + &security_coin_sig, - ); + let sb = offer.take(SpendBundle::new(ctx.take(), security_coin_sig)); println!("Submitting transaction..."); let resp = client.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, one_sided_offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); return Ok(()); @@ -474,12 +455,11 @@ pub async fn xchandles_continue_launch( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let mut security_coin_conditions = offer.security_base_conditions.reserve_fee(1); + let mut security_coin_conditions = Conditions::new().reserve_fee(1); for (i, precommit_value) in precommit_values.iter().enumerate() { let precommit_ph = precommit_puzzle_hashes[i]; @@ -515,7 +495,7 @@ pub async fn xchandles_continue_launch( let (left_slot, right_slot) = registry.actual_neigbors(handle_hash, left_slot, right_slot); - let (sec_conds, _new_slots) = registry.new_action::().spend( + let sec_conds = registry.new_action::().spend( &mut ctx, &mut registry, left_slot, @@ -523,16 +503,17 @@ pub async fn xchandles_continue_launch( precommit_coin, 1, registration_period, + start_time, )?; security_coin_conditions = security_coin_conditions.extend(sec_conds); } - let _new_registry = registry.finish_spend(&mut ctx)?; + let (_new_registry, pending_sig) = registry.finish_spend(&mut ctx)?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, if testnet11 { @@ -542,13 +523,16 @@ pub async fn xchandles_continue_launch( }, )?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let resp = client.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&client, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&client, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/xchandles/expire.rs b/src/cli/xchandles/expire.rs index d6f41b37..c5774b64 100644 --- a/src/cli/xchandles/expire.rs +++ b/src/cli/xchandles/expire.rs @@ -5,20 +5,19 @@ use chia::{ use chia_puzzle_types::{cat::CatArgs, singleton::SingletonStruct, LineageProof}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{CatLayer, DriverError, Layer, Offer, Puzzle, SpendContext}, + driver::{decode_offer, CatLayer, DriverError, Layer, Offer, Puzzle, SpendContext}, utils::Address, }; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - assets_xch_only, get_coinset_client, get_constants, get_last_onchain_timestamp, get_prefix, - hex_string_to_bytes32, new_sk, no_assets, parse_amount, parse_one_sided_offer, + assets_xch_only, create_security_coin, get_coinset_client, get_constants, + get_last_onchain_timestamp, get_prefix, hex_string_to_bytes32, no_assets, parse_amount, quick_sync_xchandles, spend_security_coin, sync_xchandles, wait_for_coin, yes_no_prompt, CliError, Db, DefaultCatMakerArgs, PrecommitCoin, PrecommitLayer, SageClient, Slot, XchandlesApiClient, XchandlesExpireAction, XchandlesExponentialPremiumRenewPuzzleArgs, - XchandlesExponentialPremiumRenewPuzzleSolution, XchandlesFactorPricingPuzzleArgs, - XchandlesFactorPricingSolution, XchandlesPrecommitValue, XchandlesRefundAction, - XchandlesSlotValue, + XchandlesFactorPricingPuzzleArgs, XchandlesPrecommitValue, XchandlesPricingSolution, + XchandlesRefundAction, XchandlesSlotValue, }; #[allow(clippy::too_many_arguments)] @@ -145,13 +144,12 @@ pub async fn xchandles_expire( } else { slot.info.value.expiration }; - let pricing_solution = XchandlesExponentialPremiumRenewPuzzleSolution { + println!("Using committed expiration: {}", commited_expiration); + let pricing_solution = XchandlesPricingSolution { buy_time: expire_time, - pricing_program_solution: XchandlesFactorPricingSolution { - current_expiration: commited_expiration, - handle: handle.clone(), - num_periods, - }, + current_expiration: commited_expiration, + handle: handle.clone(), + num_periods, }; let precommit_coin_value = XchandlesPrecommitValue::for_normal_registration( payment_asset_id.tree_hash(), @@ -163,7 +161,6 @@ pub async fn xchandles_expire( pricing_solution.tree_hash(), handle.clone(), secret, - expire_time, nft_launcher_id, nft_launcher_id.into(), ); @@ -296,11 +293,9 @@ pub async fn xchandles_expire( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = - parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let sec_conds = if refund { let slot: Option> = @@ -337,40 +332,40 @@ pub async fn xchandles_expire( precommitted_pricing_solution, slot, )? - .0 .reserve_fee(1) } else { - registry - .new_action::() - .spend( - &mut ctx, - &mut registry, - slot, - num_periods, - payment_cat_base_price, - registration_period, - precommit_coin, - )? - .0 + registry.new_action::().spend( + &mut ctx, + &mut registry, + slot, + num_periods, + payment_cat_base_price, + registration_period, + precommit_coin, + expire_time, + )? }; - let _new_registry = registry.finish_spend(&mut ctx)?; + let (_new_registry, pending_sig) = registry.finish_spend(&mut ctx)?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds, &security_coin_sk, get_constants(testnet11), )?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let resp = cli.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&cli, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&cli, security_coin.coin_id(), true).await?; println!("Confirmed!"); return Ok(()); diff --git a/src/cli/xchandles/extend.rs b/src/cli/xchandles/extend.rs index 4d85efef..c480016f 100644 --- a/src/cli/xchandles/extend.rs +++ b/src/cli/xchandles/extend.rs @@ -1,13 +1,14 @@ use chia::{clvm_utils::ToTreeHash, protocol::SpendBundle}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Offer, SpendContext}, + driver::{decode_offer, Offer, SpendContext}, }; use crate::{ - assets_xch_and_cat, get_coinset_client, get_constants, hex_string_to_bytes32, new_sk, - no_assets, parse_amount, parse_one_sided_offer, quick_sync_xchandles, spend_security_coin, - sync_xchandles, wait_for_coin, yes_no_prompt, CliError, Db, DefaultCatMakerArgs, SageClient, + assets_xch_and_cat, create_security_coin, get_coinset_client, get_constants, + get_last_onchain_timestamp, hex_string_to_bytes32, no_assets, parse_amount, + quick_sync_xchandles, spend_security_coin, spend_settlement_cats, sync_xchandles, + wait_for_coin, yes_no_prompt, CliError, Db, DefaultCatMakerArgs, SageClient, XchandlesApiClient, XchandlesExtendAction, XchandlesFactorPricingPuzzleArgs, }; @@ -80,18 +81,22 @@ pub async fn xchandles_extend( .get_slot_value(launcher_id, handle.tree_hash().into()) .await? }; + println!("Current expiration: {}", slot.info.value.expiration); - let (notarized_payment, sec_conds, _new_slot) = - registry.new_action::().spend( - &mut ctx, - &mut registry, - handle, - slot, - payment_asset_id, - payment_cat_base_price, - registration_period, - num_periods, - )?; + let start_time = get_last_onchain_timestamp(&cli).await? - 1; + println!("Extension time: {}", start_time); + + let (sec_conds, notarized_payment) = registry.new_action::().spend( + &mut ctx, + &mut registry, + handle, + slot, + payment_asset_id, + payment_cat_base_price, + registration_period, + num_periods, + start_time, + )?; yes_no_prompt("Continue with extension?")?; @@ -108,35 +113,40 @@ pub async fn xchandles_extend( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer( + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; + + let (_cats, payment_assertion) = spend_settlement_cats( &mut ctx, - offer, - security_coin_sk.public_key(), - Some(notarized_payment), - None, + &offer, + payment_asset_id, + notarized_payment.nonce, + vec![( + notarized_payment.payments[0].puzzle_hash, + notarized_payment.payments[0].amount, + )], )?; - - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); - - let _new_registry = registry.finish_spend(&mut ctx)?; + let (_new_registry, pending_sig) = registry.finish_spend(&mut ctx)?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds.extend(payment_assertion), &security_coin_sk, get_constants(testnet11), )?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let resp = cli.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&cli, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&cli, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/xchandles/initiate_launch.rs b/src/cli/xchandles/initiate_launch.rs index 94e130e9..133b43bb 100644 --- a/src/cli/xchandles/initiate_launch.rs +++ b/src/cli/xchandles/initiate_launch.rs @@ -17,8 +17,7 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Cat, DriverError, Launcher, Offer, SpendContext}, - prelude::Memos, + driver::{decode_offer, Cat, DriverError, Launcher, Offer, SpendContext}, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, utils::Address, }; @@ -71,8 +70,8 @@ fn get_additional_info_for_launch( )?; conditions = conditions.extend(price_singleton_launch_conds); - let cat_memos = Memos::some(ctx.alloc(&vec![cat_destination_puzzle_hash])?); - let (cat_creation_conds, eve_cat) = Cat::single_issuance_eve( + let cat_memos = ctx.hint(cat_destination_puzzle_hash)?; + let (cat_creation_conds, eve_cat) = Cat::issue_with_coin( ctx, security_coin.coin_id(), cat_amount, @@ -82,7 +81,7 @@ fn get_additional_info_for_launch( println!( "Premine payment asset id: {}", - hex::encode(eve_cat.asset_id) + hex::encode(eve_cat[0].info.asset_id) ); println!( "Price singleton id (SAVE THIS): {}", @@ -94,7 +93,7 @@ fn get_additional_info_for_launch( xchandles_constants .with_price_singleton(price_singleton_launcher_id) .with_launcher_id(xchandles_launcher_id), - eve_cat.asset_id, + eve_cat[0].info.asset_id, )) } @@ -243,9 +242,10 @@ pub async fn xchandles_initiate_launch( let mut ctx = SpendContext::new(); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; let (sig, _, registry, slots, security_coin) = launch_xchandles_registry( &mut ctx, - Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?, + &offer, 1, registration_period, get_additional_info_for_launch, diff --git a/src/cli/xchandles/quick_sync.rs b/src/cli/xchandles/quick_sync.rs index ef35d06b..6146727f 100644 --- a/src/cli/xchandles/quick_sync.rs +++ b/src/cli/xchandles/quick_sync.rs @@ -1,11 +1,10 @@ use chia::protocol::{Bytes32, CoinSpend}; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{Puzzle, SpendContext}, + driver::SpendContext, }; -use clvmr::serde::node_from_bytes; -use crate::{CliError, Db, XchandlesRegistry}; +use crate::{mempool_registry_maybe, CliError, Db, XchandlesRegistry}; pub async fn quick_sync_xchandles( client: &CoinsetClient, @@ -73,36 +72,22 @@ pub async fn quick_sync_xchandles( ))?; let mut temp_ctx = SpendContext::new(); - let puzzle_ptr = node_from_bytes(&mut temp_ctx, &next_spend.puzzle_reveal)?; - let puzzle = Puzzle::parse(&temp_ctx, puzzle_ptr); - let solution_ptr = node_from_bytes(&mut temp_ctx, &next_spend.solution)?; - - let xchandles_maybe = XchandlesRegistry::from_parent_spend( - &mut temp_ctx, - next_spend.coin, - puzzle, - solution_ptr, - constants, - ) - .unwrap_or_default(); - if xchandles_maybe.is_some() { + if let Ok(Some(_xchandles_maybe)) = + XchandlesRegistry::from_parent_spend(&mut temp_ctx, &next_spend, constants) + { coin_spend = Some(next_spend); break; } } - if let Some(coin_spend) = coin_spend { - let puzzle_ptr = node_from_bytes(ctx, &coin_spend.puzzle_reveal)?; - let puzzle = Puzzle::parse(ctx, puzzle_ptr); - let solution_ptr = node_from_bytes(ctx, &coin_spend.solution)?; + let coin_spend = coin_spend.ok_or(CliError::Custom( + "Could not find XCHandles registry".to_string(), + ))?; - XchandlesRegistry::from_parent_spend(ctx, coin_spend.coin, puzzle, solution_ptr, constants)? - .ok_or(CliError::Custom( - "Tried to unwrap XCHandles but couldn't".to_string(), - )) - } else { - Err(CliError::Custom( - "Could not find XCHandles registry".to_string(), - )) - } + let on_chain_registry = XchandlesRegistry::from_parent_spend(ctx, &coin_spend, constants)? + .ok_or(CliError::Custom( + "Could not parse latest XCHandles registry".to_string(), + ))?; + + mempool_registry_maybe(ctx, on_chain_registry, client).await } diff --git a/src/cli/xchandles/register.rs b/src/cli/xchandles/register.rs index 30d142a1..ddcce544 100644 --- a/src/cli/xchandles/register.rs +++ b/src/cli/xchandles/register.rs @@ -5,18 +5,18 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{CatLayer, DriverError, Layer, Offer, Puzzle, SpendContext}, + driver::{decode_offer, CatLayer, DriverError, Layer, Offer, Puzzle, SpendContext}, utils::Address, }; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - assets_xch_only, get_coinset_client, get_constants, get_last_onchain_timestamp, get_prefix, - hex_string_to_bytes32, new_sk, no_assets, parse_amount, parse_one_sided_offer, + assets_xch_only, create_security_coin, get_coinset_client, get_constants, + get_last_onchain_timestamp, get_prefix, hex_string_to_bytes32, no_assets, parse_amount, print_spend_bundle_to_file, quick_sync_xchandles, spend_security_coin, sync_xchandles, wait_for_coin, yes_no_prompt, CliError, Db, DefaultCatMakerArgs, PrecommitCoin, PrecommitLayer, SageClient, Slot, XchandlesApiClient, XchandlesExponentialPremiumRenewPuzzleArgs, - XchandlesFactorPricingPuzzleArgs, XchandlesFactorPricingSolution, XchandlesPrecommitValue, + XchandlesFactorPricingPuzzleArgs, XchandlesPrecommitValue, XchandlesPricingSolution, XchandlesRefundAction, XchandlesRegisterAction, XchandlesSlotValue, }; @@ -114,7 +114,8 @@ pub async fn xchandles_register( payment_cat_base_price, registration_period, )?; - let pricing_solution = XchandlesFactorPricingSolution { + let pricing_solution = XchandlesPricingSolution { + buy_time: start_time, current_expiration: 0, handle: handle.clone(), num_periods, @@ -139,7 +140,6 @@ pub async fn xchandles_register( pricing_solution.tree_hash(), handle.clone(), secret, - start_time, nft_launcher_id, nft_launcher_id.into(), ); @@ -254,11 +254,9 @@ pub async fn xchandles_register( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; - let offer = - parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let sec_conds = if refund { let slot: Option> = if DefaultCatMakerArgs::curry_tree_hash( @@ -326,7 +324,6 @@ pub async fn xchandles_register( precommitted_pricing_solution, slot, )? - .0 .reserve_fee(1) } else { let (left_slot, right_slot) = if local { @@ -339,31 +336,32 @@ pub async fn xchandles_register( .await? }; - registry - .new_action::() - .spend( - &mut ctx, - &mut registry, - left_slot, - right_slot, - precommit_coin, - payment_cat_base_price, - registration_period, - )? - .0 + registry.new_action::().spend( + &mut ctx, + &mut registry, + left_slot, + right_slot, + precommit_coin, + payment_cat_base_price, + registration_period, + start_time, + )? }; - let _new_registry = registry.finish_spend(&mut ctx)?; + let (_new_registry, pending_sig) = registry.finish_spend(&mut ctx)?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions.extend(sec_conds), + security_coin, + sec_conds, &security_coin_sk, get_constants(testnet11), )?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); if log { @@ -376,7 +374,7 @@ pub async fn xchandles_register( let resp = cli.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&cli, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&cli, security_coin.coin_id(), true).await?; println!("Confirmed!"); return Ok(()); diff --git a/src/cli/xchandles/sync.rs b/src/cli/xchandles/sync.rs index dd3e356f..44a29738 100644 --- a/src/cli/xchandles/sync.rs +++ b/src/cli/xchandles/sync.rs @@ -1,10 +1,12 @@ +use std::collections::HashSet; + use chia::{clvm_utils::ToTreeHash, protocol::Bytes32}; use chia_wallet_sdk::{ - coinset::{ChiaRpcClient, CoinRecord, CoinsetClient}, - driver::{Puzzle, SpendContext}, + coinset::{ChiaRpcClient, CoinsetClient}, + driver::SpendContext, }; -use crate::{CliError, Db, XchandlesConstants, XchandlesRegistry}; +use crate::{CliError, Db, XchandlesRegistry}; pub async fn sync_xchandles( client: &CoinsetClient, @@ -12,88 +14,47 @@ pub async fn sync_xchandles( ctx: &mut SpendContext, launcher_id: Bytes32, ) -> Result { - let last_unspent_coin_info = db.get_last_unspent_singleton_coin(launcher_id).await?; - - let last_spent_coin_id: Bytes32 = - if let Some((_coin_id, parent_coin_id)) = last_unspent_coin_info { - parent_coin_id - } else { - launcher_id - }; - - let mut last_coin_id = last_spent_coin_id; - let mut registry: Option = None; - let mut constants: Option = None; - loop { - let coin_record_response = client.get_coin_record_by_name(last_coin_id).await?; - let Some(coin_record) = coin_record_response.coin_record else { - return Err(CliError::CoinNotFound(last_coin_id)); - }; - if !coin_record.spent { - break; - } + let (mut registry, mut skip_save): (XchandlesRegistry, bool) = + if let (Some((_coin_id, parent_coin_id)), Some(constants)) = ( + db.get_last_unspent_singleton_coin(launcher_id).await?, + db.get_xchandles_configuration(ctx, launcher_id).await?, + ) { + let parent_record = client + .get_coin_record_by_name(parent_coin_id) + .await? + .coin_record + .ok_or(CliError::CoinNotFound(parent_coin_id))?; - let skip_db_save = last_coin_id == last_spent_coin_id; - if !skip_db_save { - db.save_singleton_coin(launcher_id, coin_record).await?; - } + let parent_spend = client + .get_puzzle_and_solution(parent_coin_id, Some(parent_record.spent_block_index)) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(parent_coin_id))?; - let puzzle_and_solution_resp = client - .get_puzzle_and_solution( - coin_record.coin.coin_id(), - Some(coin_record.spent_block_index), + ( + XchandlesRegistry::from_parent_spend(ctx, &parent_spend, constants)?.ok_or( + CliError::Custom("Could not parse latest spent CATalog registry".to_string()), + )?, + false, ) - .await?; - let Some(coin_spend) = puzzle_and_solution_resp.coin_solution else { - return Err(CliError::CoinNotSpent(last_coin_id)); - }; + } else { + let launcher_record = client + .get_coin_record_by_name(launcher_id) + .await? + .coin_record + .ok_or(CliError::CoinNotFound(launcher_id))?; - let puzzle_ptr = ctx.alloc(&coin_spend.puzzle_reveal)?; - let parent_puzzle = Puzzle::parse(ctx, puzzle_ptr); - let solution_ptr = ctx.alloc(&coin_spend.solution)?; - if !skip_db_save { - if let Some(ref prev_registry) = registry { - let pending_items = prev_registry - .get_pending_items_from_spend(ctx, solution_ptr) - .await?; - - for value in pending_items.spent_slots.iter() { - db.mark_slot_as_spent( - launcher_id, - 0, - value.tree_hash().into(), - coin_record.spent_block_index, - ) - .await?; - - // no need to actually delete handle indexed value, as - // all actions will overwrite (not remove) the handle - // from the list - } - - for slot in prev_registry.created_slot_values_to_slots(pending_items.created_slots) - { - db.save_xchandles_indexed_slot_value( - slot.info.launcher_id, - slot.info.value.handle_hash, - slot.info.value_hash, - ) - .await?; - db.save_slot(ctx, slot, 0).await?; - } - } - } + let launcher_spend = client + .get_puzzle_and_solution(launcher_id, Some(launcher_record.spent_block_index)) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(launcher_id))?; - if coin_record.coin.coin_id() == launcher_id { - let Some(( - new_registry, - initial_slots, - _initial_registration_asset_id, - _initial_base_price, - )) = XchandlesRegistry::from_launcher_solution(ctx, coin_record.coin, solution_ptr)? - else { - return Err(CliError::CoinNotFound(last_coin_id)); - }; + let solution_ptr = ctx.alloc(&launcher_spend.solution)?; + + let (registry, initial_slots, _initial_registration_asset_id, _initial_base_price) = + XchandlesRegistry::from_launcher_solution(ctx, launcher_record.coin, solution_ptr)? + .ok_or(CliError::CoinNotFound(launcher_id))?; db.save_slot(ctx, initial_slots[0].clone(), 0).await?; db.save_xchandles_indexed_slot_value( @@ -111,78 +72,162 @@ pub async fn sync_xchandles( ) .await?; - db.save_singleton_coin( + // do NOT save eve coin in db + // db.save_singleton_coin( + // launcher_id, + // CoinRecord { + // coin: launcher_record.coin, + // coinbase: false, + // confirmed_block_index: launcher_record.spent_block_index, + // spent: false, + // spent_block_index: 0, + // timestamp: 0, + // }, + // ) + // .await?; + + (registry, true) + }; + + loop { + let coin_record = client + .get_coin_record_by_name(registry.coin.coin_id()) + .await? + .coin_record + .ok_or(CliError::CoinNotFound(registry.coin.coin_id()))?; + + if skip_save { + skip_save = false; + } else { + db.save_singleton_coin(registry.info.constants.launcher_id, coin_record) + .await?; + } + + if !coin_record.spent { + break; + } + + let coin_spend = client + .get_puzzle_and_solution( + coin_record.coin.coin_id(), + Some(coin_record.spent_block_index), + ) + .await? + .coin_solution + .ok_or(CliError::CoinNotSpent(coin_record.coin.coin_id()))?; + + registry = XchandlesRegistry::from_spend(ctx, &coin_spend, registry.info.constants)? + .ok_or(CliError::Custom( + "Could not parse new XCHandles registry spend".to_string(), + ))?; + + for value in registry.pending_spend.spent_slots.iter() { + db.mark_slot_as_spent( launcher_id, - CoinRecord { - coin: new_registry.coin, - coinbase: false, - confirmed_block_index: coin_record.spent_block_index, - spent: false, - spent_block_index: 0, - timestamp: 0, - }, + 0, + value.tree_hash().into(), + coin_record.spent_block_index, ) .await?; - last_coin_id = new_registry.coin.coin_id(); - constants = Some(new_registry.info.constants); - registry = Some(new_registry); - continue; - } else if coin_record.coin.parent_coin_info == launcher_id { - last_coin_id = launcher_id; - continue; + // no need to actually delete handle indexed value, as + // all actions will overwrite (not remove) the handle + // from the list } - let constants = if let Some(cts) = constants { - cts - } else { - // look for constants from launcher spend - let launcher_record = client - .get_coin_record_by_name(launcher_id) - .await? - .coin_record - .ok_or(CliError::CoinNotFound(launcher_id))?; + let mut processed_values = HashSet::::new(); + for slot_value in registry.pending_spend.created_slots.iter() { + let slot_value_hash: Bytes32 = slot_value.tree_hash().into(); + if processed_values.contains(&slot_value_hash) { + continue; + } + processed_values.insert(slot_value_hash); + + // same slot can be created and spent mutliple times in the same block + let no_spent = registry + .pending_spend + .spent_slots + .iter() + .filter(|sv| sv.tree_hash() == slot_value_hash.into()) + .count(); + let no_created = registry + .pending_spend + .created_slots + .iter() + .filter(|sv| sv.tree_hash() == slot_value_hash.into()) + .count(); + if no_spent >= no_created { + continue; + } - let launcher_spend = client - .get_puzzle_and_solution(launcher_id, Some(launcher_record.spent_block_index)) - .await? - .coin_solution - .ok_or(CliError::CoinNotSpent(launcher_id))?; + db.save_xchandles_indexed_slot_value( + registry.info.constants.launcher_id, + slot_value.handle_hash, + slot_value_hash, + ) + .await?; + db.save_slot( + ctx, + registry.created_slot_value_to_slot(slot_value.clone()), + 0, + ) + .await?; + } - let solution_ptr = ctx.alloc(&launcher_spend.solution)?; + registry = registry.child(registry.pending_spend.latest_state.1); + } - if let Some(( - new_registry, - _initial_slots, - _initial_registration_asset_id, - _initial_base_price, - )) = - XchandlesRegistry::from_launcher_solution(ctx, launcher_record.coin, solution_ptr)? - { - constants = Some(new_registry.info.constants); - new_registry.info.constants - } else { - return Err(CliError::ConstantsNotSet); - } + mempool_registry_maybe(ctx, registry, client).await +} + +pub async fn mempool_registry_maybe( + ctx: &mut SpendContext, + on_chain_registry: XchandlesRegistry, + client: &CoinsetClient, +) -> Result { + let Some(mut mempool_items) = client + .get_mempool_items_by_coin_name(on_chain_registry.coin.coin_id()) + .await? + .mempool_items + else { + return Ok(on_chain_registry); + }; + + if mempool_items.is_empty() { + return Ok(on_chain_registry); + } + + let mempool_item = mempool_items.remove(0); + let mut registry = on_chain_registry; + let mut parent_id_to_look_for = registry.coin.parent_coin_info; + loop { + let Some(registry_spend) = mempool_item + .spend_bundle + .coin_spends + .iter() + .find(|c| c.coin.parent_coin_info == parent_id_to_look_for) + else { + break; }; - if let Some(some_registry) = XchandlesRegistry::from_parent_spend( - ctx, - coin_record.coin, - parent_puzzle, - solution_ptr, - constants, - )? { - last_coin_id = some_registry.coin.coin_id(); - registry = Some(some_registry); - } else { + let Some(new_registry) = + XchandlesRegistry::from_spend(ctx, registry_spend, registry.info.constants)? + else { break; }; + registry = new_registry; + parent_id_to_look_for = registry.coin.coin_id(); } - if let Some(registry) = registry { - Ok(registry) - } else { - Err(CliError::CoinNotFound(last_coin_id)) - } + mempool_item + .spend_bundle + .coin_spends + .into_iter() + .for_each(|coin_spend| { + if coin_spend.coin != registry.coin { + ctx.insert(coin_spend); + } + }); + registry.set_pending_signature(mempool_item.spend_bundle.aggregated_signature); + Ok(registry) } diff --git a/src/cli/xchandles/unroll_state_scheduler.rs b/src/cli/xchandles/unroll_state_scheduler.rs index c2540e3d..efffa025 100644 --- a/src/cli/xchandles/unroll_state_scheduler.rs +++ b/src/cli/xchandles/unroll_state_scheduler.rs @@ -1,13 +1,13 @@ use chia::{clvm_utils::ToTreeHash, protocol::SpendBundle}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Offer, SpendContext}, - types::{MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, + driver::{decode_offer, Offer, SpendContext}, + types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; use crate::{ - assets_xch_only, get_coinset_client, hex_string_to_bytes32, load_xchandles_state_schedule_csv, - new_sk, no_assets, parse_amount, parse_one_sided_offer, quick_sync_xchandles, + assets_xch_only, create_security_coin, get_coinset_client, hex_string_to_bytes32, + load_xchandles_state_schedule_csv, no_assets, parse_amount, quick_sync_xchandles, spend_security_coin, sync_multisig_singleton, sync_xchandles, wait_for_coin, yes_no_prompt, CliError, Db, DefaultCatMakerArgs, DelegatedStateAction, MultisigSingleton, SageClient, XchandlesExponentialPremiumRenewPuzzleArgs, XchandlesFactorPricingPuzzleArgs, @@ -124,30 +124,27 @@ pub async fn xchandles_unroll_state_scheduler( new_state, state_scheduler.info.inner_puzzle_hash().into(), )?; - registry.insert(registry_action_spend); + registry.insert_action_spend(&mut ctx, registry_action_spend)?; let registry_inner_ph = registry.info.inner_puzzle_hash(); - let _new_registry = registry.finish_spend(&mut ctx)?; + let (_new_registry, pending_sig) = registry.finish_spend(&mut ctx)?; let offer_resp = sage .make_offer(no_assets(), assets_xch_only(1), fee, None, None, false) .await?; println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; - let offer = parse_one_sided_offer(&mut ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); - - let security_coin_conditions = offer - .security_base_conditions + let security_coin_conditions = Conditions::new() .assert_concurrent_spend(state_scheduler.coin.coin_id()) .reserve_fee(1); let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, if testnet11 { @@ -159,14 +156,17 @@ pub async fn xchandles_unroll_state_scheduler( state_scheduler.spend(&mut ctx, registry_inner_ph.into())?; - let sb = SpendBundle::new(ctx.take(), offer.aggregated_signature + &security_coin_sig); + let sb = offer.take(SpendBundle::new( + ctx.take(), + security_coin_sig + &pending_sig, + )); println!("Submitting transaction..."); let resp = cli.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&cli, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&cli, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/xchandles/update.rs b/src/cli/xchandles/update.rs index 091c08fb..7532feb5 100644 --- a/src/cli/xchandles/update.rs +++ b/src/cli/xchandles/update.rs @@ -2,24 +2,21 @@ use chia::{ clvm_utils::ToTreeHash, protocol::{Bytes32, SpendBundle}, }; -use chia_puzzle_types::{ - offer::{NotarizedPayment, Payment}, - standard::StandardArgs, -}; +use chia_puzzle_types::standard::StandardArgs; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{DriverError, Offer, Spend, SpendContext, StandardLayer}, - prelude::Memos, + driver::{decode_offer, Offer, Spend, SpendContext, StandardLayer}, utils::Address, }; use clvm_traits::clvm_quote; use clvmr::NodePtr; use crate::{ - assets_xch_and_nft, get_coinset_client, get_constants, hex_string_to_bytes32, new_sk, - no_assets, parse_amount, parse_one_sided_offer, quick_sync_xchandles, - sign_standard_transaction, spend_security_coin, sync_xchandles, wait_for_coin, yes_no_prompt, - CliError, Db, SageClient, XchandlesApiClient, XchandlesSlotValue, XchandlesUpdateAction, + assets_xch_and_nft, create_security_coin, get_coinset_client, get_constants, + hex_string_to_bytes32, no_assets, parse_amount, quick_sync_xchandles, + sign_standard_transaction, spend_security_coin, spend_settlement_nft, sync_xchandles, + wait_for_coin, yes_no_prompt, CliError, Db, SageClient, XchandlesApiClient, XchandlesSlotValue, + XchandlesUpdateAction, }; fn encode_nft(nft_launcher_id: Bytes32) -> Result { @@ -124,30 +121,20 @@ pub async fn xchandles_update( println!("Offer with id {} generated.", offer_resp.offer_id); - let offer = Offer::decode(&offer_resp.offer).map_err(CliError::Offer)?; - let security_coin_sk = new_sk()?; + let offer = Offer::from_spend_bundle(&mut ctx, &decode_offer(&offer_resp.offer)?)?; + let (security_coin_sk, security_coin) = + create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let pk = security_coin_sk.public_key(); let nft_inner_ph: Bytes32 = StandardArgs::curry_tree_hash(pk).into(); - let offer = parse_one_sided_offer( + let (nft, security_conds) = spend_settlement_nft( &mut ctx, - offer, - security_coin_sk.public_key(), - None, - Some(NotarizedPayment { - nonce: registry.coin.coin_id(), - payments: vec![Payment::with_memos( - nft_inner_ph, - 1, - vec![nft_inner_ph.into()], - )], - }), + &offer, + slot.info.value.owner_launcher_id, + registry.coin.coin_id(), + nft_inner_ph, )?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); - - let nft = offer.created_nft.unwrap(); - - let (nft_inner_conds, _new_slot) = registry.new_action::().spend( + let nft_inner_conds = registry.new_action::().spend( &mut ctx, &mut registry, slot, @@ -157,11 +144,7 @@ pub async fn xchandles_update( )?; let nft_return_ph: Bytes32 = Address::decode(&return_address)?.puzzle_hash; - let nft_inner_spend = nft_inner_conds.create_coin( - nft_return_ph, - 1, - Some(Memos::hint(&mut ctx, nft_return_ph).map_err(DriverError::from)?), - ); + let nft_inner_spend = nft_inner_conds.create_coin(nft_return_ph, 1, ctx.hint(nft_return_ph)?); let nft_inner_spend = ctx.alloc(&clvm_quote!(nft_inner_spend))?; let nft_inner_spend = StandardLayer::new(pk) .delegated_inner_spend(&mut ctx, Spend::new(nft_inner_spend, NodePtr::NIL))?; @@ -173,28 +156,28 @@ pub async fn xchandles_update( &security_coin_sk, get_constants(testnet11), )?; - nft.spend(&mut ctx, nft_inner_spend)?; + let _new_nft = nft.spend(&mut ctx, nft_inner_spend)?; - let _new_registry = registry.finish_spend(&mut ctx)?; + let (_new_registry, pending_sig) = registry.finish_spend(&mut ctx)?; let security_coin_sig = spend_security_coin( &mut ctx, - offer.security_coin, - offer.security_base_conditions, + security_coin, + security_conds, &security_coin_sk, get_constants(testnet11), )?; - let sb = SpendBundle::new( + let sb = offer.take(SpendBundle::new( ctx.take(), - offer.aggregated_signature + &security_coin_sig + &nft_sig, - ); + security_coin_sig + &nft_sig + &pending_sig, + )); println!("Submitting transaction..."); let resp = cli.push_tx(sb).await?; println!("Transaction submitted; status='{}'", resp.status); - wait_for_coin(&cli, offer.security_coin.coin_id(), true).await?; + wait_for_coin(&cli, security_coin.coin_id(), true).await?; println!("Confirmed!"); Ok(()) diff --git a/src/cli/xchandles/verify_deployment.rs b/src/cli/xchandles/verify_deployment.rs index 8f841f7e..41170616 100644 --- a/src/cli/xchandles/verify_deployment.rs +++ b/src/cli/xchandles/verify_deployment.rs @@ -2,7 +2,7 @@ use chia::clvm_utils::ToTreeHash; use chia_puzzle_types::singleton::SingletonSolution; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Layer, Puzzle, SpendContext}, + driver::{Layer, SpendContext}, utils::Address, }; use clvmr::{serde::node_from_bytes, NodePtr}; @@ -137,16 +137,7 @@ pub async fn xchandles_verify_deployment( handle_index += 1; } - let puzzle_ptr = node_from_bytes(&mut ctx, &coin_spend.puzzle_reveal)?; - let parent_puzzle = Puzzle::parse(&ctx, puzzle_ptr); - registry = XchandlesRegistry::from_parent_spend( - &mut ctx, - registry.coin, - parent_puzzle, - solution, - registry.info.constants, - )? - .unwrap(); + registry = registry.child(registry.pending_spend.latest_state.1); } if handle_index < handles_to_launch.len() { diff --git a/src/drivers.rs b/src/drivers.rs index 92b69fcd..060001dd 100644 --- a/src/drivers.rs +++ b/src/drivers.rs @@ -1,22 +1,21 @@ use bip39::Mnemonic; use chia::{ - bls::{sign, PublicKey, SecretKey, Signature}, + bls::{sign, SecretKey, Signature}, clvm_utils::ToTreeHash, consensus::consensus_constants::ConsensusConstants, protocol::{Bytes32, Coin, CoinSpend}, puzzles::{ - cat::{CatArgs, CatSolution}, - offer::{NotarizedPayment, Payment, SettlementPaymentsSolution}, + offer::{NotarizedPayment, Payment}, singleton::{SingletonArgs, SingletonSolution, SingletonStruct}, - standard::{StandardArgs, StandardSolution}, - CoinProof, EveProof, LineageProof, Proof, + standard::StandardSolution, + EveProof, LineageProof, Proof, }, }; -use chia_puzzles::{CAT_PUZZLE_HASH, SETTLEMENT_PAYMENT_HASH, SINGLETON_TOP_LAYER_V1_1_HASH}; +use chia_puzzle_types::{offer::SettlementPaymentsSolution, standard::StandardArgs, Memos}; use chia_wallet_sdk::{ driver::{ - Cat, CatSpend, CurriedPuzzle, DriverError, HashedPtr, Launcher, Layer, Nft, Offer, Puzzle, - SingleCatSpend, Spend, SpendContext, StandardLayer, + Cat, CatSpend, DriverError, HashedPtr, Launcher, Layer, Nft, Offer, Spend, SpendContext, + StandardLayer, }, prelude::{AggSig, AggSigKind}, signer::{AggSigConstants, RequiredBlsSignature}, @@ -60,299 +59,6 @@ pub fn new_sk() -> Result { Ok(sk) } -pub fn parse_one_sided_offer( - ctx: &mut SpendContext, - offer: Offer, - security_public_key: PublicKey, - cat_notarized_payment: Option, - nft_notatized_payment: Option, -) -> Result { - let offer = offer.parse(ctx).map_err(custom_err)?; - - if !offer.requested_payments.is_empty() { - return Err(DriverError::Custom( - "Launch offer should not have any requested payments".to_string(), - )); - } - - let security_coin_puzzle_hash: Bytes32 = - StandardArgs::curry_tree_hash(security_public_key).into(); - - // returned spends will also spend the offer coin (creating the security coin) - let mut coin_spends = Vec::with_capacity(offer.coin_spends.len() + 1); - let mut security_coin_parent_id: Option = None; - let mut security_coin_amount = 0; - - let mut base_conditions = Conditions::new(); - let mut created_cat: Option = None; - let mut created_nft: Option> = None; - - for coin_spend in offer.coin_spends { - let puzzle_ptr = coin_spend.puzzle_reveal.to_clvm(ctx)?; - let solution_ptr = coin_spend.solution.to_clvm(ctx)?; - - let curried_puzzle = CurriedPuzzle::parse(ctx, puzzle_ptr); - - if let Some(curried_puzzle) = curried_puzzle { - if curried_puzzle.mod_hash == CAT_PUZZLE_HASH.into() { - let cat_args = CatArgs::::from_clvm(ctx, curried_puzzle.args)?; - let cat_solution = CatSolution::::from_clvm(ctx, solution_ptr)?; - - let inner_output = - ctx.run(cat_args.inner_puzzle, cat_solution.inner_puzzle_solution)?; - let inner_output = Vec::>::from_clvm(ctx, inner_output)?; - - if let Some(cc) = inner_output - .into_iter() - .filter_map(|cond| { - let Condition::CreateCoin(cc) = cond else { - return None; - }; - - Some(cc) - }) - .find(|cc| cc.puzzle_hash == SETTLEMENT_PAYMENT_HASH.into()) - { - let Some(cat_notarized_payment) = cat_notarized_payment.clone() else { - return Err(DriverError::Custom( - "CAT payment not requested but offered CAT found".to_string(), - )); - }; - - // we found a CAT creating an offered CAT - spend it to create - // the offer CAT, which then creates a 0-amount coin with - // puzzle hash = cat_destination_puzzle_hash; also return the cat - // by returning it to its original puzzle hash - - // and assert the announcement to make sure it's not going - // somewhere else - let offer_cat_full_puzzle_hash = - CatArgs::curry_tree_hash(cat_args.asset_id, SETTLEMENT_PAYMENT_HASH.into()); - let offer_coin_cat = Coin::new( - coin_spend.coin.coin_id(), - offer_cat_full_puzzle_hash.into(), - cc.amount, - ); - let refund_puzzle_hash = ctx.tree_hash(cat_args.inner_puzzle).into(); // funds will be returned to refund_puzzle_hash (inner puzzle hash) - let offer_cat = Cat::new( - offer_coin_cat, - Some(LineageProof { - parent_parent_coin_info: coin_spend.coin.parent_coin_info, - parent_inner_puzzle_hash: refund_puzzle_hash, - parent_amount: coin_spend.coin.amount, - }), - cat_args.asset_id, - SETTLEMENT_PAYMENT_HASH.into(), - ); - - // offers don't allow amount 0 coins, so we create an 1-amount coin, - // which creates a 0-amount coin and spend all the CATs together - if cat_notarized_payment.payments[0].amount == 0 { - let memos = Some(chia_wallet_sdk::prelude::Memos::new( - ctx.alloc(&cat_notarized_payment.payments[0].memos)?, - )); - let interim_inner_puzzle = ctx.alloc(&clvm_quote!(Conditions::new() - .create_coin( - cat_notarized_payment.payments[0].puzzle_hash, - 0, - memos, - )))?; - let interim_inner_ph: Bytes32 = ctx.tree_hash(interim_inner_puzzle).into(); - - let notarized_payment = NotarizedPayment { - nonce: offer_coin_cat.coin_id(), - payments: vec![ - Payment::with_memos( - refund_puzzle_hash, - cc.amount, - vec![refund_puzzle_hash.into()], - ), - Payment::new(interim_inner_ph, 1), - ], - }; - let offer_cat_inner_solution = ctx.alloc(&SettlementPaymentsSolution { - notarized_payments: vec![notarized_payment.clone()], - })?; - - let offer_cat_spend = CatSpend::new( - offer_cat, - Spend::new( - ctx.alloc_mod::()?, - offer_cat_inner_solution, - ), - ); - - let interim_cat = offer_cat.wrapped_child(interim_inner_ph, 1); - let interim_cat_spend = CatSpend::new( - interim_cat, - Spend::new(interim_inner_puzzle, NodePtr::NIL), - ); - - let orig_spends = ctx.take(); - - Cat::spend_all(ctx, &[offer_cat_spend, interim_cat_spend])?; - coin_spends.extend(ctx.take()); - - for og_spend in orig_spends { - ctx.insert(og_spend); - } - - created_cat = Some( - interim_cat - .wrapped_child(cat_notarized_payment.payments[0].puzzle_hash, 0), - ); - let announcement_msg: Bytes32 = notarized_payment.tree_hash().into(); - base_conditions = base_conditions.assert_puzzle_announcement( - announcement_id(offer_cat.coin.puzzle_hash, announcement_msg), - ); - } else { - let offer_cat_inner_solution = ctx.alloc(&SettlementPaymentsSolution { - notarized_payments: vec![cat_notarized_payment.clone()], - })?; - - let offer_cat_inner_puzzle = ctx.alloc_mod::()?; - offer_cat.spend( - ctx, - SingleCatSpend { - prev_coin_id: offer_cat.coin.coin_id(), - next_coin_proof: CoinProof { - parent_coin_info: offer_cat.coin.parent_coin_info, - inner_puzzle_hash: offer_cat.p2_puzzle_hash, - amount: cc.amount, - }, - prev_subtotal: 0, - extra_delta: 0, - inner_spend: Spend::new( - offer_cat_inner_puzzle, - offer_cat_inner_solution, - ), - }, - )?; - - created_cat = Some(offer_cat.wrapped_child( - cat_notarized_payment.payments[0].puzzle_hash, - cc.amount, - )); - let announcement_msg: Bytes32 = cat_notarized_payment.tree_hash().into(); - base_conditions = base_conditions.assert_puzzle_announcement( - announcement_id(offer_cat.coin.puzzle_hash, announcement_msg), - ); - } - } - } else if curried_puzzle.mod_hash == SINGLETON_TOP_LAYER_V1_1_HASH.into() { - let Some(nft_notatized_payment) = nft_notatized_payment.clone() else { - return Err(DriverError::Custom( - "NFT payment not requested but offered NFT found".to_string(), - )); - }; - - let parent_puzzle = Puzzle::from_clvm(ctx, puzzle_ptr)?; - let Some(nft) = Nft::::parse_child( - ctx, - coin_spend.coin, - parent_puzzle, - solution_ptr, - )? - else { - return Err(DriverError::Custom("Could not parse child NFT".to_string())); - }; - - let inner_puzzle = ctx.alloc_mod::()?; - let inner_solution = ctx.alloc(&SettlementPaymentsSolution { - notarized_payments: vec![nft_notatized_payment.clone()], - })?; - - nft.spend(ctx, Spend::new(inner_puzzle, inner_solution))?; - - created_nft = Some(nft.wrapped_child::( - nft_notatized_payment.payments[0].puzzle_hash, - nft.info.current_owner, - nft.info.metadata, - )); - let announcement_msg: Bytes32 = nft_notatized_payment.tree_hash().into(); - base_conditions = base_conditions.assert_puzzle_announcement(announcement_id( - nft.coin.puzzle_hash, - announcement_msg, - )); - } - } - - if security_coin_parent_id.is_none() { - let res = ctx.run(puzzle_ptr, solution_ptr)?; - let res = Vec::>::from_clvm(ctx, res)?; - - if let Some(cc) = res - .into_iter() - .filter_map(|cond| { - let Condition::CreateCoin(cc) = cond else { - return None; - }; - - Some(cc) - }) - .find(|cc| cc.puzzle_hash == SETTLEMENT_PAYMENT_HASH.into()) - { - let offer_coin = Coin::new( - coin_spend.coin.coin_id(), - SETTLEMENT_PAYMENT_HASH.into(), - cc.amount, - ); - let offer_coin_id = offer_coin.coin_id(); - - security_coin_parent_id = Some(offer_coin_id); - security_coin_amount = cc.amount; - - let settlement_payments_puzzle = ctx.alloc_mod::()?; - let offer_coin_puzzle = ctx.serialize(&settlement_payments_puzzle)?; - - let offer_coin_solution = SettlementPaymentsSolution { - notarized_payments: vec![NotarizedPayment { - nonce: offer_coin_id, - payments: vec![Payment::new( - security_coin_puzzle_hash, - security_coin_amount, - )], - }], - }; - let offer_coin_solution = ctx.serialize(&offer_coin_solution)?; - - let offer_coin_spend = - CoinSpend::new(offer_coin, offer_coin_puzzle, offer_coin_solution); - coin_spends.push(offer_coin_spend); - } - } - - coin_spends.push(coin_spend); - } - - let Some(security_coin_parent_id) = security_coin_parent_id else { - return Err(DriverError::Custom( - "Launch offer should offer XCH".to_string(), - )); - }; - - let security_coin = Coin::new( - security_coin_parent_id, - security_coin_puzzle_hash, - security_coin_amount, - ); - - if cat_notarized_payment.is_some() && created_cat.is_none() { - return Err(DriverError::Custom( - "Could not find CAT offered in one-sided offer".to_string(), - )); - } - - Ok(SecuredOneSidedOffer { - coin_spends, - aggregated_signature: offer.aggregated_signature, - security_coin, - security_base_conditions: base_conditions, - created_cat, - created_nft, - }) -} - pub fn spend_security_coin( ctx: &mut SpendContext, security_coin: Coin, @@ -438,9 +144,9 @@ where let launcher_memos = ctx.memos(&clvm_tuple!(launcher_id_ptr, memos_after_hint))?; clvm_quote!(Conditions::new() - .create_coin(left_slot_puzzle_hash.into(), 0, Some(slot_memos)) - .create_coin(right_slot_puzzle_hash.into(), 0, Some(slot_memos)) - .create_coin(target_inner_puzzle_hash, 1, Some(launcher_memos))) + .create_coin(left_slot_puzzle_hash.into(), 0, slot_memos) + .create_coin(right_slot_puzzle_hash.into(), 0, slot_memos) + .create_coin(target_inner_puzzle_hash, 1, launcher_memos)) .to_clvm(ctx) .map_err(DriverError::ToClvm) } @@ -532,11 +238,45 @@ where )) } +pub fn create_security_coin( + ctx: &mut SpendContext, + xch_settlement_coin: Coin, +) -> Result<(SecretKey, Coin), DriverError> { + let security_coin_sk = new_sk()?; + let security_coin_puzzle_hash: Bytes32 = + StandardArgs::curry_tree_hash(security_coin_sk.public_key()).into(); + + let notarized_payment = NotarizedPayment { + nonce: xch_settlement_coin.coin_id(), + payments: vec![Payment::new( + security_coin_puzzle_hash, + xch_settlement_coin.amount, + Memos::None, + )], + }; + let settlement_puzzle = ctx.alloc_mod::()?; + let settlement_solution = ctx.alloc(&SettlementPaymentsSolution { + notarized_payments: vec![notarized_payment], + })?; + ctx.spend( + xch_settlement_coin, + Spend::new(settlement_puzzle, settlement_solution), + )?; + + let security_coin = Coin::new( + xch_settlement_coin.coin_id(), + security_coin_puzzle_hash, + xch_settlement_coin.amount, + ); + + Ok((security_coin_sk, security_coin)) +} + #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] pub fn launch_catalog_registry( ctx: &mut SpendContext, - offer: Offer, + offer: &Offer, initial_registration_price: u64, // (registry launcher id, security coin, additional_args) -> (additional conditions, registry constants, initial_registration_asset_id) get_additional_info: fn( @@ -560,13 +300,16 @@ pub fn launch_catalog_registry( ), DriverError, > { - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let (security_coin_sk, security_coin) = + create_security_coin(ctx, offer.offered_coins().xch[0])?; + offer + .spend_bundle() + .coin_spends + .iter() + .for_each(|cs| ctx.insert(cs.clone())); - let security_coin_id = offer.security_coin.coin_id(); - - let mut security_coin_conditions = offer.security_base_conditions; + let security_coin_id = security_coin.coin_id(); + let mut security_coin_conditions = Conditions::new(); // Create CATalog registry launcher let registry_launcher = Launcher::new(security_coin_id, 1); @@ -574,12 +317,7 @@ pub fn launch_catalog_registry( let registry_launcher_id = registry_launcher_coin.coin_id(); let (additional_security_coin_conditions, catalog_constants, initial_registration_asset_id) = - get_additional_info( - ctx, - registry_launcher_id, - offer.security_coin, - additional_args, - )?; + get_additional_info(ctx, registry_launcher_id, security_coin, additional_args)?; let initial_state = CatalogRegistryState { registration_price: initial_registration_price, @@ -622,7 +360,7 @@ pub fn launch_catalog_registry( // Spend security coin let security_coin_sig = spend_security_coin( ctx, - offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, consensus_constants, @@ -630,11 +368,11 @@ pub fn launch_catalog_registry( // Finally, return the data Ok(( - offer.aggregated_signature + &security_coin_sig, + security_coin_sig + &offer.spend_bundle().aggregated_signature, security_coin_sk, catalog_registry, slots, - offer.security_coin, + security_coin, )) } @@ -642,7 +380,7 @@ pub fn launch_catalog_registry( #[allow(clippy::type_complexity)] pub fn launch_xchandles_registry( ctx: &mut SpendContext, - offer: Offer, + offer: &Offer, initial_base_registration_price: u64, initial_registration_period: u64, // (registry launcher id, security coin, additional_args) -> (additional conditions, registry constants, initial_registration_asset_id) @@ -667,13 +405,17 @@ pub fn launch_xchandles_registry( ), DriverError, > { - let security_coin_sk = new_sk()?; - let offer = parse_one_sided_offer(ctx, offer, security_coin_sk.public_key(), None, None)?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); + let (security_coin_sk, security_coin) = + create_security_coin(ctx, offer.offered_coins().xch[0])?; + offer + .spend_bundle() + .coin_spends + .iter() + .for_each(|cs| ctx.insert(cs.clone())); - let security_coin_id = offer.security_coin.coin_id(); + let security_coin_id = security_coin.coin_id(); - let mut security_coin_conditions = offer.security_base_conditions; + let mut security_coin_conditions = Conditions::new(); // Create registry coin launcher let registry_launcher = Launcher::new(security_coin_id, 1); @@ -681,12 +423,7 @@ pub fn launch_xchandles_registry( let registry_launcher_id = registry_launcher_coin.coin_id(); let (additional_security_coin_conditions, xchandles_constants, initial_registration_asset_id) = - get_additional_info( - ctx, - registry_launcher_id, - offer.security_coin, - additional_args, - )?; + get_additional_info(ctx, registry_launcher_id, security_coin, additional_args)?; // Spend intermediary coin and create registry let initial_state = XchandlesRegistryState::from( @@ -728,7 +465,7 @@ pub fn launch_xchandles_registry( // Spend security coin let security_coin_sig = spend_security_coin( ctx, - offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, consensus_constants, @@ -736,18 +473,121 @@ pub fn launch_xchandles_registry( // Finally, return the data Ok(( - offer.aggregated_signature + &security_coin_sig, + security_coin_sig + &offer.spend_bundle().aggregated_signature, security_coin_sk, xchandles_registry, slots, - offer.security_coin, + security_coin, )) } +pub fn spend_settlement_cats( + ctx: &mut SpendContext, + offer: &Offer, + asset_id: Bytes32, + nonce: Bytes32, + payments: Vec<(Bytes32, u64)>, +) -> Result<(Vec, Conditions), DriverError> { + let settlement_cats = offer + .offered_coins() + .cats + .get(&asset_id) + .ok_or(DriverError::Custom( + "Could not find required CAT in offer".to_string(), + ))?; + + let mut pmnts = Vec::with_capacity(payments.len()); + for (puzzle_hash, amount) in payments.iter() { + pmnts.push(Payment::new(*puzzle_hash, *amount, ctx.hint(*puzzle_hash)?)); + } + let notarized_payment = NotarizedPayment { + nonce, + payments: pmnts, + }; + + let offer_ann_message = ctx.alloc(¬arized_payment)?; + let offer_ann_message: Bytes32 = ctx.tree_hash(offer_ann_message).into(); + + let first_settlement_inner_solution = ctx.alloc(&SettlementPaymentsSolution { + notarized_payments: vec![notarized_payment], + })?; + let settlement_inner_puzzle = ctx.alloc_mod::()?; + + let security_coin_conditions = Conditions::new().assert_puzzle_announcement(announcement_id( + settlement_cats[0].coin.puzzle_hash, + offer_ann_message, + )); + + let mut cat_spends = Vec::with_capacity(settlement_cats.len()); + for (i, cat) in settlement_cats.iter().enumerate() { + cat_spends.push(CatSpend { + cat: *cat, + spend: Spend::new( + settlement_inner_puzzle, + if i == 0 { + first_settlement_inner_solution + } else { + NodePtr::NIL + }, + ), + hidden: false, + }); + } + let created_cats = Cat::spend_all(ctx, &cat_spends)?; + + Ok((created_cats, security_coin_conditions)) +} + +pub fn spend_settlement_nft( + ctx: &mut SpendContext, + offer: &Offer, + nft_launcher_id: Bytes32, + nonce: Bytes32, + destination_puzzle_hash: Bytes32, +) -> Result<(Nft, Conditions), DriverError> { + let settlement_nft = + offer + .offered_coins() + .nfts + .get(&nft_launcher_id) + .ok_or(DriverError::Custom( + "Could not find required NFT in offer".to_string(), + ))?; + + let notarized_payment = NotarizedPayment { + nonce, + payments: vec![Payment::new( + destination_puzzle_hash, + 1, + ctx.hint(destination_puzzle_hash)?, + )], + }; + + let offer_ann_message = ctx.alloc(¬arized_payment)?; + let offer_ann_message: Bytes32 = ctx.tree_hash(offer_ann_message).into(); + + let settlement_inner_solution = ctx.alloc(&SettlementPaymentsSolution { + notarized_payments: vec![notarized_payment], + })?; + let settlement_inner_puzzle = ctx.alloc_mod::()?; + + let security_coin_conditions = Conditions::new().assert_puzzle_announcement(announcement_id( + settlement_nft.coin.puzzle_hash, + offer_ann_message, + )); + + let created_nft = settlement_nft.spend( + ctx, + Spend::new(settlement_inner_puzzle, settlement_inner_solution), + )?; + + Ok((created_nft, security_coin_conditions)) +} + #[allow(clippy::type_complexity)] pub fn launch_dig_reward_distributor( ctx: &mut SpendContext, - offer: Offer, + offer: &Offer, first_epoch_start: u64, cat_refund_puzzle_hash: Bytes32, constants: RewardDistributorConstants, @@ -759,30 +599,21 @@ pub fn launch_dig_reward_distributor( SecretKey, RewardDistributor, Slot, + Cat, ), DriverError, > { - // use a 'trick' to find the launcher id so we can determine reserve id, then call the function again - // with the right CAT destination ph - let security_coin_sk = new_sk()?; - let mock_offer = parse_one_sided_offer( - ctx, - offer.clone(), - security_coin_sk.public_key(), - Some(NotarizedPayment { - nonce: constants.launcher_id, - payments: vec![Payment::with_memos( - cat_refund_puzzle_hash, - 0, - vec![cat_refund_puzzle_hash.into()], - )], - }), - None, - )?; + let (security_coin_sk, security_coin) = + create_security_coin(ctx, offer.offered_coins().xch[0])?; + offer + .spend_bundle() + .coin_spends + .iter() + .for_each(|cs| ctx.insert(cs.clone())); + let reward_distributor_hint: Bytes32 = "Reward Distributor v1".tree_hash().into(); - let launcher_memos = - chia_wallet_sdk::prelude::Memos::new(ctx.alloc(&(reward_distributor_hint, (comment, ())))?); - let launcher = Launcher::with_memos(mock_offer.security_coin.coin_id(), 1, launcher_memos); + let launcher_memos = ctx.memos(&(reward_distributor_hint, (comment, ())))?; + let launcher = Launcher::with_memos(security_coin.coin_id(), 1, launcher_memos); let launcher_coin = launcher.coin(); let launcher_id = launcher_coin.coin_id(); @@ -792,23 +623,40 @@ pub fn launch_dig_reward_distributor( P2DelegatedBySingletonLayerArgs::curry_tree_hash(controller_singleton_struct_hash, 0) .into(); - let offer = parse_one_sided_offer( + let total_cat_amount = offer + .offered_coins() + .cats + .get(&constants.reserve_asset_id) + .map(|cs| cs.iter().map(|c| c.coin.amount).sum::()) + .unwrap_or(1); + + let interim_cat_puzzle = clvm_quote!(Conditions::new() + .create_coin(reserve_inner_ph, 0, ctx.hint(reserve_inner_ph)?) + .create_coin( + cat_refund_puzzle_hash, + total_cat_amount, + ctx.hint(cat_refund_puzzle_hash)? + )); + let interim_cat_puzzle = ctx.alloc(&interim_cat_puzzle)?; + let interim_cat_puzzle_hash = ctx.tree_hash(interim_cat_puzzle); + + let (created_cats, mut security_coin_conditions) = spend_settlement_cats( ctx, offer, - security_coin_sk.public_key(), - Some(NotarizedPayment { - nonce: constants.launcher_id, - payments: vec![Payment::with_memos( - reserve_inner_ph, - 0, - vec![reserve_inner_ph.into()], - )], - }), - None, + constants.reserve_asset_id, + constants.launcher_id, + vec![(interim_cat_puzzle_hash.into(), total_cat_amount)], )?; - offer.coin_spends.into_iter().for_each(|cs| ctx.insert(cs)); - let mut security_coin_conditions = offer.security_base_conditions; + let interim_cat = created_cats[0]; + let created_cats = Cat::spend_all( + ctx, + &[CatSpend { + cat: interim_cat, + spend: Spend::new(interim_cat_puzzle, NodePtr::NIL), + hidden: false, + }], + )?; // Spend intermediary coin and create registry let target_info = RewardDistributorInfo::new( @@ -830,14 +678,12 @@ pub fn launch_dig_reward_distributor( ); let slot_puzzle_hash = Slot::::puzzle_hash(&slot_info); - let slot_hint: Bytes32 = - Slot::<()>::first_curry_hash(launcher_id, RewardDistributorSlotNonce::REWARD.to_u64()) - .into(); + let slot_hint: Bytes32 = first_epoch_start.tree_hash().into(); let slot_memos = ctx.hint(slot_hint)?; let launcher_memos = ctx.hint(launcher_id)?; let eve_singleton_inner_puzzle = clvm_quote!(Conditions::new() - .create_coin(slot_puzzle_hash.into(), 0, Some(slot_memos)) - .create_coin(target_inner_puzzle_hash.into(), 1, Some(launcher_memos))) + .create_coin(slot_puzzle_hash.into(), 0, slot_memos) + .create_coin(target_inner_puzzle_hash.into(), 1, launcher_memos)) .to_clvm(ctx)?; let eve_singleton_inner_puzzle_hash = ctx.tree_hash(eve_singleton_inner_puzzle); @@ -887,15 +733,11 @@ pub fn launch_dig_reward_distributor( security_coin_conditions.assert_concurrent_spend(eve_coin.coin_id()); // create reserve and registry - let Some(reserve_cat) = offer.created_cat else { - return Err(DriverError::Custom( - "Offer does not contain reserve".to_string(), - )); - }; + let reserve_cat = created_cats[0]; let reserve = Reserve::new( reserve_cat.coin.parent_coin_info, reserve_cat.lineage_proof.unwrap(), - reserve_cat.asset_id, + reserve_cat.info.asset_id, controller_singleton_struct_hash, 0, reserve_cat.coin.amount, @@ -905,7 +747,7 @@ pub fn launch_dig_reward_distributor( // Spend security coin let security_coin_sig = spend_security_coin( ctx, - offer.security_coin, + security_coin, security_coin_conditions, &security_coin_sk, consensus_constants, @@ -913,10 +755,11 @@ pub fn launch_dig_reward_distributor( // Finally, return the data Ok(( - offer.aggregated_signature + &security_coin_sig, + security_coin_sig + &offer.spend_bundle().aggregated_signature, security_coin_sk, registry, slot, + created_cats[1], // refund cat )) } @@ -930,9 +773,9 @@ mod tests { CoinProof, }, }; - use chia_puzzles::SINGLETON_LAUNCHER_HASH; + use chia_puzzles::{SETTLEMENT_PAYMENT_HASH, SINGLETON_LAUNCHER_HASH}; use chia_wallet_sdk::{ - driver::{Nft, NftMint, SpendWithConditions}, + driver::{Nft, NftMint, SingleCatSpend, SpendWithConditions}, test::Simulator, types::TESTNET11_CONSTANTS, }; @@ -950,10 +793,9 @@ mod tests { RewardDistributorStakeAction, RewardDistributorSyncAction, RewardDistributorType, RewardDistributorUnstakeAction, RewardDistributorWithdrawIncentivesAction, Slot, SpendContextExt, XchandlesExpireAction, XchandlesExponentialPremiumRenewPuzzleArgs, - XchandlesExponentialPremiumRenewPuzzleSolution, XchandlesExtendAction, - XchandlesFactorPricingPuzzleArgs, XchandlesFactorPricingSolution, XchandlesOracleAction, - XchandlesPrecommitValue, XchandlesRefundAction, XchandlesRegisterAction, - XchandlesUpdateAction, ANY_METADATA_UPDATER_HASH, + XchandlesExtendAction, XchandlesFactorPricingPuzzleArgs, XchandlesOracleAction, + XchandlesPrecommitValue, XchandlesPricingSolution, XchandlesRefundAction, + XchandlesRegisterAction, XchandlesUpdateAction, ANY_METADATA_UPDATER_HASH, }; use super::*; @@ -1043,7 +885,7 @@ mod tests { let message: Bytes32 = new_state.tree_hash().into(); let price_singleton_inner_solution = Conditions::new() .send_message(18, message.into(), vec![ctx.alloc(&receiver_puzzle_hash)?]) - .create_coin(price_singleton_inner_puzzle_hash.into(), 1, None); + .create_coin(price_singleton_inner_puzzle_hash.into(), 1, Memos::None); let price_singleton_inner_solution = price_singleton_inner_solution.to_clvm(ctx)?; let price_singleton_solution = SingletonSolution { @@ -1108,7 +950,7 @@ mod tests { let eve_nft_inner_puzzle_hash = tail_hash; let value = CatalogPrecommitValue::with_default_cat_maker( - payment_cat.asset_id.tree_hash(), + payment_cat.info.asset_id.tree_hash(), eve_nft_inner_puzzle_hash.into(), tail, ); @@ -1119,7 +961,7 @@ mod tests { ctx, payment_cat.coin.coin_id(), payment_cat.child_lineage_proof(), - payment_cat.asset_id, + payment_cat.info.asset_id, SingletonStruct::new(catalog.info.constants.launcher_id) .tree_hash() .into(), @@ -1133,24 +975,24 @@ mod tests { let payment_cat_inner_spend = minter_p2.spend_with_conditions( ctx, Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, None) + .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, Memos::None) .create_coin( minter_puzzle_hash, payment_cat.coin.amount - reg_amount, - None, + Memos::None, ), )?; Cat::spend_all( ctx, &[CatSpend { cat: payment_cat, - inner_spend: payment_cat_inner_spend, - extra_delta: 0, + spend: payment_cat_inner_spend, + hidden: false, }], )?; let new_payment_cat = - payment_cat.wrapped_child(minter_puzzle_hash, payment_cat.coin.amount - reg_amount); + payment_cat.child(minter_puzzle_hash, payment_cat.coin.amount - reg_amount); // sim.spend_coins(ctx.take(), sks)?; benchmark.add_spends(ctx, sim, "create_precommit", sks)?; @@ -1169,7 +1011,21 @@ mod tests { slot.cloned(), )?; - let new_catalog = catalog.finish_spend(ctx)?; + // check refund action created/spent slots function + let created_slots = catalog.pending_spend.created_slots.clone(); + let spent_slots = catalog.pending_spend.spent_slots.clone(); + if slot.is_some() { + assert_eq!(created_slots.len(), 1); + assert_eq!(created_slots[0], slot.unwrap().info.value); + + assert_eq!(spent_slots.len(), 1); + assert_eq!(spent_slots[0], slot.unwrap().info.value); + } else { + assert_eq!(created_slots.len(), 0); + assert_eq!(spent_slots.len(), 0); + } + + let (new_catalog, _) = catalog.finish_spend(ctx)?; ensure_conditions_met(ctx, sim, secure_cond, 0)?; @@ -1193,7 +1049,7 @@ mod tests { let catalog_constants = CatalogRegistryConstants { launcher_id: Bytes32::from([1; 32]), royalty_address: Bytes32::from([7; 32]), - royalty_ten_thousandths: 100, + royalty_basis_points: 100, precommit_payout_puzzle_hash: Bytes32::from([8; 32]), relative_block_height: 1, price_singleton_launcher_id: Bytes32::from(hex!( @@ -1210,21 +1066,29 @@ mod tests { let offer_src_coin = launcher_bls.coin; let offer_spend = StandardLayer::new(launcher_bls.pk).spend_with_conditions( ctx, - Conditions::new().create_coin(SETTLEMENT_PAYMENT_HASH.into(), offer_amount, None), + Conditions::new().create_coin( + SETTLEMENT_PAYMENT_HASH.into(), + offer_amount, + Memos::None, + ), )?; let puzzle_reveal = ctx.serialize(&offer_spend.puzzle)?; let solution = ctx.serialize(&offer_spend.solution)?; - let offer = Offer::new(SpendBundle { - coin_spends: vec![CoinSpend::new(offer_src_coin, puzzle_reveal, solution)], - aggregated_signature: sign_standard_transaction( - ctx, - offer_src_coin, - offer_spend, - &launcher_bls.sk, - &TESTNET11_CONSTANTS, - )?, - }); + let agg_sig = sign_standard_transaction( + ctx, + offer_src_coin, + offer_spend, + &launcher_bls.sk, + &TESTNET11_CONSTANTS, + )?; + let offer = Offer::from_spend_bundle( + ctx, + &SpendBundle { + coin_spends: vec![CoinSpend::new(offer_src_coin, puzzle_reveal, solution)], + aggregated_signature: agg_sig, + }, + )?; let ( price_singleton_launcher_id, @@ -1240,21 +1104,21 @@ mod tests { let minter_bls = sim.bls(payment_cat_amount); let minter_p2 = StandardLayer::new(minter_bls.pk); - let (issue_cat, mut payment_cat) = Cat::single_issuance_eve( + let (issue_cat, payment_cat) = Cat::issue_with_coin( ctx, minter_bls.coin.coin_id(), payment_cat_amount, - Conditions::new().create_coin(minter_bls.puzzle_hash, payment_cat_amount, None), + Conditions::new().create_coin(minter_bls.puzzle_hash, payment_cat_amount, Memos::None), )?; + let mut payment_cat = payment_cat[0]; minter_p2.spend(ctx, minter_bls.coin, issue_cat)?; - payment_cat = payment_cat.wrapped_child(minter_bls.puzzle_hash, payment_cat_amount); sim.spend_coins(ctx.take(), &[minter_bls.sk.clone()])?; // Launch catalog let (_, security_sk, mut catalog, slots, _security_coin) = launch_catalog_registry( ctx, - offer, + &offer, initial_registration_price, |_ctx, _launcher_id, _coin, (catalog_constants, initial_registration_asset_id)| { Ok(( @@ -1266,7 +1130,7 @@ mod tests { &TESTNET11_CONSTANTS, ( catalog_constants.with_price_singleton(price_singleton_launcher_id), - payment_cat.asset_id, + payment_cat.info.asset_id, ), )?; @@ -1292,13 +1156,13 @@ mod tests { let eve_nft_inner_puzzle = clvm_quote!(Conditions::new().create_coin( Bytes32::new([4 + i as u8; 32]), 1, - None + Memos::None, )) .to_clvm(ctx)?; let eve_nft_inner_puzzle_hash = ctx.tree_hash(eve_nft_inner_puzzle); let value = CatalogPrecommitValue::with_default_cat_maker( - payment_cat.asset_id.tree_hash(), + payment_cat.info.asset_id.tree_hash(), eve_nft_inner_puzzle_hash.into(), tail, ); @@ -1309,7 +1173,7 @@ mod tests { ctx, payment_cat.coin.coin_id(), payment_cat.child_lineage_proof(), - payment_cat.asset_id, + payment_cat.info.asset_id, SingletonStruct::new(catalog.info.constants.launcher_id) .tree_hash() .into(), @@ -1323,24 +1187,24 @@ mod tests { let payment_cat_inner_spend = minter_p2.spend_with_conditions( ctx, Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, None) + .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, Memos::None) .create_coin( minter_bls.puzzle_hash, payment_cat_amount - reg_amount, - None, + Memos::None, ), )?; - Cat::spend_all( + let new_cats = Cat::spend_all( ctx, &[CatSpend { cat: payment_cat, - inner_spend: payment_cat_inner_spend, - extra_delta: 0, + spend: payment_cat_inner_spend, + hidden: false, }], )?; payment_cat_amount -= reg_amount; - payment_cat = payment_cat.wrapped_child(minter_bls.puzzle_hash, payment_cat_amount); + payment_cat = new_cats[1]; // sim.spend_coins(ctx.take(), &[user_bls.sk.clone(), minter_bls.sk.clone()])?; benchmark.add_spends( @@ -1390,7 +1254,7 @@ mod tests { let new_state = CatalogRegistryState { cat_maker_puzzle_hash: DefaultCatMakerArgs::curry_tree_hash( - payment_cat.asset_id.tree_hash().into(), + payment_cat.info.asset_id.tree_hash().into(), ) .into(), registration_price: new_price, @@ -1419,13 +1283,13 @@ mod tests { delegated_state_action_solution.other_singleton_inner_puzzle_hash, )?; - catalog.insert(action_spend); - catalog = catalog.finish_spend(ctx)?; + catalog.insert_action_spend(ctx, action_spend)?; + catalog = catalog.finish_spend(ctx)?.0; // sim.spend_coins(ctx.take(), &[user_bls.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "update_price", &[user_bls.sk.clone()])?; }; - let (secure_cond, new_slots) = catalog.new_action::().spend( + let secure_cond = catalog.new_action::().spend( ctx, &mut catalog, tail_hash.into(), @@ -1438,7 +1302,19 @@ mod tests { }, )?; - catalog = catalog.finish_spend(ctx)?; + // check register action created/spent slots function + let created_slots: Vec> = catalog + .pending_spend + .created_slots + .iter() + .map(|s| catalog.created_slot_value_to_slot(*s)) + .collect(); + let spent_slots = catalog.pending_spend.spent_slots.clone(); + assert_eq!(spent_slots.len(), 2); + assert_eq!(spent_slots[0], left_slot.info.value); + assert_eq!(spent_slots[1], right_slot.info.value); + + catalog = catalog.finish_spend(ctx)?.0; ensure_conditions_met(ctx, &mut sim, secure_cond.clone(), 1)?; @@ -1449,7 +1325,14 @@ mod tests { s.info.value_hash != left_slot.info.value_hash && s.info.value_hash != right_slot.info.value_hash }); - slots.extend(new_slots); + slots.extend(created_slots.clone()); + + created_slots.into_iter().for_each(|s| { + assert!(sim + .coin_state(s.coin.coin_id()) + .map(|c| c.spent_height) + .is_some()); + }); } assert_eq!( @@ -1483,20 +1366,19 @@ mod tests { let minter2_bls = sim.bls(alternative_payment_cat_amount); let minter_p2_2 = StandardLayer::new(minter2_bls.pk); - let (issue_cat, mut alternative_payment_cat) = Cat::single_issuance_eve( + let (issue_cat, alternative_payment_cat) = Cat::issue_with_coin( ctx, minter2_bls.coin.coin_id(), alternative_payment_cat_amount, Conditions::new().create_coin( minter2_bls.puzzle_hash, alternative_payment_cat_amount, - None, + Memos::None, ), )?; minter_p2_2.spend(ctx, minter2_bls.coin, issue_cat)?; + let alternative_payment_cat = alternative_payment_cat[0]; - alternative_payment_cat = alternative_payment_cat - .wrapped_child(minter2_bls.puzzle_hash, alternative_payment_cat_amount); sim.spend_coins(ctx.take(), &[minter2_bls.sk.clone()])?; let (catalog, _alternative_payment_cat) = test_refund_for_catalog( @@ -1560,16 +1442,11 @@ mod tests { let pricing_solution_hash = ctx.tree_hash(pricing_solution); let value = XchandlesPrecommitValue::for_normal_registration( - payment_cat.asset_id.tree_hash(), + payment_cat.info.asset_id.tree_hash(), pricing_puzzle_hash, pricing_solution_hash, handle_to_refund.clone(), Bytes32::default(), - if let Some(existing_slot) = &slot { - existing_slot.info.value.expiration + 28 * 24 * 60 * 60 + 1 - } else { - 0 - }, Bytes32::default(), Bytes::default(), ); @@ -1580,7 +1457,7 @@ mod tests { ctx, payment_cat.coin.coin_id(), payment_cat.child_lineage_proof(), - payment_cat.asset_id, + payment_cat.info.asset_id, SingletonStruct::new(registry.info.constants.launcher_id) .tree_hash() .into(), @@ -1594,23 +1471,27 @@ mod tests { let payment_cat_inner_spend = minter_p2.spend_with_conditions( ctx, Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, payment_cat_amount, None) + .create_coin( + precommit_coin.inner_puzzle_hash, + payment_cat_amount, + Memos::None, + ) .create_coin( minter_puzzle_hash, payment_cat.coin.amount - payment_cat_amount, - None, + Memos::None, ), )?; Cat::spend_all( ctx, &[CatSpend { cat: payment_cat, - inner_spend: payment_cat_inner_spend, - extra_delta: 0, + spend: payment_cat_inner_spend, + hidden: false, }], )?; - let new_payment_cat = payment_cat.wrapped_child( + let new_payment_cat = payment_cat.child( minter_puzzle_hash, payment_cat.coin.amount - payment_cat_amount, ); @@ -1625,7 +1506,7 @@ mod tests { let mut registry = registry; let used_slot_value_hash = slot.clone().map(|s| s.info.value_hash); - let (secure_cond, _new_slot_maybe) = registry.new_action::().spend( + let secure_cond = registry.new_action::().spend( ctx, &mut registry, precommit_coin, @@ -1633,16 +1514,16 @@ mod tests { pricing_solution, slot, )?; - assert_eq!( - used_slot_value_hash, - XchandlesRefundAction::get_spent_slot_value_from_solution( - ctx, - registry.pending_items.actions[registry.pending_items.actions.len() - 1].solution - )? - .map(|s| s.tree_hash().into()) - ); + if let Some(used_slot_value_hash) = used_slot_value_hash { + assert_eq!( + used_slot_value_hash, + registry.pending_spend.spent_slots[registry.pending_spend.spent_slots.len() - 1] + .tree_hash() + .into() + ); + } - let new_registry = registry.finish_spend(ctx)?; + let (new_registry, _) = registry.finish_spend(ctx)?; ensure_conditions_met(ctx, sim, secure_cond.clone(), 0)?; @@ -1678,37 +1559,44 @@ mod tests { let launcher_bls = sim.bls(offer_amount); let offer_spend = StandardLayer::new(launcher_bls.pk).spend_with_conditions( ctx, - Conditions::new().create_coin(SETTLEMENT_PAYMENT_HASH.into(), offer_amount, None), + Conditions::new().create_coin( + SETTLEMENT_PAYMENT_HASH.into(), + offer_amount, + Memos::None, + ), )?; let puzzle_reveal = ctx.serialize(&offer_spend.puzzle)?; let solution = ctx.serialize(&offer_spend.solution)?; - let offer = Offer::new(SpendBundle { - coin_spends: vec![CoinSpend::new(launcher_bls.coin, puzzle_reveal, solution)], - aggregated_signature: sign_standard_transaction( - ctx, - launcher_bls.coin, - offer_spend, - &launcher_bls.sk, - &TESTNET11_CONSTANTS, - )?, - }); + let agg_sig = sign_standard_transaction( + ctx, + launcher_bls.coin, + offer_spend, + &launcher_bls.sk, + &TESTNET11_CONSTANTS, + )?; + let offer = Offer::from_spend_bundle( + ctx, + &SpendBundle { + coin_spends: vec![CoinSpend::new(launcher_bls.coin, puzzle_reveal, solution)], + aggregated_signature: agg_sig, + }, + )?; // Launch CAT let mut payment_cat_amount = 10_000_000; let minter_bls = sim.bls(payment_cat_amount); let minter_p2 = StandardLayer::new(minter_bls.pk); - let (issue_cat, mut payment_cat) = Cat::single_issuance_eve( + let (issue_cat, payment_cat) = Cat::issue_with_coin( ctx, minter_bls.coin.coin_id(), payment_cat_amount, - Conditions::new().create_coin(minter_bls.puzzle_hash, payment_cat_amount, None), + Conditions::new().create_coin(minter_bls.puzzle_hash, payment_cat_amount, Memos::None), )?; + let mut payment_cat = payment_cat[0]; minter_p2.spend(ctx, minter_bls.coin, issue_cat)?; - payment_cat = payment_cat.wrapped_child(minter_bls.puzzle_hash, payment_cat_amount); - sim.spend_coins(ctx.take(), &[minter_bls.sk.clone()])?; // Launch price singleton @@ -1726,7 +1614,7 @@ mod tests { let (_, security_sk, mut registry, slots_returned_by_launch, _security_coin) = launch_xchandles_registry( ctx, - offer, + &offer, initial_registration_price, reg_period, |_ctx, _launcher_id, _coin, (xchandles_constants, payment_cat_asset_id)| { @@ -1735,7 +1623,7 @@ mod tests { &TESTNET11_CONSTANTS, ( xchandles_constants.with_price_singleton(price_singleton_launcher_id), - payment_cat.asset_id, + payment_cat.info.asset_id, ), )?; @@ -1750,7 +1638,7 @@ mod tests { XchandlesRegistry::from_launcher_solution(ctx, spend.coin, launcher_solution)? { initial_slots = Some(slots); - assert_eq!(initial_registration_asset_id, payment_cat.asset_id); + assert_eq!(initial_registration_asset_id, payment_cat.info.asset_id); assert_eq!( registry.info.constants, xchandles_constants @@ -1805,9 +1693,10 @@ mod tests { let secret = Bytes32::default(); let value = XchandlesPrecommitValue::for_normal_registration( - payment_cat.asset_id.tree_hash(), + payment_cat.info.asset_id.tree_hash(), XchandlesFactorPricingPuzzleArgs::curry_tree_hash(base_price, reg_period), - XchandlesFactorPricingSolution { + XchandlesPricingSolution { + buy_time: 100, current_expiration: 0, handle: handle.clone(), num_periods: 1, @@ -1815,7 +1704,6 @@ mod tests { .tree_hash(), handle.clone(), secret, - 100, handle_owner_launcher_id, handle_resolved_data, ); @@ -1826,7 +1714,7 @@ mod tests { ctx, payment_cat.coin.coin_id(), payment_cat.child_lineage_proof(), - payment_cat.asset_id, + payment_cat.info.asset_id, SingletonStruct::new(registry.info.constants.launcher_id) .tree_hash() .into(), @@ -1840,24 +1728,24 @@ mod tests { let payment_cat_inner_spend = minter_p2.spend_with_conditions( ctx, Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, None) + .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, Memos::None) .create_coin( minter_bls.puzzle_hash, payment_cat_amount - reg_amount, - None, + Memos::None, ), )?; Cat::spend_all( ctx, &[CatSpend { cat: payment_cat, - inner_spend: payment_cat_inner_spend, - extra_delta: 0, + spend: payment_cat_inner_spend, + hidden: false, }], )?; payment_cat_amount -= reg_amount; - payment_cat = payment_cat.wrapped_child(minter_bls.puzzle_hash, payment_cat_amount); + payment_cat = payment_cat.child(minter_bls.puzzle_hash, payment_cat_amount); // sim.spend_coins(ctx.take(), &[user_bls.sk.clone(), minter_bls.sk.clone()])?; benchmark.add_spends( @@ -1927,7 +1815,7 @@ mod tests { price_singleton_proof, price_singleton_puzzle, XchandlesRegistryState::from( - payment_cat.asset_id.tree_hash().into(), + payment_cat.info.asset_id.tree_hash().into(), new_price, reg_period, ), @@ -1944,14 +1832,14 @@ mod tests { delegated_state_action_solution.other_singleton_inner_puzzle_hash, )?; - registry.insert(action_spend); - registry = registry.finish_spend(ctx)?; + registry.insert_action_spend(ctx, action_spend)?; + registry = registry.finish_spend(ctx)?.0; // sim.spend_coins(ctx.take(), &[user_bls.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "update_price", &[user_bls.sk.clone()])?; }; let spent_values = [left_slot.info.value.clone(), right_slot.info.value.clone()]; - let (secure_cond, new_slots) = registry.new_action::().spend( + let secure_cond = registry.new_action::().spend( ctx, &mut registry, left_slot.clone(), @@ -1959,19 +1847,28 @@ mod tests { precommit_coin, base_price, reg_period, + 100, )?; ensure_conditions_met(ctx, &mut sim, secure_cond.clone(), 1)?; assert_eq!( - spent_values, - XchandlesRegisterAction::get_spent_slot_values_from_solution( - ctx, - registry.pending_items.actions[registry.pending_items.actions.len() - 1] - .solution - )? + registry + .pending_spend + .spent_slots + .iter() + .rev() + .take(2) + .collect::>(), + spent_values.iter().rev().collect::>(), ); - registry = registry.finish_spend(ctx)?; + let new_slots = registry + .pending_spend + .created_slots + .iter() + .map(|s| registry.created_slot_value_to_slot(s.clone())) + .collect::>(); + registry = registry.finish_spend(ctx)?.0; sim.pass_time(100); // registration start was at timestamp 100 // sim.spend_coins(ctx.take(), &[user_bls.sk.clone()])?; @@ -1987,25 +1884,28 @@ mod tests { // test on-chain oracle for current handle let spent_slot_value_hash = oracle_slot.info.value_hash; - let (oracle_conds, new_slot) = registry.new_action::().spend( + let oracle_conds = registry.new_action::().spend( ctx, &mut registry, oracle_slot.clone(), )?; + let new_slot = registry + .created_slot_value_to_slot(registry.pending_spend.created_slots[0].clone()); ensure_conditions_met(ctx, &mut sim, oracle_conds, 0)?; assert_eq!( spent_slot_value_hash, - XchandlesOracleAction::get_spent_slot_value_from_solution( - ctx, - registry.pending_items.actions[registry.pending_items.actions.len() - 1] - .solution - )? - .tree_hash() - .into() + registry + .pending_spend + .spent_slots + .iter() + .next_back() + .unwrap() + .tree_hash() + .into() ); - registry = registry.finish_spend(ctx)?; + registry = registry.finish_spend(ctx)?.0; // sim.spend_coins(ctx.take(), &[user_bls.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "oracle", &[user_bls.sk.clone()])?; @@ -2020,37 +1920,45 @@ mod tests { XchandlesFactorPricingPuzzleArgs::get_price(base_price, &handle, extension_years); let spent_slot_value_hash = extension_slot.info.value_hash; - let (notarized_payment, extend_conds, new_slot) = + let (extend_conds, notarized_payment) = registry.new_action::().spend( ctx, &mut registry, handle, extension_slot.clone(), - payment_cat.asset_id, + payment_cat.info.asset_id, base_price, reg_period, extension_years, + 0, )?; + let new_slot = registry + .created_slot_value_to_slot(registry.pending_spend.created_slots[0].clone()); assert_eq!( spent_slot_value_hash, - XchandlesExtendAction::get_spent_slot_value_from_solution( - ctx, - registry.pending_items.actions[registry.pending_items.actions.len() - 1] - .solution - )? - .tree_hash() - .into() + registry + .pending_spend + .spent_slots + .iter() + .next_back() + .unwrap() + .tree_hash() + .into() ); let payment_cat_inner_spend = minter_p2.spend_with_conditions( ctx, extend_conds - .create_coin(SETTLEMENT_PAYMENT_HASH.into(), pay_for_extension, None) + .create_coin( + SETTLEMENT_PAYMENT_HASH.into(), + pay_for_extension, + Memos::None, + ) .create_coin( minter_bls.puzzle_hash, payment_cat_amount - pay_for_extension, - None, + Memos::None, ), )?; @@ -2064,24 +1972,23 @@ mod tests { &[ CatSpend { cat: payment_cat, - inner_spend: payment_cat_inner_spend, - extra_delta: 0, + spend: payment_cat_inner_spend, + hidden: false, }, CatSpend { - cat: payment_cat - .wrapped_child(SETTLEMENT_PAYMENT_HASH.into(), pay_for_extension), - inner_spend: cat_offer_inner_spend, - extra_delta: 0, + cat: payment_cat.child(SETTLEMENT_PAYMENT_HASH.into(), pay_for_extension), + spend: cat_offer_inner_spend, + hidden: false, }, ], )?; payment_cat_amount -= pay_for_extension; - payment_cat = payment_cat.wrapped_child(minter_bls.puzzle_hash, payment_cat_amount); + payment_cat = payment_cat.child(minter_bls.puzzle_hash, payment_cat_amount); - registry = registry.finish_spend(ctx)?; + registry = registry.finish_spend(ctx)?.0; - // sim.spend_coins(ctx.take(), &[user_bls.sk.clone(), minter_bls.sk.clone()])?; + // sim.spend_coins(spends, &[user_bls.sk.clone(), minter_bls.sk.clone()])?; benchmark.add_spends( ctx, &mut sim, @@ -2098,7 +2005,7 @@ mod tests { let update_slot = new_slot; let update_slot_value_hash = update_slot.info.value_hash; - let (update_conds, new_slot) = registry.new_action::().spend( + let update_conds = registry.new_action::().spend( ctx, &mut registry, update_slot.clone(), @@ -2106,20 +2013,23 @@ mod tests { new_resolved_data, did.info.inner_puzzle_hash().into(), )?; + let new_slot = registry + .created_slot_value_to_slot(registry.pending_spend.created_slots[0].clone()); let _new_did = did.update(ctx, &user_p2, update_conds)?; assert_eq!( update_slot_value_hash, - XchandlesUpdateAction::get_spent_slot_value_from_solution( - ctx, - registry.pending_items.actions[registry.pending_items.actions.len() - 1] - .solution - )? - .tree_hash() - .into() + registry + .pending_spend + .spent_slots + .iter() + .next_back() + .unwrap() + .tree_hash() + .into() ); - registry = registry.finish_spend(ctx)?; + registry = registry.finish_spend(ctx)?.0; // sim.spend_coins(ctx.take(), &[user_bls.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "update", &[user_bls.sk.clone()])?; @@ -2149,22 +2059,19 @@ mod tests { let expiration = initial_slot.info.value.expiration; let buy_time = expiration + 27 * 24 * 60 * 60; // last day of auction; 0 < premium < 1 CAT let value = XchandlesPrecommitValue::for_normal_registration( - payment_cat.asset_id.tree_hash(), + payment_cat.info.asset_id.tree_hash(), XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( base_price, reg_period, 1000, ), - XchandlesExponentialPremiumRenewPuzzleSolution { + XchandlesPricingSolution { buy_time, - pricing_program_solution: XchandlesFactorPricingSolution { - current_expiration: expiration, - handle: handle_to_expire.clone(), - num_periods: 1, - }, + current_expiration: expiration, + handle: handle_to_expire.clone(), + num_periods: 1, } .tree_hash(), handle_to_expire.clone(), Bytes32::default(), - buy_time, Bytes32::from([42; 32]), Bytes32::from([69; 32]).into(), ); @@ -2179,7 +2086,7 @@ mod tests { ctx, payment_cat.coin.coin_id(), payment_cat.child_lineage_proof(), - payment_cat.asset_id, + payment_cat.info.asset_id, SingletonStruct::new(registry.info.constants.launcher_id) .tree_hash() .into(), @@ -2194,24 +2101,24 @@ mod tests { let payment_cat_inner_spend = minter_p2.spend_with_conditions( ctx, Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, None) + .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, Memos::None) .create_coin( minter_bls.puzzle_hash, payment_cat_amount - reg_amount, - None, + Memos::None, ), )?; Cat::spend_all( ctx, &[CatSpend { cat: payment_cat, - inner_spend: payment_cat_inner_spend, - extra_delta: 0, + spend: payment_cat_inner_spend, + hidden: false, }], )?; payment_cat = - payment_cat.wrapped_child(minter_bls.puzzle_hash, payment_cat.coin.amount - reg_amount); + payment_cat.child(minter_bls.puzzle_hash, payment_cat.coin.amount - reg_amount); sim.set_next_timestamp(buy_time)?; // sim.spend_coins(ctx.take(), &[user_bls.sk.clone(), minter_bls.sk.clone()])?; @@ -2223,7 +2130,7 @@ mod tests { )?; let spent_slot_value_hash = initial_slot.info.value_hash; - let (expire_conds, _new_slot) = registry.new_action::().spend( + let expire_conds = registry.new_action::().spend( ctx, &mut registry, initial_slot.clone(), @@ -2231,6 +2138,7 @@ mod tests { base_price, reg_period, precommit_coin, + buy_time, )?; // assert expire conds @@ -2238,14 +2146,16 @@ mod tests { assert_eq!( spent_slot_value_hash, - XchandlesExpireAction::get_spent_slot_value_from_solution( - ctx, - registry.pending_items.actions[registry.pending_items.actions.len() - 1].solution - )? - .tree_hash() - .into() + registry + .pending_spend + .spent_slots + .iter() + .next_back() + .unwrap() + .tree_hash() + .into() ); - registry = registry.finish_spend(ctx)?; + registry = registry.finish_spend(ctx)?.0; // sim.spend_coins(ctx.take(), &[user_bls.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "expire", &[user_bls.sk.clone()])?; @@ -2262,22 +2172,12 @@ mod tests { )? .get_puzzle(ctx)? }; - let pricing_solution = if use_factor_pricing { - ctx.alloc(&XchandlesFactorPricingSolution { - current_expiration: 0, - handle: unregistered_handle.clone(), - num_periods: 1, - })? - } else { - ctx.alloc(&XchandlesExponentialPremiumRenewPuzzleSolution { - buy_time: 28 * 24 * 60 * 60 + 1, // premium should be 0 - pricing_program_solution: XchandlesFactorPricingSolution { - current_expiration: 0, - handle: unregistered_handle.clone(), - num_periods: 1, - }, - })? - }; + let pricing_solution = ctx.alloc(&XchandlesPricingSolution { + buy_time: 28 * 24 * 60 * 60 + 1, // premium should be 0 + current_expiration: 0, + handle: unregistered_handle.clone(), + num_periods: 1, + })?; let expected_price = XchandlesFactorPricingPuzzleArgs::get_price(base_price, &unregistered_handle, 1); @@ -2309,22 +2209,12 @@ mod tests { .find(|s| s.info.value.handle_hash == existing_handle.tree_hash().into()) .unwrap() .clone(); - let existing_handle_pricing_solution = if use_factor_pricing { - ctx.alloc(&XchandlesFactorPricingSolution { - current_expiration: existing_slot.info.value.expiration, - handle: existing_handle.clone(), - num_periods: 1, - })? - } else { - ctx.alloc(&XchandlesExponentialPremiumRenewPuzzleSolution { - buy_time: existing_slot.info.value.expiration + 28 * 24 * 60 * 60 + 1, // premium should be 0 - pricing_program_solution: XchandlesFactorPricingSolution { - current_expiration: existing_slot.info.value.expiration, - handle: existing_handle.clone(), - num_periods: 1, - }, - })? - }; + let existing_handle_pricing_solution = ctx.alloc(&XchandlesPricingSolution { + buy_time: existing_slot.info.value.expiration + 28 * 24 * 60 * 60 + 1, // premium should be 0 + current_expiration: existing_slot.info.value.expiration, + handle: existing_handle.clone(), + num_periods: 1, + })?; let existing_handle_expected_price = XchandlesFactorPricingPuzzleArgs::get_price(base_price, &existing_handle, 1); @@ -2333,20 +2223,19 @@ mod tests { let minter2 = sim.bls(alternative_payment_cat_amount); let minter_p2_2 = StandardLayer::new(minter2.pk); - let (issue_cat, mut alternative_payment_cat) = Cat::single_issuance_eve( + let (issue_cat, alternative_payment_cat) = Cat::issue_with_coin( ctx, minter2.coin.coin_id(), alternative_payment_cat_amount, Conditions::new().create_coin( minter2.puzzle_hash, alternative_payment_cat_amount, - None, + Memos::None, ), )?; minter_p2_2.spend(ctx, minter2.coin, issue_cat)?; - alternative_payment_cat = alternative_payment_cat - .wrapped_child(minter2.puzzle_hash, alternative_payment_cat_amount); + let alternative_payment_cat = alternative_payment_cat[0]; sim.spend_coins(ctx.take(), &[minter2.sk.clone()])?; registry = test_refund_for_xchandles( @@ -2448,9 +2337,9 @@ mod tests { metadata: cat_nft_metadata_for_testing(), metadata_updater_puzzle_hash: ANY_METADATA_UPDATER_HASH.into(), royalty_puzzle_hash, - royalty_ten_thousandths: 100, + royalty_basis_points: 100, p2_puzzle_hash: bls.puzzle_hash, - owner: None, + transfer_condition: None, }, )?; p2.spend(ctx, bls.coin, create_nft)?; @@ -2499,7 +2388,7 @@ mod tests { let test_singleton_inner_puzzle_hash = ctx.tree_hash(test_singleton_inner_puzzle); let test_singleton_inner_solution = test_singleton_output_conditions - .create_coin(test_singleton_inner_puzzle_hash.into(), 1, None) + .create_coin(test_singleton_inner_puzzle_hash.into(), 1, Memos::None) .to_clvm(ctx)?; let test_singleton_solution = ctx.alloc(&SingletonSolution { lineage_proof: test_singleton_proof, @@ -2551,15 +2440,15 @@ mod tests { let cat_minter = sim.bls(cat_amount); let cat_minter_p2 = StandardLayer::new(cat_minter.pk); - let (issue_cat, mut source_cat) = Cat::single_issuance_eve( + let (issue_cat, source_cat) = Cat::issue_with_coin( ctx, cat_minter.coin.coin_id(), cat_amount, - Conditions::new().create_coin(cat_minter.puzzle_hash, cat_amount, None), + Conditions::new().create_coin(cat_minter.puzzle_hash, cat_amount, Memos::None), )?; cat_minter_p2.spend(ctx, cat_minter.coin, issue_cat)?; - source_cat = source_cat.wrapped_child(cat_minter.puzzle_hash, cat_amount); + let source_cat = source_cat[0]; sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; // Launch manager singleton @@ -2582,7 +2471,7 @@ mod tests { 42, 420, // 4.2% fee 9000, // 90% of the amount deposited will be returned - source_cat.asset_id, + source_cat.info.asset_id, ); // Create source offer @@ -2593,7 +2482,11 @@ mod tests { let launcher_bls = sim.bls(offer_amount); let offer_spend = StandardLayer::new(launcher_bls.pk).spend_with_conditions( ctx, - Conditions::new().create_coin(SETTLEMENT_PAYMENT_HASH.into(), offer_amount, None), + Conditions::new().create_coin( + SETTLEMENT_PAYMENT_HASH.into(), + offer_amount, + Memos::None, + ), )?; let puzzle_reveal = ctx.serialize(&offer_spend.puzzle)?; @@ -2602,7 +2495,7 @@ mod tests { let cat_minter_inner_puzzle = clvm_quote!(Conditions::new().create_coin( SETTLEMENT_PAYMENT_HASH.into(), source_cat.coin.amount, - None + Memos::None )) .to_clvm(ctx)?; let source_cat_inner_spend = cat_minter_p2.delegated_inner_spend( @@ -2623,7 +2516,8 @@ mod tests { }, prev_subtotal: 0, extra_delta: 0, - inner_spend: source_cat_inner_spend, + p2_spend: source_cat_inner_spend, + revoke: false, }, )?; let spends = ctx.take(); @@ -2638,31 +2532,36 @@ mod tests { } } - let offer = Offer::new(SpendBundle { - coin_spends: vec![ - CoinSpend::new(launcher_bls.coin, puzzle_reveal, solution), - cat_offer_spend, - ], - aggregated_signature: sign_standard_transaction( - ctx, - launcher_bls.coin, - offer_spend, - &launcher_bls.sk, - &TESTNET11_CONSTANTS, - )?, - }); - - // Launch the reward distributor - let first_epoch_start = 1234; - let (_, security_sk, mut registry, first_epoch_slot) = launch_dig_reward_distributor( + let agg_sig = sign_standard_transaction( ctx, - offer, - first_epoch_start, - Bytes32::default(), - constants, + launcher_bls.coin, + offer_spend, + &launcher_bls.sk, &TESTNET11_CONSTANTS, - "yak yak yak", )?; + let offer = Offer::from_spend_bundle( + ctx, + &SpendBundle { + coin_spends: vec![ + CoinSpend::new(launcher_bls.coin, puzzle_reveal, solution), + cat_offer_spend, + ], + aggregated_signature: agg_sig, + }, + )?; + + // Launch the reward distributor + let first_epoch_start = 1234; + let (_, security_sk, mut registry, first_epoch_slot, mut source_cat) = + launch_dig_reward_distributor( + ctx, + &offer, + first_epoch_start, + source_cat.info.p2_puzzle_hash, + constants, + &TESTNET11_CONSTANTS, + "yak yak yak", + )?; // sim.spend_coins( // ctx.take(), @@ -2683,16 +2582,13 @@ mod tests { ], )?; - source_cat = source_cat - .wrapped_child(SETTLEMENT_PAYMENT_HASH.into(), source_cat.coin.amount) - .wrapped_child(cat_minter.puzzle_hash, source_cat.coin.amount); assert!(sim.coin_state(source_cat.coin.coin_id()).is_some()); let nft_bls = sim.bls(1); // add the 1st entry/NFT before reward epoch ('first epoch') begins let (entry1_slot, _nft1) = if manager_type == RewardDistributorType::Manager { - let (manager_conditions, entry1_slot) = registry + let manager_conditions = registry .new_action::() .spend( ctx, @@ -2701,7 +2597,11 @@ mod tests { 1, manager_or_did_singleton_inner_puzzle_hash, )?; - registry = registry.finish_spend(ctx, vec![])?; + let entry1_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_entry_slots[0], + RewardDistributorSlotNonce::ENTRY, + ); + registry = registry.finish_spend(ctx, vec![])?.0; (manager_or_did_coin, manager_or_did_singleton_proof) = spend_manager_singleton( ctx, @@ -2757,27 +2657,30 @@ mod tests { }], }; - let (sec_conds, notarized_payment, entry1_slot, locked_nft) = registry + let (sec_conds, notarized_payment, locked_nft) = registry .new_action::() .spend(ctx, &mut registry, nft, nft_proof, nft_bls.puzzle_hash)?; - registry = registry.finish_spend(ctx, vec![])?; + let entry1_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_entry_slots[0], + RewardDistributorSlotNonce::ENTRY, + ); + registry = registry.finish_spend(ctx, vec![])?.0; ensure_conditions_met(ctx, &mut sim, sec_conds, 0)?; - let offer_nft = - nft.wrapped_child(SETTLEMENT_PAYMENT_HASH.into(), None, nft.info.metadata); + let offer_nft = nft.child(SETTLEMENT_PAYMENT_HASH.into(), None, nft.info.metadata, 1); let nft_inner_spend = Spend::new( ctx.alloc(&clvm_quote!(Conditions::new().create_coin( SETTLEMENT_PAYMENT_HASH.into(), 1, - None + Memos::None )))?, NodePtr::NIL, ); let nft_inner_spend = StandardLayer::new(nft_bls.pk).delegated_inner_spend(ctx, nft_inner_spend)?; - nft.spend(ctx, nft_inner_spend)?; + let _new_nft = nft.spend(ctx, nft_inner_spend)?; let nft_inner_spend = Spend::new( ctx.alloc_mod::()?, @@ -2785,7 +2688,7 @@ mod tests { notarized_payments: vec![notarized_payment], })?, ); - offer_nft.spend(ctx, nft_inner_spend)?; + let _new_offer_nft = offer_nft.spend(ctx, nft_inner_spend)?; // sim.spend_coins(spends, &[nft_bls.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "stake_nft", &[nft_bls.sk.clone()])?; @@ -2795,7 +2698,7 @@ mod tests { // commit incentives for first epoch let rewards_to_add = constants.epoch_seconds; - let (secure_conditions, first_epoch_commitment_slot, mut incentive_slots) = registry + let secure_conditions = registry .new_action::() .spend( ctx, @@ -2805,8 +2708,19 @@ mod tests { cat_minter.puzzle_hash, rewards_to_add, )?; + let first_epoch_commitment_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_commitment_slots[0], + RewardDistributorSlotNonce::COMMITMENT, + ); + let mut incentive_slots = registry + .pending_spend + .created_reward_slots + .iter() + .map(|s| registry.created_slot_value_to_slot(*s, RewardDistributorSlotNonce::REWARD)) + .collect::>(); // spend reserve and source cat together so deltas add up + let hint = ctx.hint(cat_minter.puzzle_hash)?; let source_cat_spend = CatSpend::new( source_cat, cat_minter_p2.spend_with_conditions( @@ -2814,15 +2728,15 @@ mod tests { secure_conditions.create_coin( cat_minter.puzzle_hash, source_cat.coin.amount - rewards_to_add, - None, + hint, ), )?, ); - registry = registry.finish_spend(ctx, vec![source_cat_spend])?; + registry = registry.finish_spend(ctx, vec![source_cat_spend])?.0; // sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "commit_incentives", &[cat_minter.sk.clone()])?; - source_cat = source_cat.wrapped_child( + source_cat = source_cat.child( cat_minter.puzzle_hash, source_cat.coin.amount - rewards_to_add, ); @@ -2836,7 +2750,7 @@ mod tests { // commit incentives for fifth epoch let fifth_epoch_start = first_epoch_start + constants.epoch_seconds * 4; let rewards_to_add = constants.epoch_seconds * 10; - let (secure_conditions, fifth_epoch_commitment_slot, new_incentive_slots) = registry + let secure_conditions = registry .new_action::() .spend( ctx, @@ -2846,6 +2760,16 @@ mod tests { cat_minter.puzzle_hash, rewards_to_add, )?; + let fifth_epoch_commitment_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_commitment_slots[0], + RewardDistributorSlotNonce::COMMITMENT, + ); + let new_incentive_slots = registry + .pending_spend + .created_reward_slots + .iter() + .map(|s| registry.created_slot_value_to_slot(*s, RewardDistributorSlotNonce::REWARD)) + .collect::>(); let new_value_keys = new_incentive_slots .iter() @@ -2862,16 +2786,16 @@ mod tests { secure_conditions.create_coin( cat_minter.puzzle_hash, source_cat.coin.amount - rewards_to_add, - None, + Memos::None, ), )?, ); - registry = registry.finish_spend(ctx, vec![source_cat_spend])?; + registry = registry.finish_spend(ctx, vec![source_cat_spend])?.0; // sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "commit_incentives", &[cat_minter.sk.clone()])?; - source_cat = source_cat.wrapped_child( + source_cat = source_cat.child( cat_minter.puzzle_hash, source_cat.coin.amount - rewards_to_add, ); @@ -2884,7 +2808,7 @@ mod tests { // 2nd commit incentives for fifth epoch let rewards_to_add = constants.epoch_seconds * 2; - let (secure_conditions, fifth_epoch_commitment_slot2, new_incentive_slots) = registry + let secure_conditions = registry .new_action::() .spend( ctx, @@ -2898,6 +2822,16 @@ mod tests { cat_minter.puzzle_hash, rewards_to_add, )?; + let fifth_epoch_commitment_slot2 = registry.created_slot_value_to_slot( + registry.pending_spend.created_commitment_slots[0], + RewardDistributorSlotNonce::COMMITMENT, + ); + let new_incentive_slots = registry + .pending_spend + .created_reward_slots + .iter() + .map(|s| registry.created_slot_value_to_slot(*s, RewardDistributorSlotNonce::REWARD)) + .collect::>(); let new_value_keys = new_incentive_slots .iter() @@ -2914,16 +2848,16 @@ mod tests { secure_conditions.create_coin( cat_minter.puzzle_hash, source_cat.coin.amount - rewards_to_add, - None, + Memos::None, ), )?, ); - registry = registry.finish_spend(ctx, vec![source_cat_spend])?; + registry = registry.finish_spend(ctx, vec![source_cat_spend])?.0; // sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "commit_incentives", &[cat_minter.sk.clone()])?; - source_cat = source_cat.wrapped_child( + source_cat = source_cat.child( cat_minter.puzzle_hash, source_cat.coin.amount - rewards_to_add, ); @@ -2940,7 +2874,7 @@ mod tests { .is_none()); // withdraw the 1st incentives for epoch 5 - let (withdraw_incentives_conditions, new_reward_slot, withdrawn_amount) = registry + let (withdraw_incentives_conditions, withdrawn_amount) = registry .new_action::() .spend( ctx, @@ -2952,11 +2886,15 @@ mod tests { .unwrap() .clone(), )?; + let new_reward_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_reward_slots[0], + RewardDistributorSlotNonce::REWARD, + ); let payout_coin_id = registry .reserve .to_cat() - .wrapped_child( + .child( cat_minter.puzzle_hash, // fifth_epoch_commitment_slot.info.value.unwrap().clawback_ph, withdrawn_amount, ) @@ -2966,7 +2904,7 @@ mod tests { let claimer_coin = sim.new_coin(cat_minter.puzzle_hash, 0); cat_minter_p2.spend(ctx, claimer_coin, withdraw_incentives_conditions)?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; sim.set_next_timestamp(first_epoch_start)?; // sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; benchmark.add_spends( @@ -2998,7 +2936,7 @@ mod tests { .find(|s| s.info.value.epoch_start == first_epoch_start) .unwrap() .clone(); - let (new_epoch_conditions, new_reward_slot, fee) = registry + let (new_epoch_conditions, fee) = registry .new_action::() .spend( ctx, @@ -3006,14 +2944,18 @@ mod tests { first_epoch_incentives_slot.clone(), // first_epoch_incentives_slot.info.value.rewards, )?; + let new_reward_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_reward_slots[0], + RewardDistributorSlotNonce::REWARD, + ); let payout_coin_id = reserve_cat - .wrapped_child(constants.fee_payout_puzzle_hash, fee) + .child(constants.fee_payout_puzzle_hash, fee) .coin .coin_id(); ensure_conditions_met(ctx, &mut sim, new_epoch_conditions, 0)?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; sim.pass_time(100); // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "new_epoch", &[])?; @@ -3057,7 +2999,7 @@ mod tests { )?; ensure_conditions_met(ctx, &mut sim, sync_conditions, 0)?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; sim.pass_time(400); // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "sync", &[])?; @@ -3083,7 +3025,7 @@ mod tests { )?; ensure_conditions_met(ctx, &mut sim, sync_conditions, 0)?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "sync", &[])?; assert!(registry.info.state.round_time_info.last_update == first_epoch_start + 500); @@ -3115,12 +3057,12 @@ mod tests { add_incentives_conditions.create_coin( cat_minter.puzzle_hash, source_cat.coin.amount - incentives_amount, - None, + Memos::None, ), )?, ); - registry = registry.finish_spend(ctx, vec![source_cat_spend])?; + registry = registry.finish_spend(ctx, vec![source_cat_spend])?.0; // sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "add_incentives", &[cat_minter.sk.clone()])?; @@ -3137,7 +3079,7 @@ mod tests { registry_info.state.round_reward_info.remaining_rewards + (incentives_amount - incentives_amount * constants.fee_bps / 10000) ); - source_cat = source_cat.wrapped_child( + source_cat = source_cat.child( cat_minter.puzzle_hash, source_cat.coin.amount - incentives_amount, ); @@ -3146,7 +3088,7 @@ mod tests { let nft2_bls = sim.bls(0); let nft3_bls = sim.bls(0); let (entry2_slot, other_nft2_info) = if manager_type == RewardDistributorType::Manager { - let (manager_conditions, entry2_slot) = registry + let manager_conditions = registry .new_action::() .spend( ctx, @@ -3155,6 +3097,11 @@ mod tests { 2, manager_or_did_singleton_inner_puzzle_hash, )?; + let entry2_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_entry_slots[0], + RewardDistributorSlotNonce::ENTRY, + ); + (manager_or_did_coin, manager_or_did_singleton_proof) = spend_manager_singleton( ctx, manager_or_did_coin, @@ -3163,7 +3110,7 @@ mod tests { manager_conditions, )?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; sim.pass_time(250); // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "add_entry", &[])?; @@ -3232,26 +3179,34 @@ mod tests { }], }; - let (sec_conds2, notarized_payment2, entry2_slot, locked_nft2) = registry + let (sec_conds2, notarized_payment2, locked_nft2) = registry .new_action::() .spend(ctx, &mut registry, nft2, nft2_proof, nft2_bls.puzzle_hash)?; - let (sec_conds3, notarized_payment3, entry3_slot, locked_nft3) = registry + let entry2_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_entry_slots[0], + RewardDistributorSlotNonce::ENTRY, + ); + let (sec_conds3, notarized_payment3, locked_nft3) = registry .new_action::() .spend(ctx, &mut registry, nft3, nft3_proof, nft3_bls.puzzle_hash)?; - registry = registry.finish_spend(ctx, vec![])?; + let entry3_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_entry_slots[1], + RewardDistributorSlotNonce::ENTRY, + ); + registry = registry.finish_spend(ctx, vec![])?.0; ensure_conditions_met(ctx, &mut sim, sec_conds2.extend(sec_conds3), 0)?; let offer2_nft = - nft2.wrapped_child(SETTLEMENT_PAYMENT_HASH.into(), None, nft2.info.metadata); + nft2.child(SETTLEMENT_PAYMENT_HASH.into(), None, nft2.info.metadata, 1); let offer3_nft = - nft3.wrapped_child(SETTLEMENT_PAYMENT_HASH.into(), None, nft3.info.metadata); + nft3.child(SETTLEMENT_PAYMENT_HASH.into(), None, nft3.info.metadata, 1); let nfts_inner_spend = Spend::new( ctx.alloc(&clvm_quote!(Conditions::new().create_coin( SETTLEMENT_PAYMENT_HASH.into(), 1, - None + Memos::None )))?, NodePtr::NIL, ); @@ -3259,8 +3214,8 @@ mod tests { StandardLayer::new(nft2_bls.pk).delegated_inner_spend(ctx, nfts_inner_spend)?; let nft3_inner_spend = StandardLayer::new(nft3_bls.pk).delegated_inner_spend(ctx, nfts_inner_spend)?; - nft2.spend(ctx, nft2_inner_spend)?; - nft3.spend(ctx, nft3_inner_spend)?; + let _new_nft2 = nft2.spend(ctx, nft2_inner_spend)?; + let _new_nft3 = nft3.spend(ctx, nft3_inner_spend)?; let nft2_inner_spend = Spend::new( ctx.alloc_mod::()?, @@ -3268,7 +3223,7 @@ mod tests { notarized_payments: vec![notarized_payment2], })?, ); - offer2_nft.spend(ctx, nft2_inner_spend)?; + let _new_offer2_nft = offer2_nft.spend(ctx, nft2_inner_spend)?; let nft3_inner_spend = Spend::new( ctx.alloc_mod::()?, @@ -3276,7 +3231,7 @@ mod tests { notarized_payments: vec![notarized_payment3], })?, ); - offer3_nft.spend(ctx, nft3_inner_spend)?; + let _new_offer3_nft = offer3_nft.spend(ctx, nft3_inner_spend)?; sim.pass_time(250); // sim.spend_coins(spends, &[nft2_bls.sk.clone(), nft3_bls.sk.clone()])?; @@ -3300,7 +3255,7 @@ mod tests { )?; ensure_conditions_met(ctx, &mut sim, sync_conditions, 0)?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "sync", &[])?; assert!(registry.info.state.round_time_info.last_update == first_epoch_start + 750); @@ -3319,11 +3274,11 @@ mod tests { let reserve_cat = registry.reserve.to_cat(); if let Some((entry3_slot, locked_nft2, locked_nft3)) = other_nft2_info { let nft2_return_coin_id = locked_nft2 - .wrapped_child(nft2_bls.puzzle_hash, None, locked_nft2.info.metadata) + .child(nft2_bls.puzzle_hash, None, locked_nft2.info.metadata, 1) .coin .coin_id(); let nft3_return_coin_id = locked_nft3 - .wrapped_child(nft3_bls.puzzle_hash, None, locked_nft3.info.metadata) + .child(nft3_bls.puzzle_hash, None, locked_nft3.info.metadata, 1) .coin .coin_id(); @@ -3337,7 +3292,7 @@ mod tests { StandardLayer::new(nft2_bls.pk).spend(ctx, nft2_bls.coin, custody2_conds)?; StandardLayer::new(nft3_bls.pk).spend(ctx, nft3_bls.coin, custody3_conds)?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; // sim.spend_coins(spends, &[nft2_bls.sk.clone(), nft3_bls.sk.clone()])?; benchmark.add_spends( @@ -3348,11 +3303,11 @@ mod tests { )?; let payout_coin_id2 = reserve_cat - .wrapped_child(nft2_bls.puzzle_hash, payout2_amount) + .child(nft2_bls.puzzle_hash, payout2_amount) .coin .coin_id(); let payout_coin_id3 = reserve_cat - .wrapped_child(nft3_bls.puzzle_hash, payout3_amount) + .child(nft3_bls.puzzle_hash, payout3_amount) .coin .coin_id(); @@ -3383,11 +3338,11 @@ mod tests { remove_entry_manager_conditions, )?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "remove_entry", &[])?; let payout_coin_id = reserve_cat - .wrapped_child(entry2_bls.puzzle_hash, entry2_payout_amount) + .child(entry2_bls.puzzle_hash, entry2_payout_amount) .coin .coin_id(); @@ -3426,9 +3381,13 @@ mod tests { .unwrap() .clone(); - let (new_epoch_conditions, new_reward_slot, _manager_fee) = registry + let (new_epoch_conditions, _manager_fee) = registry .new_action::() .spend(ctx, &mut registry, reward_slot)?; + let new_reward_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_reward_slots[0], + RewardDistributorSlotNonce::REWARD, + ); incentive_slots .retain(|s| s.info.value.epoch_start != new_reward_slot.info.value.epoch_start); incentive_slots.push(new_reward_slot); @@ -3442,7 +3401,7 @@ mod tests { 0, )?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; sim.set_next_timestamp(update_time)?; // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "sync_and_new_epoch", &[])?; @@ -3451,7 +3410,7 @@ mod tests { // commit incentives for 10th epoch let tenth_epoch_start = first_epoch_start + constants.epoch_seconds * 9; let rewards_to_add = constants.epoch_seconds * 10; - let (secure_conditions, tenth_epoch_commitment_slot, new_incentive_slots) = registry + let secure_conditions = registry .new_action::() .spend( ctx, @@ -3461,6 +3420,16 @@ mod tests { cat_minter.puzzle_hash, rewards_to_add, )?; + let tenth_epoch_commitment_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_commitment_slots[0], + RewardDistributorSlotNonce::COMMITMENT, + ); + let new_incentive_slots = registry + .pending_spend + .created_reward_slots + .iter() + .map(|s| registry.created_slot_value_to_slot(*s, RewardDistributorSlotNonce::REWARD)) + .collect::>(); let new_value_keys = new_incentive_slots .iter() @@ -3477,15 +3446,15 @@ mod tests { secure_conditions.create_coin( cat_minter.puzzle_hash, source_cat.coin.amount - rewards_to_add, - None, + Memos::None, ), )?, ); - registry = registry.finish_spend(ctx, vec![source_cat_spend])?; + registry = registry.finish_spend(ctx, vec![source_cat_spend])?.0; // sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; benchmark.add_spends(ctx, &mut sim, "commit_incentives", &[cat_minter.sk.clone()])?; - let _source_cat = source_cat.wrapped_child( + let _source_cat = source_cat.child( cat_minter.puzzle_hash, source_cat.coin.amount - rewards_to_add, ); @@ -3511,7 +3480,7 @@ mod tests { }) .unwrap() .clone(); - let (new_epoch_conditions, new_reward_slot, _manager_fee) = registry + let (new_epoch_conditions, _manager_fee) = registry .new_action::() .spend( ctx, @@ -3519,6 +3488,10 @@ mod tests { reward_slot.clone(), // reward_slot.info.value.rewards, )?; + let new_reward_slot = registry.created_slot_value_to_slot( + registry.pending_spend.created_reward_slots[0], + RewardDistributorSlotNonce::REWARD, + ); incentive_slots .retain(|s| s.info.value.epoch_start != new_reward_slot.info.value.epoch_start); incentive_slots.push(new_reward_slot); @@ -3530,7 +3503,7 @@ mod tests { 0, )?; - registry = registry.finish_spend(ctx, vec![])?; + registry = registry.finish_spend(ctx, vec![])?.0; sim.set_next_timestamp(update_time)?; // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "sync", &[])?; @@ -3545,19 +3518,19 @@ mod tests { // payout entry let reserve_cat = registry.reserve.to_cat(); - let (payout_conditions, _entry1_slot, withdrawal_amount) = registry + let (payout_conditions, withdrawal_amount) = registry .new_action::() .spend(ctx, &mut registry, entry1_slot)?; ensure_conditions_met(ctx, &mut sim, payout_conditions.extend(sync_conditions), 0)?; - let _registry = registry.finish_spend(ctx, vec![])?; + let _registry = registry.finish_spend(ctx, vec![])?.0; sim.set_next_timestamp(update_time)?; // sim.spend_coins(ctx.take(), &[])?; benchmark.add_spends(ctx, &mut sim, "initiate_payout", &[])?; let payout_coin_id = reserve_cat - .wrapped_child( + .child( match manager_type { RewardDistributorType::Manager => entry1_bls.puzzle_hash, RewardDistributorType::Nft => nft_bls.puzzle_hash, diff --git a/src/layers/action_layer.rs b/src/layers/action_layer.rs index 026b5707..fcc99612 100644 --- a/src/layers/action_layer.rs +++ b/src/layers/action_layer.rs @@ -566,7 +566,7 @@ impl ReserveFinalizer2ndCurryArgs { } #[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct ReserveFinalizerSolution { pub reserve_parent_id: Bytes32, } @@ -611,7 +611,7 @@ impl ActionLayerArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RawActionLayerSolution { pub puzzles: Vec

, pub selectors_and_proofs: Vec<(u32, Option)>, diff --git a/src/layers/actions/catalog/refund.rs b/src/layers/actions/catalog/refund.rs index 11f8f128..9b3e8e52 100644 --- a/src/layers/actions/catalog/refund.rs +++ b/src/layers/actions/catalog/refund.rs @@ -56,6 +56,27 @@ impl CatalogRefundAction { .to_clvm(ctx)?) } + pub fn spent_slot_value( + &self, + ctx: &SpendContext, + solution: NodePtr, + ) -> Result, DriverError> { + let params = CatalogRefundActionSolution::::from_clvm(ctx, solution)?; + + Ok(params.neighbors.map(|neighbors| CatalogSlotValue { + asset_id: params.tail_hash, + neighbors, + })) + } + + pub fn created_slot_value( + &self, + ctx: &SpendContext, + solution: NodePtr, + ) -> Result, DriverError> { + self.spent_slot_value(ctx, solution) + } + #[allow(clippy::too_many_arguments)] pub fn spend( self, @@ -90,6 +111,7 @@ impl CatalogRefundAction { // if there's a slot, spend it if let Some(slot) = slot { + let slot = catalog.actual_slot(slot); slot.spend(ctx, spender_inner_puzzle_hash)?; } @@ -113,7 +135,7 @@ impl CatalogRefundAction { let action_solution = action_solution.to_clvm(ctx)?; let action_puzzle = self.construct_puzzle(ctx)?; - catalog.insert(Spend::new(action_puzzle, action_solution)); + catalog.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; Ok(secure_conditions) } } @@ -170,7 +192,7 @@ impl CatalogRefundActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct CatalogRefundActionSolution { pub precommited_cat_maker_hash: Bytes32, pub precommited_cat_maker_reveal: P, diff --git a/src/layers/actions/catalog/register.rs b/src/layers/actions/catalog/register.rs index 3f3b306b..cb62ba11 100644 --- a/src/layers/actions/catalog/register.rs +++ b/src/layers/actions/catalog/register.rs @@ -47,7 +47,7 @@ impl Action for CatalogRegisterAction { Self { launcher_id: constants.launcher_id, royalty_puzzle_hash_hash: constants.royalty_address.tree_hash().into(), - trade_price_percentage: constants.royalty_ten_thousandths, + trade_price_percentage: constants.royalty_basis_points, relative_block_height: constants.relative_block_height, payout_puzzle_hash: constants.precommit_payout_puzzle_hash, } @@ -69,7 +69,28 @@ impl CatalogRegisterAction { .to_clvm(ctx)?) } - pub fn get_slot_values_from_solution( + pub fn spent_slot_values( + &self, + ctx: &SpendContext, + solution: NodePtr, + ) -> Result<[CatalogSlotValue; 2], DriverError> { + let params = CatalogRegisterActionSolution::::from_clvm(ctx, solution)?; + + Ok([ + CatalogSlotValue::new( + params.left_tail_hash, + params.left_left_tail_hash, + params.right_tail_hash, + ), + CatalogSlotValue::new( + params.right_tail_hash, + params.left_tail_hash, + params.right_right_tail_hash, + ), + ]) + } + + pub fn created_slot_values( &self, ctx: &SpendContext, solution: NodePtr, @@ -105,7 +126,7 @@ impl CatalogRegisterAction { right_slot: Slot, precommit_coin: PrecommitCoin, eve_nft_inner_spend: Spend, - ) -> Result<(Conditions, Vec>), DriverError> { + ) -> Result { // calculate announcement let register_announcement: Bytes32 = clvm_tuple!(tail_hash, precommit_coin.value.initial_inner_puzzle_hash) @@ -135,13 +156,14 @@ impl CatalogRegisterAction { (), ANY_METADATA_UPDATER_HASH.into(), catalog.info.constants.royalty_address, - catalog.info.constants.royalty_ten_thousandths, + catalog.info.constants.royalty_basis_points, )?; // spend nft launcher - nft.spend(ctx, eve_nft_inner_spend)?; + let _new_nft = nft.spend(ctx, eve_nft_inner_spend)?; // finally, spend self + let (left_slot, right_slot) = catalog.actual_neigbors(tail_hash, left_slot, right_slot); let my_solution = CatalogRegisterActionSolution { cat_maker_reveal: DefaultCatMakerArgs::get_puzzle( ctx, @@ -160,20 +182,18 @@ impl CatalogRegisterAction { let my_solution = my_solution.to_clvm(ctx)?; let my_puzzle = self.construct_puzzle(ctx)?; - let slot_values = self.get_slot_values_from_solution(ctx, my_solution)?; - catalog.insert(Spend::new(my_puzzle, my_solution)); + catalog.insert_action_spend(ctx, Spend::new(my_puzzle, my_solution))?; // spend slots left_slot.spend(ctx, my_inner_puzzle_hash)?; right_slot.spend(ctx, my_inner_puzzle_hash)?; - Ok(( + Ok( Conditions::new().assert_puzzle_announcement(announcement_id( catalog.coin.puzzle_hash, register_announcement, )), - catalog.created_slot_values_to_slots(slot_values.to_vec()), - )) + ) } } @@ -279,7 +299,7 @@ impl CatalogRegisterActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct CatalogRegisterActionSolution { pub cat_maker_reveal: P, pub cat_maker_solution: S, diff --git a/src/layers/actions/delegated_state.rs b/src/layers/actions/delegated_state.rs index 3f1b2eb6..383676ec 100644 --- a/src/layers/actions/delegated_state.rs +++ b/src/layers/actions/delegated_state.rs @@ -119,7 +119,7 @@ impl DelegatedStateActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct DelegatedStateActionSolution { pub new_state: S, #[clvm(rest)] diff --git a/src/layers/actions/reward_distributor/add_entry.rs b/src/layers/actions/reward_distributor/add_entry.rs index 73687499..c6d010cf 100644 --- a/src/layers/actions/reward_distributor/add_entry.rs +++ b/src/layers/actions/reward_distributor/add_entry.rs @@ -58,8 +58,7 @@ impl RewardDistributorAddEntryAction { .map_err(DriverError::ToClvm) } - pub fn get_slot_value_from_solution( - &self, + pub fn created_slot_value( ctx: &SpendContext, state: &RewardDistributorState, solution: NodePtr, @@ -80,7 +79,7 @@ impl RewardDistributorAddEntryAction { payout_puzzle_hash: Bytes32, shares: u64, manager_singleton_inner_puzzle_hash: Bytes32, - ) -> Result<(Conditions, Slot), DriverError> { + ) -> Result { // calculate message that the manager needs to send let add_entry_message: Bytes32 = clvm_tuple!(payout_puzzle_hash, shares).tree_hash().into(); let mut add_entry_message: Vec = add_entry_message.to_vec(); @@ -99,15 +98,8 @@ impl RewardDistributorAddEntryAction { })?; let action_puzzle = self.construct_puzzle(ctx)?; - let my_state = distributor.get_latest_pending_state(ctx)?; - let slot_value = self.get_slot_value_from_solution(ctx, &my_state, action_solution)?; - distributor.insert(Spend::new(action_puzzle, action_solution)); - Ok(( - add_entry_message, - distributor - .created_slot_values_to_slots(vec![slot_value], RewardDistributorSlotNonce::ENTRY) - .remove(0), - )) + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; + Ok(add_entry_message) } } @@ -164,7 +156,7 @@ impl RewardDistributorAddEntryActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorAddEntryActionSolution { pub manager_singleton_inner_puzzle_hash: Bytes32, pub entry_payout_puzzle_hash: Bytes32, diff --git a/src/layers/actions/reward_distributor/add_incentives.rs b/src/layers/actions/reward_distributor/add_incentives.rs index aacfd0b7..29f33463 100644 --- a/src/layers/actions/reward_distributor/add_incentives.rs +++ b/src/layers/actions/reward_distributor/add_incentives.rs @@ -55,7 +55,7 @@ impl RewardDistributorAddIncentivesAction { distributor: &mut RewardDistributor, amount: u64, ) -> Result { - let my_state = distributor.get_latest_pending_state(ctx)?; + let my_state = distributor.pending_spend.latest_state.1; // calculate announcement needed to ensure everything's happening as expected let mut add_incentives_announcement: Vec = @@ -74,7 +74,7 @@ impl RewardDistributorAddIncentivesAction { })?; let action_puzzle = self.construct_puzzle(ctx)?; - distributor.insert(Spend::new(action_puzzle, action_solution)); + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; Ok(add_incentives_announcement) } } @@ -108,7 +108,7 @@ impl RewardDistributorAddIncentivesActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorAddIncentivesActionSolution { pub amount: u64, #[clvm(rest)] diff --git a/src/layers/actions/reward_distributor/commit_incentives.rs b/src/layers/actions/reward_distributor/commit_incentives.rs index aac0f454..608c48c8 100644 --- a/src/layers/actions/reward_distributor/commit_incentives.rs +++ b/src/layers/actions/reward_distributor/commit_incentives.rs @@ -52,9 +52,7 @@ impl RewardDistributorCommitIncentivesAction { .map_err(DriverError::ToClvm) } - #[allow(clippy::type_complexity)] - pub fn get_slot_values_from_solution( - &self, + pub fn created_slot_values( ctx: &SpendContext, epoch_seconds: u64, solution: NodePtr, @@ -62,7 +60,6 @@ impl RewardDistributorCommitIncentivesAction { ( RewardDistributorCommitmentSlotValue, Vec, - (RewardDistributorSlotNonce, Bytes32), // spent slot ), DriverError, > { @@ -107,18 +104,20 @@ impl RewardDistributorCommitIncentivesAction { } } - let spent_slot = ( - RewardDistributorSlotNonce::REWARD, - RewardDistributorRewardSlotValue { - epoch_start: solution.slot_epoch_time, - next_epoch_initialized: solution.slot_next_epoch_initialized, - rewards: solution.slot_total_rewards, - } - .tree_hash() - .into(), - ); + Ok((commitment_slot_value, reward_slot_values)) + } - Ok((commitment_slot_value, reward_slot_values, spent_slot)) + pub fn spent_slot_value( + ctx: &SpendContext, + solution: NodePtr, + ) -> Result { + let solution = ctx.extract::(solution)?; + + Ok(RewardDistributorRewardSlotValue { + epoch_start: solution.slot_epoch_time, + next_epoch_initialized: solution.slot_next_epoch_initialized, + rewards: solution.slot_total_rewards, + }) } #[allow(clippy::type_complexity)] @@ -130,14 +129,9 @@ impl RewardDistributorCommitIncentivesAction { epoch_start: u64, clawback_ph: Bytes32, rewards_to_add: u64, - ) -> Result< - ( - Conditions, - Slot, - Vec>, - ), - DriverError, - > { + ) -> Result { + let reward_slot = distributor.actual_reward_slot_value(reward_slot); + let new_commitment_slot_value = RewardDistributorCommitmentSlotValue { epoch_start, clawback_ph, @@ -163,29 +157,13 @@ impl RewardDistributorCommitIncentivesAction { // spend reward slot reward_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; - let (_commitment_slot_value, reward_slot_values, _spent) = self - .get_slot_values_from_solution( - ctx, - distributor.info.constants.epoch_seconds, - action_solution, - )?; - distributor.insert(Spend::new(action_puzzle, action_solution)); - Ok(( + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; + Ok( Conditions::new().assert_puzzle_announcement(announcement_id( distributor.coin.puzzle_hash, commit_reward_announcement, )), - distributor - .created_slot_values_to_slots( - vec![new_commitment_slot_value], - RewardDistributorSlotNonce::COMMITMENT, - ) - .remove(0), - distributor.created_slot_values_to_slots( - reward_slot_values, - RewardDistributorSlotNonce::REWARD, - ), - )) + ) } } @@ -234,7 +212,7 @@ impl RewardDistributorCommitIncentivesActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorCommitIncentivesActionSolution { pub slot_epoch_time: u64, pub slot_next_epoch_initialized: bool, diff --git a/src/layers/actions/reward_distributor/initiate_payout.rs b/src/layers/actions/reward_distributor/initiate_payout.rs index b2a49d72..d7af0ca7 100644 --- a/src/layers/actions/reward_distributor/initiate_payout.rs +++ b/src/layers/actions/reward_distributor/initiate_payout.rs @@ -52,37 +52,31 @@ impl RewardDistributorInitiatePayoutAction { .map_err(DriverError::ToClvm) } - pub fn get_slot_value_from_solution( - &self, + pub fn created_slot_value( ctx: &SpendContext, - my_state: &RewardDistributorState, + current_state: &RewardDistributorState, solution: NodePtr, - ) -> Result< - ( - RewardDistributorEntrySlotValue, - (RewardDistributorSlotNonce, Bytes32), - ), - DriverError, - > { + ) -> Result { let solution = ctx.extract::(solution)?; - let new_slot = RewardDistributorEntrySlotValue { + Ok(RewardDistributorEntrySlotValue { payout_puzzle_hash: solution.entry_payout_puzzle_hash, - initial_cumulative_payout: my_state.round_reward_info.cumulative_payout, + initial_cumulative_payout: current_state.round_reward_info.cumulative_payout, shares: solution.entry_shares, - }; - let old_slot = RewardDistributorEntrySlotValue { + }) + } + + pub fn spent_slot_value( + ctx: &SpendContext, + solution: NodePtr, + ) -> Result { + let solution = ctx.extract::(solution)?; + + Ok(RewardDistributorEntrySlotValue { payout_puzzle_hash: solution.entry_payout_puzzle_hash, initial_cumulative_payout: solution.entry_initial_cumulative_payout, shares: solution.entry_shares, - }; - Ok(( - new_slot, - ( - RewardDistributorSlotNonce::ENTRY, - old_slot.tree_hash().into(), - ), - )) + }) } pub fn spend( @@ -90,8 +84,9 @@ impl RewardDistributorInitiatePayoutAction { ctx: &mut SpendContext, distributor: &mut RewardDistributor, entry_slot: Slot, - ) -> Result<(Conditions, Slot, u64), DriverError> { - let my_state = distributor.get_latest_pending_state(ctx)?; + ) -> Result<(Conditions, u64), DriverError> { + let my_state = distributor.pending_spend.latest_state.1; + let entry_slot = distributor.actual_entry_slot_value(entry_slot); let withdrawal_amount = entry_slot.info.value.shares * (my_state.round_reward_info.cumulative_payout @@ -117,18 +112,13 @@ impl RewardDistributorInitiatePayoutAction { // spend entry slot entry_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; - let slot_value = self - .get_slot_value_from_solution(ctx, &my_state, action_solution)? - .0; - distributor.insert(Spend::new(action_puzzle, action_solution)); + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; + Ok(( Conditions::new().assert_puzzle_announcement(announcement_id( distributor.coin.puzzle_hash, initiate_payout_announcement, )), - distributor - .created_slot_values_to_slots(vec![slot_value], RewardDistributorSlotNonce::ENTRY) - .remove(0), withdrawal_amount, )) } @@ -183,7 +173,7 @@ impl RewardDistributorInitiatePayoutActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorInitiatePayoutActionSolution { pub entry_payout_amount: u64, pub entry_payout_puzzle_hash: Bytes32, diff --git a/src/layers/actions/reward_distributor/new_epoch.rs b/src/layers/actions/reward_distributor/new_epoch.rs index a4aefe71..da16cc85 100644 --- a/src/layers/actions/reward_distributor/new_epoch.rs +++ b/src/layers/actions/reward_distributor/new_epoch.rs @@ -60,31 +60,30 @@ impl RewardDistributorNewEpochAction { .map_err(DriverError::ToClvm) } - pub fn get_slot_value_from_solution( - &self, + pub fn created_slot_value( ctx: &SpendContext, solution: NodePtr, - ) -> Result< - ( - RewardDistributorRewardSlotValue, - (RewardDistributorSlotNonce, Bytes32), - ), - DriverError, - > { + ) -> Result { let solution = ctx.extract::(solution)?; - let slot_valie = RewardDistributorRewardSlotValue { + Ok(RewardDistributorRewardSlotValue { epoch_start: solution.slot_epoch_time, next_epoch_initialized: solution.slot_next_epoch_initialized, rewards: solution.slot_total_rewards, - }; - Ok(( - slot_valie, - ( - RewardDistributorSlotNonce::REWARD, - slot_valie.tree_hash().into(), - ), - )) + }) + } + + pub fn spent_slot_value( + ctx: &SpendContext, + solution: NodePtr, + ) -> Result { + let solution = ctx.extract::(solution)?; + + Ok(RewardDistributorRewardSlotValue { + epoch_start: solution.slot_epoch_time, + next_epoch_initialized: solution.slot_next_epoch_initialized, + rewards: solution.slot_total_rewards, + }) } pub fn spend( @@ -92,9 +91,10 @@ impl RewardDistributorNewEpochAction { ctx: &mut SpendContext, distributor: &mut RewardDistributor, reward_slot: Slot, - ) -> Result<(Conditions, Slot, u64), DriverError> { + ) -> Result<(Conditions, u64), DriverError> { // also returns fee - let my_state = distributor.get_latest_pending_state(ctx)?; + let my_state = distributor.pending_spend.latest_state.1; + let reward_slot = distributor.actual_reward_slot_value(reward_slot); let epoch_total_rewards = if my_state.round_time_info.epoch_end == reward_slot.info.value.epoch_start { @@ -128,15 +128,8 @@ impl RewardDistributorNewEpochAction { // spend slot reward_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; - let slot_value = self.get_slot_value_from_solution(ctx, action_solution)?.0; - distributor.insert(Spend::new(action_puzzle, action_solution)); - Ok(( - new_epoch_conditions, - distributor - .created_slot_values_to_slots(vec![slot_value], RewardDistributorSlotNonce::REWARD) - .remove(0), - fee, - )) + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; + Ok((new_epoch_conditions, fee)) } } @@ -198,7 +191,7 @@ impl RewardDistributorNewEpochActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorNewEpochActionSolution { pub slot_epoch_time: u64, pub slot_next_epoch_initialized: bool, diff --git a/src/layers/actions/reward_distributor/remove_entry.rs b/src/layers/actions/reward_distributor/remove_entry.rs index 242cf84e..9ca84c72 100644 --- a/src/layers/actions/reward_distributor/remove_entry.rs +++ b/src/layers/actions/reward_distributor/remove_entry.rs @@ -66,6 +66,8 @@ impl RewardDistributorRemoveEntryAction { manager_singleton_inner_puzzle_hash: Bytes32, ) -> Result<(Conditions, u64), DriverError> { // u64 = last payment amount + let my_state = distributor.pending_spend.latest_state.1; + let entry_slot = distributor.actual_entry_slot_value(entry_slot); // compute message that the manager needs to send let remove_entry_message: Bytes32 = clvm_tuple!( @@ -86,7 +88,6 @@ impl RewardDistributorRemoveEntryAction { .assert_concurrent_puzzle(entry_slot.coin.puzzle_hash); // spend self - let my_state = distributor.get_latest_pending_state(ctx)?; let entry_payout_amount = entry_slot.info.value.shares * (my_state.round_reward_info.cumulative_payout - entry_slot.info.value.initial_cumulative_payout); @@ -102,27 +103,21 @@ impl RewardDistributorRemoveEntryAction { // spend entry slot entry_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; - distributor.insert(Spend::new(action_puzzle, action_solution)); + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; Ok((remove_entry_conditions, entry_payout_amount)) } - pub fn get_spent_slot_value_from_solution( - &self, + pub fn spent_slot_value( ctx: &SpendContext, solution: NodePtr, - ) -> Result<(RewardDistributorSlotNonce, Bytes32), DriverError> { + ) -> Result { let solution = ctx.extract::(solution)?; - Ok(( - RewardDistributorSlotNonce::ENTRY, - RewardDistributorEntrySlotValue { - payout_puzzle_hash: solution.entry_payout_puzzle_hash, - initial_cumulative_payout: solution.entry_initial_cumulative_payout, - shares: solution.entry_shares, - } - .tree_hash() - .into(), - )) + Ok(RewardDistributorEntrySlotValue { + payout_puzzle_hash: solution.entry_payout_puzzle_hash, + initial_cumulative_payout: solution.entry_initial_cumulative_payout, + shares: solution.entry_shares, + }) } } @@ -183,7 +178,7 @@ impl RewardDistributorRemoveEntryActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorRemoveEntryActionSolution { pub manager_singleton_inner_puzzle_hash: Bytes32, pub entry_payout_amount: u64, diff --git a/src/layers/actions/reward_distributor/stake.rs b/src/layers/actions/reward_distributor/stake.rs index 49daed79..dc0c2cff 100644 --- a/src/layers/actions/reward_distributor/stake.rs +++ b/src/layers/actions/reward_distributor/stake.rs @@ -10,7 +10,7 @@ use chia_puzzle_types::{ }; use chia_puzzles::{NFT_OWNERSHIP_LAYER_HASH, NFT_STATE_LAYER_HASH, SETTLEMENT_PAYMENT_HASH}; use chia_wallet_sdk::{ - driver::{DriverError, HashedPtr, Nft, Spend, SpendContext}, + driver::{Asset, DriverError, HashedPtr, Nft, Spend, SpendContext}, types::{announcement_id, Conditions}, }; use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; @@ -64,8 +64,7 @@ impl RewardDistributorStakeAction { .map_err(DriverError::ToClvm) } - pub fn get_slot_value_from_solution( - &self, + pub fn created_slot_value( ctx: &SpendContext, state: &RewardDistributorState, solution: NodePtr, @@ -86,16 +85,9 @@ impl RewardDistributorStakeAction { current_nft: Nft, nft_launcher_proof: NftLauncherProof, entry_custody_puzzle_hash: Bytes32, - ) -> Result< - ( - Conditions, - NotarizedPayment, - Slot, - Nft, - ), - DriverError, - > { - let ephemeral_counter = distributor.get_latest_pending_ephemeral_state(ctx)?; + ) -> Result<(Conditions, NotarizedPayment, Nft), DriverError> { + let ephemeral_counter = + ctx.extract::(distributor.pending_spend.latest_state.0)?; let my_id = distributor.coin.coin_id(); // calculate notarized payment @@ -111,19 +103,22 @@ impl RewardDistributorStakeAction { .tree_hash() .into(); let notarized_payment = NotarizedPayment { - nonce: clvm_tuple!(ephemeral_counter, my_id).tree_hash().into(), - payments: vec![Payment::with_memos( + nonce: clvm_tuple!(ephemeral_counter.tree_hash(), my_id) + .tree_hash() + .into(), + payments: vec![Payment::new( payment_puzzle_hash, 1, - vec![payment_puzzle_hash.into()], + ctx.hint(payment_puzzle_hash)?, )], }; // spend self - let nft = current_nft.wrapped_child( + let nft = current_nft.child( SETTLEMENT_PAYMENT_HASH.into(), None, current_nft.info.metadata, + current_nft.amount(), ); let action_solution = ctx.alloc(&RewardDistributorStakeActionSolution { my_id, @@ -136,7 +131,7 @@ impl RewardDistributorStakeAction { nft_transfer_porgram_hash: NftRoyaltyTransferPuzzleArgs::curry_tree_hash( nft.info.launcher_id, nft.info.royalty_puzzle_hash, - nft.info.royalty_ten_thousandths, + nft.info.royalty_basis_points, ) .into(), nft_launcher_proof, @@ -144,20 +139,15 @@ impl RewardDistributorStakeAction { })?; let action_puzzle = self.construct_puzzle(ctx)?; - let my_state = distributor.get_latest_pending_state(ctx)?; - let slot_value = self.get_slot_value_from_solution(ctx, &my_state, action_solution)?; - - let msg: Bytes32 = notarized_payment.tree_hash().into(); - distributor.insert(Spend::new(action_puzzle, action_solution)); + let notarized_payment_ptr = ctx.alloc(¬arized_payment)?; + let msg: Bytes32 = ctx.tree_hash(notarized_payment_ptr).into(); + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; Ok(( Conditions::new() .assert_puzzle_announcement(announcement_id(nft.coin.puzzle_hash, msg)), notarized_payment, - distributor - .created_slot_values_to_slots(vec![slot_value], RewardDistributorSlotNonce::ENTRY) - .remove(0), - nft.wrapped_child(payment_puzzle_hash, None, nft.info.metadata), + nft.child(payment_puzzle_hash, None, nft.info.metadata, nft.amount()), )) } } @@ -258,7 +248,7 @@ pub struct NftLauncherProof { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorStakeActionSolution { pub my_id: Bytes32, pub nft_metadata_hash: Bytes32, diff --git a/src/layers/actions/reward_distributor/sync.rs b/src/layers/actions/reward_distributor/sync.rs index f60c0ee7..29d65543 100644 --- a/src/layers/actions/reward_distributor/sync.rs +++ b/src/layers/actions/reward_distributor/sync.rs @@ -36,7 +36,7 @@ impl RewardDistributorSyncAction { update_time: u64, ) -> Result { // calculate announcement needed to ensure everything's happening as expected - let my_state = distributor.get_latest_pending_state(ctx)?; + let my_state = distributor.pending_spend.latest_state.1; let mut new_epoch_announcement: Vec = clvm_tuple!(update_time, my_state.round_time_info.epoch_end) .tree_hash() @@ -51,7 +51,7 @@ impl RewardDistributorSyncAction { let action_solution = ctx.alloc(&RewardDistributorSyncActionSolution { update_time })?; let action_puzzle = self.construct_puzzle(ctx)?; - distributor.insert(Spend::new(action_puzzle, action_solution)); + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; Ok(new_epoch_conditions) } } @@ -72,7 +72,7 @@ impl RewardDistributorSyncActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorSyncActionSolution { pub update_time: u64, } diff --git a/src/layers/actions/reward_distributor/unstake.rs b/src/layers/actions/reward_distributor/unstake.rs index 2675e9ce..89df0e6b 100644 --- a/src/layers/actions/reward_distributor/unstake.rs +++ b/src/layers/actions/reward_distributor/unstake.rs @@ -10,7 +10,6 @@ use chia_puzzles::{ }; use chia_wallet_sdk::{ driver::{DriverError, HashedPtr, Layer, Nft, Spend, SpendContext}, - prelude::Memos, types::Conditions, }; use clvm_traits::{clvm_quote, FromClvm, ToClvm}; @@ -58,23 +57,17 @@ impl RewardDistributorUnstakeAction { .map_err(DriverError::ToClvm) } - pub fn get_spent_slot_value_from_solution( - &self, + pub fn spent_slot_value( ctx: &SpendContext, solution: NodePtr, - ) -> Result<(RewardDistributorSlotNonce, Bytes32), DriverError> { + ) -> Result { let solution = ctx.extract::(solution)?; - Ok(( - RewardDistributorSlotNonce::ENTRY, - RewardDistributorEntrySlotValue { - payout_puzzle_hash: solution.entry_custody_puzzle_hash, - initial_cumulative_payout: solution.entry_initial_cumulative_payout, - shares: 1, - } - .tree_hash() - .into(), - )) + Ok(RewardDistributorEntrySlotValue { + payout_puzzle_hash: solution.entry_custody_puzzle_hash, + initial_cumulative_payout: solution.entry_initial_cumulative_payout, + shares: 1, + }) } pub fn spend( @@ -85,6 +78,8 @@ impl RewardDistributorUnstakeAction { locked_nft: Nft, ) -> Result<(Conditions, u64), DriverError> { // u64 = last payment amount + let my_state = distributor.pending_spend.latest_state.1; + let entry_slot = distributor.actual_entry_slot_value(entry_slot); // compute message that the custody puzzle needs to send let unstake_message: Bytes32 = locked_nft.info.launcher_id; @@ -99,7 +94,6 @@ impl RewardDistributorUnstakeAction { .assert_concurrent_puzzle(entry_slot.coin.puzzle_hash); // spend self - let my_state = distributor.get_latest_pending_state(ctx)?; let entry_payout_amount = entry_slot.info.value.shares * (my_state.round_reward_info.cumulative_payout - entry_slot.info.value.initial_cumulative_payout); @@ -115,7 +109,7 @@ impl RewardDistributorUnstakeAction { nft_transfer_porgram_hash: NftRoyaltyTransferPuzzleArgs::curry_tree_hash( locked_nft.info.launcher_id, locked_nft.info.royalty_puzzle_hash, - locked_nft.info.royalty_ten_thousandths, + locked_nft.info.royalty_basis_points, ) .into(), entry_initial_cumulative_payout: entry_slot.info.value.initial_cumulative_payout, @@ -124,7 +118,7 @@ impl RewardDistributorUnstakeAction { let action_puzzle = self.construct_puzzle(ctx)?; let registry_inner_puzzle_hash = distributor.info.inner_puzzle_hash(); - distributor.insert(Spend::new(action_puzzle, action_solution)); + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; // spend NFT let my_p2 = P2DelegatedBySingletonLayer::new( @@ -143,11 +137,11 @@ impl RewardDistributorUnstakeAction { .to_clvm(ctx) .map_err(DriverError::ToClvm)?; - let hint = Memos::hint(ctx, entry_slot.info.value.payout_puzzle_hash)?; + let hint = ctx.hint(entry_slot.info.value.payout_puzzle_hash)?; let delegated_puzzle = ctx.alloc(&clvm_quote!(Conditions::new().create_coin( entry_slot.info.value.payout_puzzle_hash, 1, - Some(hint), + hint, )))?; let nft_inner_solution = my_p2.construct_solution( ctx, @@ -158,7 +152,7 @@ impl RewardDistributorUnstakeAction { }, )?; - locked_nft.spend(ctx, Spend::new(nft_inner_puzzle, nft_inner_solution))?; + let _new_nft = locked_nft.spend(ctx, Spend::new(nft_inner_puzzle, nft_inner_solution))?; // spend entry slot entry_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; @@ -226,7 +220,7 @@ impl RewardDistributorUnstakeActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorUnstakeActionSolution { pub nft_launcher_id: Bytes32, pub nft_parent_id: Bytes32, diff --git a/src/layers/actions/reward_distributor/withdraw_incentives.rs b/src/layers/actions/reward_distributor/withdraw_incentives.rs index 0da587e3..349a85c6 100644 --- a/src/layers/actions/reward_distributor/withdraw_incentives.rs +++ b/src/layers/actions/reward_distributor/withdraw_incentives.rs @@ -52,51 +52,49 @@ impl RewardDistributorWithdrawIncentivesAction { .map_err(DriverError::ToClvm) } - pub fn get_slot_value_from_solution( - &self, + pub fn created_slot_value( + ctx: &SpendContext, + withdrawal_share_bps: u64, + solution: NodePtr, + ) -> Result { + let solution = + ctx.extract::(solution)?; + let withdrawal_share = solution.committed_value * withdrawal_share_bps / 10000; + + let new_reward_slot_value = RewardDistributorRewardSlotValue { + epoch_start: solution.reward_slot_epoch_time, + next_epoch_initialized: solution.reward_slot_next_epoch_initialized, + rewards: solution.reward_slot_total_rewards - withdrawal_share, + }; + + Ok(new_reward_slot_value) + } + + pub fn spent_slot_values( ctx: &SpendContext, - my_constants: &RewardDistributorConstants, solution: NodePtr, ) -> Result< ( RewardDistributorRewardSlotValue, - [(RewardDistributorSlotNonce, Bytes32); 2], + RewardDistributorCommitmentSlotValue, ), DriverError, > { let solution = ctx.extract::(solution)?; - let withdrawal_share = solution.committed_value * my_constants.withdrawal_share_bps / 10000; let old_reward_slot_value = RewardDistributorRewardSlotValue { epoch_start: solution.reward_slot_epoch_time, next_epoch_initialized: solution.reward_slot_next_epoch_initialized, rewards: solution.reward_slot_total_rewards, }; - let new_reward_slot_value = RewardDistributorRewardSlotValue { - epoch_start: solution.reward_slot_epoch_time, - next_epoch_initialized: solution.reward_slot_next_epoch_initialized, - rewards: solution.reward_slot_total_rewards - withdrawal_share, - }; let commitment_slot_value = RewardDistributorCommitmentSlotValue { epoch_start: solution.reward_slot_epoch_time, clawback_ph: solution.clawback_ph, rewards: solution.committed_value, }; - Ok(( - new_reward_slot_value, - [ - ( - RewardDistributorSlotNonce::REWARD, - old_reward_slot_value.tree_hash().into(), - ), - ( - RewardDistributorSlotNonce::COMMITMENT, - commitment_slot_value.tree_hash().into(), - ), - ], - )) + Ok((old_reward_slot_value, commitment_slot_value)) } pub fn spend( @@ -105,8 +103,10 @@ impl RewardDistributorWithdrawIncentivesAction { distributor: &mut RewardDistributor, commitment_slot: Slot, reward_slot: Slot, - ) -> Result<(Conditions, Slot, u64), DriverError> { + ) -> Result<(Conditions, u64), DriverError> { // last u64 = withdrawn amount + let commitment_slot = distributor.actual_commitment_slot_value(commitment_slot); + let reward_slot = distributor.actual_reward_slot_value(reward_slot); let withdrawal_share = commitment_slot.info.value.rewards * distributor.info.constants.withdrawal_share_bps / 10000; @@ -131,23 +131,14 @@ impl RewardDistributorWithdrawIncentivesAction { })?; let action_puzzle = self.construct_puzzle(ctx)?; - let slot_value = self - .get_slot_value_from_solution(ctx, &distributor.info.constants, action_solution)? - .0; - distributor.insert(Spend::new(action_puzzle, action_solution)); + distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; // spend slots let my_inner_puzzle_hash: Bytes32 = distributor.info.inner_puzzle_hash().into(); reward_slot.spend(ctx, my_inner_puzzle_hash)?; commitment_slot.spend(ctx, my_inner_puzzle_hash)?; - Ok(( - withdraw_incentives_conditions, - distributor - .created_slot_values_to_slots(vec![slot_value], RewardDistributorSlotNonce::REWARD) - .remove(0), - withdrawal_share, - )) + Ok((withdraw_incentives_conditions, withdrawal_share)) } } @@ -199,7 +190,7 @@ impl RewardDistributorWithdrawIncentivesActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct RewardDistributorWithdrawIncentivesActionSolution { pub reward_slot_epoch_time: u64, pub reward_slot_next_epoch_initialized: bool, diff --git a/src/layers/actions/xchandles/expire.rs b/src/layers/actions/xchandles/expire.rs index 0b124a74..69c1572b 100644 --- a/src/layers/actions/xchandles/expire.rs +++ b/src/layers/actions/xchandles/expire.rs @@ -17,7 +17,7 @@ use crate::{ XchandlesRegistry, XchandlesSlotValue, }; -use super::{XchandlesFactorPricingPuzzleArgs, XchandlesFactorPricingSolution}; +use super::{XchandlesFactorPricingPuzzleArgs, XchandlesPricingSolution}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct XchandlesExpireAction { @@ -59,7 +59,7 @@ impl XchandlesExpireAction { .to_clvm(ctx)?) } - pub fn get_spent_slot_value_from_solution( + pub fn spent_slot_value( ctx: &SpendContext, solution: NodePtr, ) -> Result { @@ -85,7 +85,7 @@ impl XchandlesExpireAction { )) } - pub fn get_created_slot_value_from_solution( + pub fn created_slot_value( ctx: &mut SpendContext, solution: NodePtr, ) -> Result { @@ -128,7 +128,8 @@ impl XchandlesExpireAction { base_handle_price: u64, registration_period: u64, precommit_coin: PrecommitCoin, - ) -> Result<(Conditions, Slot), DriverError> { + start_time: u64, + ) -> Result { let my_inner_puzzle_hash: Bytes32 = registry.info.inner_puzzle_hash().into(); // announcement is simply premcommitment coin ph @@ -142,6 +143,7 @@ impl XchandlesExpireAction { )?; // spend self + let slot = registry.actual_slot(slot); let action_solution = XchandlesExpireActionSolution { cat_maker_puzzle_reveal: DefaultCatMakerArgs::get_puzzle( ctx, @@ -156,15 +158,12 @@ impl XchandlesExpireAction { 1000, )? .get_puzzle(ctx)?, - expired_handle_pricing_puzzle_solution: - XchandlesExponentialPremiumRenewPuzzleSolution:: { - buy_time: precommit_coin.value.start_time, - pricing_program_solution: XchandlesFactorPricingSolution { - current_expiration: slot.info.value.expiration, - handle: precommit_coin.value.handle.clone(), - num_periods, - }, - }, + expired_handle_pricing_puzzle_solution: XchandlesPricingSolution { + buy_time: start_time, + current_expiration: slot.info.value.expiration, + handle: precommit_coin.value.handle.clone(), + num_periods, + }, refund_puzzle_hash_hash: precommit_coin.refund_puzzle_hash.tree_hash().into(), secret: precommit_coin.value.secret, neighbors: slot.info.value.neighbors, @@ -177,38 +176,24 @@ impl XchandlesExpireAction { .to_clvm(ctx)?; let action_puzzle = self.construct_puzzle(ctx)?; - registry.insert(Spend::new(action_puzzle, action_solution)); - let new_slot_value = Self::get_created_slot_value_from_solution(ctx, action_solution)?; - registry - .pending_items - .created_slots - .push(new_slot_value.clone()); + registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; // spend slot - registry - .pending_items - .spent_slots - .push(slot.info.value.clone()); slot.spend(ctx, my_inner_puzzle_hash)?; let mut expire_ann: Vec = expire_ann.to_vec(); expire_ann.insert(0, b'x'); - Ok(( - Conditions::new() - .assert_puzzle_announcement(announcement_id(registry.coin.puzzle_hash, expire_ann)), - registry - .created_slot_values_to_slots(vec![new_slot_value.clone()]) - .remove(0), - )) + Ok(Conditions::new() + .assert_puzzle_announcement(announcement_id(registry.coin.puzzle_hash, expire_ann))) } } -pub const XCHANDLES_EXPIRE_PUZZLE: [u8; 1081] = - hex!("ff02ffff01ff02ffff03ffff22ffff09ffff02ff16ffff04ff02ffff04ff4fff80808080ff5780ffff09ffff02ff16ffff04ff02ffff04ff82016fff80808080ff81f780ffff09ffff0dff827fef80ffff012080ffff15ffff0141ffff0dff827fef808080ffff01ff04ff17ffff02ff2effff04ff02ffff04ffff02ff4fffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff8205ef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff16ffff04ff02ffff04ffff04ffff04ffff04ff57ff81af80ffff04ff81f7ff8202ef8080ffff04ffff04ff8216efff820bef80ffff04ff8204efffff04ff825fefff827fef80808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff81af8080ffff04ffff05ffff02ff82016fff8202ef8080ffff04ffff04ffff04ff10ffff04ff8204efff808080ffff04ffff04ff10ffff04ff820aefff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ff820aefff822fef8080ff80808080ff8080808080ffff04ffff02ff1affff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ffff10ffff06ffff02ff82016fff8202ef8080ff8204ef80ff823fef8080ff80808080ff8080808080ff8080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ffff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0178ff0580ff808080ff178080ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080"); +pub const XCHANDLES_EXPIRE_PUZZLE: [u8; 1073] = + hex!("ff02ffff01ff02ffff03ffff22ffff09ffff02ff16ffff04ff02ffff04ff4fff80808080ff5780ffff09ffff02ff16ffff04ff02ffff04ff82016fff80808080ff81f780ffff09ffff0dff825fef80ffff012080ffff15ffff0141ffff0dff827fef808080ffff01ff04ff17ffff02ff2effff04ff02ffff04ffff02ff4fffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff8205ef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff16ffff04ff02ffff04ffff04ffff04ffff04ff57ff81af80ffff04ff81f7ff8202ef8080ffff04ffff04ff8216efff820bef80ffff04ff825fefff827fef808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff81af8080ffff04ffff05ffff02ff82016fff8202ef8080ffff04ffff04ffff04ff10ffff04ff8204efff808080ffff04ffff04ff10ffff04ff820aefff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ff820aefff822fef8080ff80808080ff8080808080ffff04ffff02ff1affff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ffff10ffff06ffff02ff82016fff8202ef8080ff8204ef80ff823fef8080ff80808080ff8080808080ff8080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ffff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0178ff0580ff808080ff178080ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080"); pub const XCHANDLES_EXPIRE_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( " - f17bc6e5a0503ce269c6ea2c9c51d74d34531638cc61349e6b1cfa104098001d + 514d248262b0b1607f305a26bf315f6ecb7d7705bfcf5856f12a9a22344af728 " )); @@ -256,7 +241,7 @@ impl XchandlesExpireActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct XchandlesExpireActionSolution { pub cat_maker_puzzle_reveal: CMP, pub cat_maker_puzzle_solution: CMS, @@ -270,12 +255,12 @@ pub struct XchandlesExpireActionSolution { pub new_rest: XchandlesDataValue, } -pub const XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE: [u8; 351] = - hex!("ff02ffff01ff04ffff10ffff05ffff02ff05ffff04ff8202ffff8203ff808080ffff02ff06ffff04ff02ffff04ffff02ff04ffff04ff02ffff04ff5fffff04ff81bfffff04ffff0101ffff04ffff05ffff14ffff12ffff0183010000ffff3dffff11ff82017fff8202ff80ff0b8080ff0b8080ffff04ffff05ffff14ff17ffff17ffff0101ffff05ffff14ffff11ff82017fff8202ff80ff0b8080808080ff8080808080808080ffff04ff2fff808080808080ffff06ffff02ff05ffff04ff8202ffff8203ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ff04ffff04ff02ffff04ff05ffff04ff1bffff04ffff17ff17ffff010180ffff04ff2fffff04ffff02ffff03ffff18ff2fff1780ffff01ff05ffff14ffff12ff5fff1380ff058080ffff015f80ff0180ff8080808080808080ffff015f80ff0180ff02ffff03ffff15ff05ff0b80ffff01ff11ff05ff0b80ff8080ff0180ff018080"); +pub const XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE: [u8; 333] = + hex!("ff02ffff01ff04ffff10ffff05ffff02ff05ff81ff8080ffff02ff06ffff04ff02ffff04ffff02ff04ffff04ff02ffff04ff5fffff04ff81bfffff04ffff0101ffff04ffff05ffff14ffff12ffff0183010000ffff3dffff11ff82017fff8202ff80ff0b8080ff0b8080ffff04ffff05ffff14ff17ffff17ffff0101ffff05ffff14ffff11ff82017fff8202ff80ff0b8080808080ff8080808080808080ffff04ff2fff808080808080ffff06ffff02ff05ff81ff808080ffff04ffff01ffff02ffff03ff0bffff01ff02ff04ffff04ff02ffff04ff05ffff04ff1bffff04ffff17ff17ffff010180ffff04ff2fffff04ffff02ffff03ffff18ff2fff1780ffff01ff05ffff14ffff12ff5fff1380ff058080ffff015f80ff0180ff8080808080808080ffff015f80ff0180ff02ffff03ffff15ff05ff0b80ffff01ff11ff05ff0b80ff8080ff0180ff018080"); pub const XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( " - 1e690af48fe029e072638c4952929d3d17795592d59b6cc8c18ddf5921f50285 + b54c0f4b73e63e78470366bd4006ca629d94f36c8ea58abacf8cc1cbb7724907 " )); @@ -384,15 +369,11 @@ impl XchandlesExponentialPremiumRenewPuzzleArgs { num_periods: u64, ) -> Result { let puzzle = self.get_puzzle(ctx)?; - let solution = ctx.alloc(&XchandlesExponentialPremiumRenewPuzzleSolution::< - XchandlesFactorPricingSolution, - > { + let solution = ctx.alloc(&XchandlesPricingSolution { buy_time, - pricing_program_solution: XchandlesFactorPricingSolution { - current_expiration: expiration, - handle, - num_periods, - }, + current_expiration: expiration, + handle, + num_periods, })?; let output = ctx.run(puzzle, solution)?; @@ -400,14 +381,6 @@ impl XchandlesExponentialPremiumRenewPuzzleArgs { } } -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] -pub struct XchandlesExponentialPremiumRenewPuzzleSolution { - pub buy_time: u64, - #[clvm(rest)] - pub pricing_program_solution: S, -} - #[cfg(test)] mod tests { use super::*; @@ -437,15 +410,11 @@ mod tests { for day in 0..28 { for hour in 0..24 { let buy_time = day * 24 * 60 * 60 + hour * 60 * 60; - let solution = ctx.alloc(&XchandlesExponentialPremiumRenewPuzzleSolution::< - XchandlesFactorPricingSolution, - > { + let solution = ctx.alloc(&XchandlesPricingSolution { buy_time, - pricing_program_solution: XchandlesFactorPricingSolution { - current_expiration: 0, - handle: "yakuhito".to_string(), - num_periods: 1, - }, + current_expiration: 0, + handle: "yakuhito".to_string(), + num_periods: 1, })?; let output = ctx.run(puzzle, solution)?; @@ -485,15 +454,11 @@ mod tests { } // check premium after auction is 0 - let solution = ctx.alloc(&XchandlesExponentialPremiumRenewPuzzleSolution::< - XchandlesFactorPricingSolution, - > { + let solution = ctx.alloc(&XchandlesPricingSolution { buy_time: 28 * 24 * 60 * 60, - pricing_program_solution: XchandlesFactorPricingSolution { - current_expiration: 0, - handle: "yakuhito".to_string(), - num_periods: 1, - }, + current_expiration: 0, + handle: "yakuhito".to_string(), + num_periods: 1, })?; let output = ctx.run(puzzle, solution)?; diff --git a/src/layers/actions/xchandles/extend.rs b/src/layers/actions/xchandles/extend.rs index ba418d73..6d13683c 100644 --- a/src/layers/actions/xchandles/extend.rs +++ b/src/layers/actions/xchandles/extend.rs @@ -17,7 +17,7 @@ use crate::{ XchandlesDataValue, XchandlesRegistry, XchandlesSlotValue, }; -use super::{XchandlesFactorPricingPuzzleArgs, XchandlesFactorPricingSolution}; +use super::{XchandlesFactorPricingPuzzleArgs, XchandlesPricingSolution}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct XchandlesExtendAction { @@ -49,22 +49,22 @@ impl XchandlesExtendAction { .to_clvm(ctx)?) } - pub fn get_spent_slot_value_from_solution( + pub fn spent_slot_value( ctx: &mut SpendContext, solution: NodePtr, ) -> Result { let solution = ctx.extract::>(solution)?; - // current expiration is the first truth given to a pricing puzzle - let current_expiration = solution.pricing_solution.0; + // current expiration is the second truth given to a pricing puzzle + let current_expiration = solution.pricing_solution.1 .0; Ok(XchandlesSlotValue::new( - solution.pricing_solution.1 .0.tree_hash().into(), + solution.pricing_solution.1 .1 .0.tree_hash().into(), solution.neighbors.left_value, solution.neighbors.right_value, current_expiration, @@ -73,7 +73,7 @@ impl XchandlesExtendAction { )) } - pub fn get_created_slot_value_from_solution( + pub fn created_slot_value( ctx: &mut SpendContext, solution: NodePtr, ) -> Result { @@ -85,11 +85,14 @@ impl XchandlesExtendAction { let pricing_output = ctx.run(solution.pricing_puzzle_reveal, solution.pricing_solution)?; let registration_time_delta = <(NodePtr, u64)>::from_clvm(ctx, pricing_output)?.1; - let (_, (handle, _)) = - ctx.extract::<(NodePtr, (String, NodePtr))>(solution.pricing_solution)?; + let (_, (_, (handle, _))) = + ctx.extract::<(NodePtr, (NodePtr, (String, NodePtr)))>(solution.pricing_solution)?; - // current expiration is the first truth given to a pricing puzzle - let current_expiration = ctx.extract::<(u64, NodePtr)>(solution.pricing_solution)?.0; + // current expiration is the second truth given to a pricing puzzle + let current_expiration = ctx + .extract::<(NodePtr, (u64, NodePtr))>(solution.pricing_solution)? + .1 + .0; Ok(XchandlesSlotValue::new( handle.tree_hash().into(), @@ -112,7 +115,8 @@ impl XchandlesExtendAction { base_handle_price: u64, registration_period: u64, num_periods: u64, - ) -> Result<(NotarizedPayment, Conditions, Slot), DriverError> { + buy_time: u64, + ) -> Result<(Conditions, NotarizedPayment), DriverError> { let spender_inner_puzzle_hash: Bytes32 = registry.info.inner_puzzle_hash().into(); // spend self @@ -123,9 +127,12 @@ impl XchandlesExtendAction { base_handle_price, registration_period, )?; + + let slot = registry.actual_slot(slot); let action_solution = ctx.alloc(&XchandlesExtendActionSolution { pricing_puzzle_reveal, - pricing_solution: XchandlesFactorPricingSolution { + pricing_solution: XchandlesPricingSolution { + buy_time, current_expiration: slot.info.value.expiration, handle: handle.clone(), num_periods, @@ -137,7 +144,7 @@ impl XchandlesExtendAction { })?; let action_puzzle = self.construct_puzzle(ctx)?; - registry.insert(Spend::new(action_puzzle, action_solution)); + registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; let renew_amount = XchandlesFactorPricingPuzzleArgs::get_price(base_handle_price, &handle, num_periods); @@ -146,45 +153,32 @@ impl XchandlesExtendAction { nonce: clvm_tuple!(handle.clone(), slot.info.value.expiration) .tree_hash() .into(), - payments: vec![Payment::with_memos( + payments: vec![Payment::new( registry.info.constants.precommit_payout_puzzle_hash, renew_amount, - vec![registry.info.constants.precommit_payout_puzzle_hash.into()], + ctx.hint(registry.info.constants.precommit_payout_puzzle_hash)?, )], }; // spend slot - registry - .pending_items - .spent_slots - .push(slot.info.value.clone()); slot.spend(ctx, spender_inner_puzzle_hash)?; let mut extend_ann: Vec = clvm_tuple!(renew_amount, handle).tree_hash().to_vec(); extend_ann.insert(0, b'e'); - let new_slot_value = Self::get_created_slot_value_from_solution(ctx, action_solution)?; - registry - .pending_items - .created_slots - .push(new_slot_value.clone()); - Ok(( - notarized_payment, Conditions::new() .assert_puzzle_announcement(announcement_id(registry.coin.puzzle_hash, extend_ann)), - registry - .created_slot_values_to_slots(vec![new_slot_value]) - .remove(0), + notarized_payment, )) } } -pub const XCHANDLES_EXTEND_PUZZLE: [u8; 928] = hex!("ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff8202dfff8080808080ffff09ff82016fffff02ff2effff04ff02ffff04ff819fff808080808080ffff01ff04ff2fffff04ffff02ff3effff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff82055f80ff820bdf80ffff04ff82025fff820fdf8080ff80808080ff8080808080ffff04ffff04ff2cffff04ffff0effff0165ffff02ff2effff04ff02ffff04ffff04ffff05ffff02ff819fff82015f8080ff82055f80ff8080808080ff808080ffff04ffff04ff10ffff04ff82025fff808080ffff04ffff02ff16ffff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff82055f80ff820bdf80ffff04ffff10ff82025fffff06ffff02ff819fff82015f808080ff820fdf8080ff80808080ff8080808080ffff04ffff04ff18ffff04ffff0bffff02ff8202dfffff04ff05ff8205df8080ffff02ff2effff04ff02ffff04ffff04ffff02ff2effff04ff02ffff04ffff04ff82055fff82025f80ff80808080ffff04ffff04ff0bffff04ffff05ffff02ff819fff82015f8080ffff04ffff04ff0bff8080ff80808080ff808080ff8080808080ff808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff553fff33ff3e42ffff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff14ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff3cffff04ffff0112ffff04ff80ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ff8080808080ff018080"); +pub const XCHANDLES_EXTEND_PUZZLE: [u8; 964] = hex!("ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff8202dfff8080808080ffff09ff82016fffff02ff2effff04ff02ffff04ff819fff808080808080ffff01ff04ff2fffff04ffff02ff3effff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff820b5f80ff820bdf80ffff04ff82055fff820fdf8080ff80808080ff8080808080ffff04ffff04ff3cffff04ffff0effff0165ffff02ff2effff04ff02ffff04ffff04ffff05ffff02ff819fff82015f8080ff820b5f80ff8080808080ff808080ffff04ffff04ff10ffff04ff82055fff808080ffff04ffff04ff14ffff04ff82025fff808080ffff04ffff02ff16ffff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff820b5f80ff820bdf80ffff04ffff10ff82055fffff06ffff02ff819fff82015f808080ff820fdf8080ff80808080ff8080808080ffff04ffff04ff18ffff04ffff0bffff02ff8202dfffff04ff05ff8205df8080ffff02ff2effff04ff02ffff04ffff04ffff02ff2effff04ff02ffff04ffff04ff820b5fff82055f80ff80808080ffff04ffff04ff0bffff04ffff05ffff02ff819fff82015f8080ffff04ffff04ff0bff8080ff80808080ff808080ff8080808080ff808080ff8080808080808080ffff01ff088080ff0180ffff04ffff01ffffff553fff51ff333effff42ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff2cffff04ffff0bff81baffff0bff2affff0bff2aff81daff0580ffff0bff2affff0bff81faffff0bff2affff0bff2aff81daffff0bffff0101ff0b8080ffff0bff2aff81daff819a808080ff819a808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff12ffff04ffff0112ffff04ff80ffff04ffff0bff81baffff0bff2affff0bff2aff81daff0580ffff0bff2affff0bff81faffff0bff2affff0bff2aff81daffff0bffff0101ff0b8080ffff0bff2aff81daff819a808080ff819a808080ff8080808080ff018080"); pub const XCHANDLES_EXTEND_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( " - 16682d7841b1e3d77a6202b70ed75c5bc9d923aa6ac045d71aa489f0d7886584 + caa665c939f3de5d90dd22b00d092ba7c794300bf994b9ddcea536fa77843e08 " )); @@ -217,7 +211,7 @@ impl XchandlesExtendActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct XchandlesExtendActionSolution { pub pricing_puzzle_reveal: PP, pub pricing_solution: PS, diff --git a/src/layers/actions/xchandles/oracle.rs b/src/layers/actions/xchandles/oracle.rs index 094dcbd0..b63fb11e 100644 --- a/src/layers/actions/xchandles/oracle.rs +++ b/src/layers/actions/xchandles/oracle.rs @@ -42,7 +42,7 @@ impl XchandlesOracleAction { .to_clvm(ctx)?) } - pub fn get_spent_slot_value_from_solution( + pub fn spent_slot_value( ctx: &SpendContext, solution: NodePtr, ) -> Result { @@ -51,7 +51,7 @@ impl XchandlesOracleAction { Ok(slot_value) } - pub fn get_created_slot_value(spent_slot_value: XchandlesSlotValue) -> XchandlesSlotValue { + pub fn created_slot_value(spent_slot_value: XchandlesSlotValue) -> XchandlesSlotValue { spent_slot_value } @@ -60,32 +60,23 @@ impl XchandlesOracleAction { ctx: &mut SpendContext, registry: &mut XchandlesRegistry, slot: Slot, - ) -> Result<(Conditions, Slot), DriverError> { + ) -> Result { // spend self + let slot = registry.actual_slot(slot); let action_solution = ctx.alloc(&slot.info.value)?; let action_puzzle = self.construct_puzzle(ctx)?; - registry.insert(Spend::new(action_puzzle, action_solution)); + registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - let new_slot = Self::get_created_slot_value(slot.info.value.clone()); - registry.pending_items.created_slots.push(new_slot.clone()); + let new_slot = Self::created_slot_value(slot.info.value.clone()); // spend slot - registry - .pending_items - .spent_slots - .push(slot.info.value.clone()); slot.spend(ctx, registry.info.inner_puzzle_hash().into())?; let mut oracle_ann = new_slot.tree_hash().to_vec(); oracle_ann.insert(0, b'o'); - Ok(( - Conditions::new() - .assert_puzzle_announcement(announcement_id(registry.coin.puzzle_hash, oracle_ann)), - registry - .created_slot_values_to_slots(vec![new_slot.clone()]) - .remove(0), - )) + Ok(Conditions::new() + .assert_puzzle_announcement(announcement_id(registry.coin.puzzle_hash, oracle_ann))) } } diff --git a/src/layers/actions/xchandles/refund.rs b/src/layers/actions/xchandles/refund.rs index 6c85bc75..00e34a7e 100644 --- a/src/layers/actions/xchandles/refund.rs +++ b/src/layers/actions/xchandles/refund.rs @@ -56,7 +56,7 @@ impl XchandlesRefundAction { .to_clvm(ctx)?) } - pub fn get_spent_slot_value_from_solution( + pub fn spent_slot_value( ctx: &SpendContext, solution: NodePtr, ) -> Result, DriverError> { @@ -68,7 +68,7 @@ impl XchandlesRefundAction { Ok(solution.slot_value) } - pub fn get_created_slot_value( + pub fn created_slot_value( spent_slot_value: Option, ) -> Option { spent_slot_value // nothing changed; just oracle @@ -82,7 +82,7 @@ impl XchandlesRefundAction { precommited_pricing_puzzle_reveal: NodePtr, precommited_pricing_puzzle_solution: NodePtr, slot: Option>, - ) -> Result<(Conditions, Option>), DriverError> { + ) -> Result { // calculate announcement let mut refund_announcement: Vec = precommit_coin.coin.puzzle_hash.to_vec(); refund_announcement.insert(0, b'$'); @@ -96,6 +96,7 @@ impl XchandlesRefundAction { )?; // spend self + let slot = slot.map(|s| registry.actual_slot(s)); let action_solution = XchandlesRefundActionSolution { precommited_cat_maker_reveal: DefaultCatMakerArgs::get_puzzle( ctx, @@ -113,7 +114,6 @@ impl XchandlesRefundAction { precommited_pricing_puzzle_solution, handle: precommit_coin.value.handle.clone(), secret: precommit_coin.value.secret, - precommited_start_time: precommit_coin.value.start_time, precommited_owner_launcher_id: precommit_coin.value.owner_launcher_id, precommited_resolved_data: precommit_coin.value.resolved_data.clone(), refund_puzzle_hash_hash: precommit_coin.refund_puzzle_hash.tree_hash().into(), @@ -123,50 +123,28 @@ impl XchandlesRefundAction { .to_clvm(ctx)?; let action_puzzle = self.construct_puzzle(ctx)?; - registry.insert(Spend::new(action_puzzle, action_solution)); - - let new_slot_value = if let Some(slot) = &slot { - let slot_value = slot.info.value.clone(); - - registry - .pending_items - .created_slots - .push(slot_value.clone()); - - Some( - registry - .created_slot_values_to_slots(vec![slot_value.clone()]) - .remove(0), - ) - } else { - None - }; + registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; // if there's a slot, spend it if let Some(slot) = slot { - registry - .pending_items - .spent_slots - .push(slot.info.value.clone()); slot.spend(ctx, my_inner_puzzle_hash)?; } - Ok(( + Ok( Conditions::new().assert_puzzle_announcement(announcement_id( registry.coin.puzzle_hash, refund_announcement, )), - new_slot_value, - )) + ) } } -pub const XCHANDLES_REFUND_PUZZLE: [u8; 1081] = - hex!("ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff4fff8080808080ffff09ff8205efffff02ff2effff04ff02ffff04ff8202efff8080808080ffff02ffff03ff8307ffefffff01ff09ff8313ffefffff0bffff0101ff8217ef8080ffff01ff010180ff018080ffff01ff04ff17ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ff8307ffefff80808080ffff04ffff22ffff09ff81afff5780ffff02ffff03ffff09ff8205efff81b780ffff01ff09ff8217efff822bef80ffff01ff02ffff03ffff09ff8205efff81f780ffff01ff09ff8217efff825bef80ff8080ff018080ff0180ffff09ff8305ffefffff05ffff02ff8202efff820bef80808080ffff04ffff02ff4fffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ff8302ffef80ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff81afff82016f80ffff04ff8205efff820bef8080ffff04ffff04ff8217efff822fef80ffff04ff825fefffff04ff82bfefff83017fef80808080ff808080808080ffff0bff1cff62ff42808080ff42808080ff42808080ff82016f8080ffff04ff8305ffefff808080808080808080ffff01ff088080ff0180ffff04ffff01ffffff333eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff10ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff04ffff04ff14ffff04ffff0113ffff04ff80ffff04ff2fffff04ff5fff808080808080ffff04ffff04ff18ffff04ffff0effff0124ff2f80ff808080ffff02ffff03ff17ffff01ff04ffff02ff3effff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ff0bff8080808080ff808080ff8080ff01808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ff8080808080ff018080"); +pub const XCHANDLES_REFUND_PUZZLE: [u8; 1036] = + hex!("ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff4fff8080808080ffff09ff8205efffff02ff2effff04ff02ffff04ff8202efff8080808080ffff02ffff03ff8303ffefffff01ff09ff8309ffefffff0bffff0101ff8217ef8080ffff01ff010180ff018080ffff01ff04ff17ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ff8303ffefff80808080ffff04ffff22ffff09ff81afff5780ffff09ff8217efff825bef80ffff21ffff09ff8205efff81b780ffff09ff8205efff81f78080ffff09ff8302ffefffff05ffff02ff8202efff820bef80808080ffff04ffff02ff4fffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ff83017fef80ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff81afff82016f80ffff04ff8205efff820bef8080ffff04ffff04ff8217efff822fef80ffff04ff825fefff82bfef808080ff808080808080ffff0bff1cff62ff42808080ff42808080ff42808080ff82016f8080ffff04ff8302ffefff808080808080808080ffff01ff088080ff0180ffff04ffff01ffffff333eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff10ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff04ffff04ff14ffff04ffff0113ffff04ff80ffff04ff2fffff04ff5fff808080808080ffff04ffff04ff18ffff04ffff0effff0124ff2f80ff808080ffff02ffff03ff17ffff01ff04ffff02ff3effff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ff0bff8080808080ff808080ff8080ff01808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ff8080808080ff018080"); pub const XCHANDLES_REFUND_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( " - e1ea8aede5151fb27f29ab643f1078ec608e586fb446f4d39464dd803d40343a + 4083fcef97c4ed9aa0a07884e4280ec6a00b77fb5ff5300ca0c7cdddacdfeae8 " )); @@ -214,7 +192,7 @@ impl XchandlesRefundActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct XchandlesRefundActionSolution { pub precommited_cat_maker_reveal: CMP, pub precommited_cat_maker_hash: Bytes32, @@ -224,7 +202,6 @@ pub struct XchandlesRefundActionSolution { pub precommited_pricing_puzzle_solution: PS, pub handle: String, pub secret: S, - pub precommited_start_time: u64, pub precommited_owner_launcher_id: Bytes32, pub precommited_resolved_data: Bytes, pub refund_puzzle_hash_hash: Bytes32, diff --git a/src/layers/actions/xchandles/register.rs b/src/layers/actions/xchandles/register.rs index 8d536bf5..c9fc6e7f 100644 --- a/src/layers/actions/xchandles/register.rs +++ b/src/layers/actions/xchandles/register.rs @@ -57,7 +57,7 @@ impl XchandlesRegisterAction { .to_clvm(ctx)?) } - pub fn get_spent_slot_values_from_solution( + pub fn spent_slot_values( ctx: &SpendContext, solution: NodePtr, ) -> Result<[XchandlesSlotValue; 2], DriverError> { @@ -89,7 +89,7 @@ impl XchandlesRegisterAction { ]) } - pub fn get_created_slot_values_from_solution( + pub fn created_slot_values( ctx: &mut SpendContext, solution: NodePtr, ) -> Result<[XchandlesSlotValue; 3], DriverError> { @@ -107,6 +107,8 @@ impl XchandlesRegisterAction { )?; let registration_time_delta = <(NodePtr, u64)>::from_clvm(ctx, pricing_output)?.1; + let (start_time, _) = ctx.extract::<(u64, NodePtr)>(solution.pricing_puzzle_solution)?; + Ok([ XchandlesSlotValue::new( solution.neighbors.left_value, @@ -120,7 +122,7 @@ impl XchandlesRegisterAction { solution.handle_hash, solution.neighbors.left_value, solution.neighbors.right_value, - solution.start_time + registration_time_delta, + start_time + registration_time_delta, solution.data.owner_launcher_id, solution.data.resolved_data, ), @@ -145,12 +147,13 @@ impl XchandlesRegisterAction { precommit_coin: PrecommitCoin, base_handle_price: u64, registration_period: u64, - ) -> Result<(Conditions, [Slot; 3]), DriverError> { + start_time: u64, + ) -> Result { let handle: String = precommit_coin.value.handle.clone(); let handle_hash: Bytes32 = handle.tree_hash().into(); + let (left_slot, right_slot) = registry.actual_neigbors(handle_hash, left_slot, right_slot); let secret = precommit_coin.value.secret; - let start_time = precommit_coin.value.start_time; let num_periods = precommit_coin.coin.amount / XchandlesFactorPricingPuzzleArgs::get_price(base_handle_price, &handle, 1); @@ -175,7 +178,8 @@ impl XchandlesRegisterAction { base_handle_price, registration_period, )?, - pricing_puzzle_solution: XchandlesFactorPricingSolution { + pricing_puzzle_solution: XchandlesPricingSolution { + buy_time: start_time, current_expiration: 0, handle: handle.clone(), num_periods, @@ -195,7 +199,6 @@ impl XchandlesRegisterAction { right_right_value: right_slot.info.value.neighbors.right_value, right_expiration: right_slot.info.value.expiration, right_data: right_slot.info.value.rest_data(), - start_time, data: XchandlesDataValue { owner_launcher_id: precommit_coin.value.owner_launcher_id, resolved_data: precommit_coin.value.resolved_data, @@ -206,54 +209,26 @@ impl XchandlesRegisterAction { .to_clvm(ctx)?; let action_puzzle = self.construct_puzzle(ctx)?; - registry.insert(Spend::new(action_puzzle, action_solution)); + registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; // spend slots - registry - .pending_items - .spent_slots - .push(left_slot.info.value.clone()); - registry - .pending_items - .spent_slots - .push(right_slot.info.value.clone()); - left_slot.spend(ctx, my_inner_puzzle_hash)?; right_slot.spend(ctx, my_inner_puzzle_hash)?; - let new_slots_values = Self::get_created_slot_values_from_solution(ctx, action_solution)?; - - registry - .pending_items - .created_slots - .push(new_slots_values[0].clone()); - registry - .pending_items - .created_slots - .push(new_slots_values[1].clone()); - registry - .pending_items - .created_slots - .push(new_slots_values[2].clone()); - - Ok(( + Ok( Conditions::new().assert_puzzle_announcement(announcement_id( registry.coin.puzzle_hash, register_announcement, )), - registry - .created_slot_values_to_slots(new_slots_values.to_vec()) - .try_into() - .unwrap(), - )) + ) } } -pub const XCHANDLES_REGISTER_PUZZLE: [u8; 1356] = hex!("ff02ffff01ff02ffff03ffff22ffff09ff4fffff0bffff0101ff82056f8080ffff20ff82026f80ffff0aff4fff8213ef80ffff0aff821befff4f80ffff09ff57ffff02ff2effff04ff02ffff04ff8202efff8080808080ffff09ff81b7ffff02ff2effff04ff02ffff04ff81afff8080808080ffff09ffff0dff8313ffef80ffff012080ffff15ffff0141ffff0dff831bffef808080ffff01ff04ff17ffff02ff1affff04ff02ffff04ffff02ff8202efffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff8317ffef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff57ff8205ef80ffff04ff81b7ff82016f8080ffff04ffff04ff82056fff832fffef80ffff04ff8305ffefffff04ff8313ffefff831bffef80808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff8205ef8080ffff04ffff05ffff02ff81afff82016f8080ffff04ffff04ffff04ff10ffff04ff8305ffefff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff821bef8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff8213efff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff4fff820bef80ffff04ffff10ff8305ffefffff06ffff02ff81afff82016f808080ff830bffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff4f8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff4fff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ff80808080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0172ff0580ff808080ff178080ffff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080"); +pub const XCHANDLES_REGISTER_PUZZLE: [u8; 1345] = hex!("ff02ffff01ff02ffff03ffff22ffff09ff4fffff0bffff0101ff820b6f8080ffff20ff82056f80ffff0aff4fff8213ef80ffff0aff821befff4f80ffff09ff57ffff02ff2effff04ff02ffff04ff8202efff8080808080ffff09ff81b7ffff02ff2effff04ff02ffff04ff81afff8080808080ffff09ffff0dff8309ffef80ffff012080ffff15ffff0141ffff0dff830dffef808080ffff01ff04ff17ffff02ff1affff04ff02ffff04ffff02ff8202efffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff830bffef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff57ff8205ef80ffff04ff81b7ff82016f8080ffff04ffff04ff820b6fff8317ffef80ffff04ff8309ffefff830dffef808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff8205ef8080ffff04ffff05ffff02ff81afff82016f8080ffff04ffff04ffff04ff10ffff04ff82026fff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff821bef8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff8213efff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff4fff820bef80ffff04ffff10ff82026fffff06ffff02ff81afff82016f808080ff8305ffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff4f8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff4fff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ff80808080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0172ff0580ff808080ff178080ffff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080"); pub const XCHANDLES_REGISTER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( " - 277d7b7171f56365d124c68beb3933aecda41dd09a2112f4dd56ebde542f54e5 + 07848cf0db85d13490c15331a065364add5f5b52d8059c410f1ff7aa87e66722 " )); @@ -301,7 +276,7 @@ impl XchandlesRegisterActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct XchandlesRegisterActionSolution { pub handle_hash: Bytes32, pub pricing_puzzle_reveal: PP, @@ -315,17 +290,16 @@ pub struct XchandlesRegisterActionSolution { pub right_right_value: Bytes32, pub right_expiration: u64, pub right_data: XchandlesDataValue, - pub start_time: u64, pub data: XchandlesDataValue, pub refund_puzzle_hash_hash: Bytes32, pub secret: S, } -pub const XCHANDLES_FACTOR_PRICING_PUZZLE: [u8; 475] = hex!("ff02ffff01ff02ffff03ffff15ff3fff8080ffff01ff04ffff12ff3fff05ffff02ff06ffff04ff02ffff04ffff0dff2f80ffff04ffff02ff04ffff04ff02ffff04ff2fff80808080ff808080808080ffff12ff3fff0b8080ffff01ff088080ff0180ffff04ffff01ffff02ffff03ff05ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff016080ffff15ffff017bffff0cff05ff80ffff0101808080ffff01ff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff80808080ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff012f80ffff15ffff013affff0cff05ff80ffff0101808080ffff01ff10ffff0101ffff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff8080808080ffff01ff088080ff018080ff0180ff8080ff0180ff05ffff14ffff02ffff03ffff15ff05ffff010280ffff01ff02ffff03ffff15ff05ffff010480ffff01ff02ffff03ffff09ff05ffff010580ffff01ff0110ffff01ff02ffff03ffff15ff05ffff011f80ffff01ff0880ffff01ff010280ff018080ff0180ffff01ff02ffff03ffff09ff05ffff010380ffff01ff01820080ffff01ff014080ff018080ff0180ffff01ff088080ff0180ffff03ff0bffff0102ffff0101808080ff018080"); +pub const XCHANDLES_FACTOR_PRICING_PUZZLE: [u8; 475] = hex!("ff02ffff01ff02ffff03ffff15ff7fff8080ffff01ff04ffff12ff7fff05ffff02ff06ffff04ff02ffff04ffff0dff5f80ffff04ffff02ff04ffff04ff02ffff04ff5fff80808080ff808080808080ffff12ff7fff0b8080ffff01ff088080ff0180ffff04ffff01ffff02ffff03ff05ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff016080ffff15ffff017bffff0cff05ff80ffff0101808080ffff01ff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff80808080ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff012f80ffff15ffff013affff0cff05ff80ffff0101808080ffff01ff10ffff0101ffff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff8080808080ffff01ff088080ff018080ff0180ff8080ff0180ff05ffff14ffff02ffff03ffff15ff05ffff010280ffff01ff02ffff03ffff15ff05ffff010480ffff01ff02ffff03ffff09ff05ffff010580ffff01ff0110ffff01ff02ffff03ffff15ff05ffff011f80ffff01ff0880ffff01ff010280ff018080ff0180ffff01ff02ffff03ffff09ff05ffff010380ffff01ff01820080ffff01ff014080ff018080ff0180ffff01ff088080ff0180ffff03ff0bffff0102ffff0101808080ff018080"); pub const XCHANDLES_FACTOR_PRICING_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( " - 3795a26d84d34e964f4f53ca7431d925d2b3399f9fdf2570de4d50313a3e9e4b + a7edc890e6c256e4e729e826e7b45ad0616ec8d431e4e051ee68ddf4cae868bb " )); @@ -385,8 +359,9 @@ impl XchandlesFactorPricingPuzzleArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] -pub struct XchandlesFactorPricingSolution { +#[clvm(list)] +pub struct XchandlesPricingSolution { + pub buy_time: u64, pub current_expiration: u64, pub handle: String, #[clvm(rest)] @@ -428,7 +403,8 @@ mod tests { "a".repeat(handle_length) }; - let solution = ctx.alloc(&XchandlesFactorPricingSolution { + let solution = ctx.alloc(&XchandlesPricingSolution { + buy_time: 0, current_expiration: (handle_length - 3) as u64, // shouldn't matter handle, num_periods, @@ -459,7 +435,8 @@ mod tests { // make sure the puzzle won't let us register a handle of length 2 - let solution = ctx.alloc(&XchandlesFactorPricingSolution { + let solution = ctx.alloc(&XchandlesPricingSolution { + buy_time: 0, current_expiration: 0, handle: "aa".to_string(), num_periods: 1, @@ -472,7 +449,8 @@ mod tests { // make sure the puzzle won't let us register a handle of length 32 - let solution = ctx.alloc(&XchandlesFactorPricingSolution { + let solution = ctx.alloc(&XchandlesPricingSolution { + buy_time: 0, current_expiration: 0, handle: "a".repeat(32), num_periods: 1, @@ -485,7 +463,8 @@ mod tests { // make sure the puzzle won't let us register a handle with invalid characters - let solution = ctx.alloc(&XchandlesFactorPricingSolution { + let solution = ctx.alloc(&XchandlesPricingSolution { + buy_time: 0, current_expiration: 0, handle: "yak@test".to_string(), num_periods: 1, diff --git a/src/layers/actions/xchandles/update.rs b/src/layers/actions/xchandles/update.rs index c8d10d0c..20de56d6 100644 --- a/src/layers/actions/xchandles/update.rs +++ b/src/layers/actions/xchandles/update.rs @@ -44,7 +44,7 @@ impl XchandlesUpdateAction { .to_clvm(ctx)?) } - pub fn get_spent_slot_value_from_solution( + pub fn spent_slot_value( ctx: &SpendContext, solution: NodePtr, ) -> Result { @@ -53,7 +53,7 @@ impl XchandlesUpdateAction { Ok(solution.current_slot_value) } - pub fn get_created_slot_value_from_solution( + pub fn created_slot_value( ctx: &mut SpendContext, solution: NodePtr, ) -> Result { @@ -73,8 +73,9 @@ impl XchandlesUpdateAction { new_owner_launcher_id: Bytes32, new_resolved_data: Bytes, announcer_inner_puzzle_hash: Bytes32, - ) -> Result<(Conditions, Slot), DriverError> { + ) -> Result { // spend self + let slot = registry.actual_slot(slot); let action_solution = ctx.alloc(&XchandlesUpdateActionSolution { current_slot_value: slot.info.value.clone(), new_data: XchandlesDataValue { @@ -85,18 +86,7 @@ impl XchandlesUpdateAction { })?; let action_puzzle = self.construct_puzzle(ctx)?; - registry.insert(Spend::new(action_puzzle, action_solution)); - - let new_slot_value = slot - .info - .value - .clone() - .with_data(new_owner_launcher_id, new_resolved_data.clone()); - - registry - .pending_items - .created_slots - .push(new_slot_value.clone()); + registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; // spend slot let my_inner_puzzle_hash: Bytes32 = registry.info.inner_puzzle_hash().into(); @@ -108,21 +98,12 @@ impl XchandlesUpdateAction { .tree_hash() .into(); - registry - .pending_items - .spent_slots - .push(slot.info.value.clone()); slot.spend(ctx, my_inner_puzzle_hash)?; - Ok(( - Conditions::new().send_message( - 18, - msg.into(), - vec![ctx.alloc(®istry.coin.puzzle_hash)?], - ), - registry - .created_slot_values_to_slots(vec![new_slot_value.clone()]) - .remove(0), + Ok(Conditions::new().send_message( + 18, + msg.into(), + vec![ctx.alloc(®istry.coin.puzzle_hash)?], )) } } @@ -164,7 +145,7 @@ impl XchandlesUpdateActionArgs { } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct XchandlesUpdateActionSolution { pub current_slot_value: XchandlesSlotValue, pub new_data: XchandlesDataValue, diff --git a/src/layers/m_of_n_layer.rs b/src/layers/m_of_n_layer.rs index 03ba60db..6e34024a 100644 --- a/src/layers/m_of_n_layer.rs +++ b/src/layers/m_of_n_layer.rs @@ -173,7 +173,7 @@ impl P2MOfNDelegateDirectArgs { } #[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct P2MOfNDelegateDirectSolution { pub selectors: Vec, pub delegated_puzzle: P, diff --git a/src/layers/p2_delegated_by_singleton_layer.rs b/src/layers/p2_delegated_by_singleton_layer.rs index 59dafc5e..007d2fa6 100644 --- a/src/layers/p2_delegated_by_singleton_layer.rs +++ b/src/layers/p2_delegated_by_singleton_layer.rs @@ -127,7 +127,7 @@ impl P2DelegatedBySingletonLayerArgs { } #[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct P2DelegatedBySingletonLayerSolution { pub singleton_inner_puzzle_hash: Bytes32, pub delegated_puzzle: P, diff --git a/src/layers/precommit_layer.rs b/src/layers/precommit_layer.rs index 9542e9a6..21486c9e 100644 --- a/src/layers/precommit_layer.rs +++ b/src/layers/precommit_layer.rs @@ -195,7 +195,7 @@ pub struct PrecommitLayer2ndCurryArgs { } #[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct PrecommitLayerSolution { pub mode: u8, pub my_amount: u64, @@ -238,7 +238,7 @@ impl CatalogPrecommitValue { let mut conds = Conditions::new().create_coin( owner_inner_puzzle_hash, 1, - Some(ctx.hint(owner_inner_puzzle_hash)?), + ctx.hint(owner_inner_puzzle_hash)?, ); let updater_solution = ctx.alloc(&initial_metadata)?; conds = conds.update_nft_metadata(ctx.any_metadata_updater()?, updater_solution); @@ -269,7 +269,7 @@ where // value is: // (c // (c (c cat_maker_reveal cat_maker_solution) (c pricing_puzzle_reveal pricing_solution)) -// (c (c secret handle) (c start_time (c owner_launcher_id resolved_data)))) +// (c (c secret handle) (c owner_launcher_id resolved_data))) // ) #[derive(Debug, Clone, PartialEq, Eq)] pub struct XchandlesPrecommitValue @@ -284,7 +284,6 @@ where pub pricing_solution: PS, pub handle: String, pub secret: S, - pub start_time: u64, pub owner_launcher_id: Bytes32, pub resolved_data: Bytes, } @@ -303,7 +302,6 @@ where pricing_solution: PS, handle: String, secret: S, - start_time: u64, owner_launcher_id: Bytes32, resolved_data: Bytes, ) -> Self { @@ -314,7 +312,6 @@ where pricing_solution, handle, secret, - start_time, owner_launcher_id, resolved_data, } @@ -329,7 +326,6 @@ impl XchandlesPrecommitValue<(), TreeHash, Bytes32> { pricing_puzzle_solution: PS, handle: String, secret: Bytes32, - start_time: u64, owner_launcher_id: Bytes32, resolved_data: Bytes, ) -> Self @@ -343,7 +339,6 @@ impl XchandlesPrecommitValue<(), TreeHash, Bytes32> { pricing_puzzle_solution.tree_hash(), handle, secret, - start_time, owner_launcher_id, resolved_data, ) @@ -365,10 +360,7 @@ where ), clvm_tuple!( clvm_tuple!(self.handle.tree_hash(), self.secret.tree_hash()), - clvm_tuple!( - self.start_time, - clvm_tuple!(self.owner_launcher_id, self.resolved_data.tree_hash()) - ) + clvm_tuple!(self.owner_launcher_id, self.resolved_data.tree_hash()) ) ) .tree_hash() diff --git a/src/layers/state_scheduler_layer.rs b/src/layers/state_scheduler_layer.rs index 9ab38575..f050f340 100644 --- a/src/layers/state_scheduler_layer.rs +++ b/src/layers/state_scheduler_layer.rs @@ -2,6 +2,7 @@ use chia::{ clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, protocol::Bytes32, }; +use chia_puzzle_types::Memos; use chia_puzzles::SINGLETON_TOP_LAYER_V1_1_HASH; use chia_wallet_sdk::{ driver::{DriverError, Layer, Puzzle, SpendContext}, @@ -94,7 +95,7 @@ impl Layer for StateSchedulerLayer { fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { let base_conditions = Conditions::new() - .create_coin(self.new_puzzle_hash, 1, None) + .create_coin(self.new_puzzle_hash, 1, Memos::None) .assert_height_absolute(self.required_block_height); let inner_puzzle = ctx.alloc(&clvm_quote!(base_conditions))?; @@ -162,7 +163,7 @@ where } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct StateSchedulerLayerSolution { pub other_singleton_inner_puzzle_hash: Bytes32, #[clvm(rest)] diff --git a/src/layers/verification_layer.rs b/src/layers/verification_layer.rs index a00c75b9..edad44fd 100644 --- a/src/layers/verification_layer.rs +++ b/src/layers/verification_layer.rs @@ -180,7 +180,7 @@ where } #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct VerificationLayerSolution { pub revocation_singleton_inner_puzzle_hash: Option, } diff --git a/src/primitives/catalog_registry.rs b/src/primitives/catalog_registry.rs index e0c6cf5c..e4e6765a 100644 --- a/src/primitives/catalog_registry.rs +++ b/src/primitives/catalog_registry.rs @@ -1,19 +1,46 @@ use chia::{ + bls::Signature, clvm_utils::ToTreeHash, - protocol::{Bytes32, Coin}, + protocol::{Bytes32, Coin, CoinSpend}, puzzles::{singleton::SingletonSolution, LineageProof, Proof}, }; use chia_wallet_sdk::driver::{DriverError, Layer, Puzzle, Spend, SpendContext}; -use clvm_traits::FromClvm; -use clvmr::{Allocator, NodePtr}; +use clvm_traits::{clvm_list, match_tuple}; +use clvmr::NodePtr; -use crate::{Action, ActionLayer, ActionLayerSolution, CatalogRegisterAction, Registry}; +use crate::{ + Action, ActionLayer, ActionLayerSolution, CatalogRefundAction, CatalogRegisterAction, + DelegatedStateAction, Registry, +}; use super::{ CatalogRegistryConstants, CatalogRegistryInfo, CatalogRegistryState, CatalogSlotValue, Slot, SlotInfo, SlotProof, }; +#[derive(Debug, Clone)] +pub struct CatalogPendingSpendInfo { + pub actions: Vec, + pub created_slots: Vec, + pub spent_slots: Vec, + + pub latest_state: (NodePtr, CatalogRegistryState), + + pub signature: Signature, +} + +impl CatalogPendingSpendInfo { + pub fn new(latest_state: CatalogRegistryState) -> Self { + Self { + actions: vec![], + created_slots: vec![], + spent_slots: vec![], + latest_state: (NodePtr::NIL, latest_state), + signature: Signature::default(), + } + } +} + #[derive(Debug, Clone)] #[must_use] pub struct CatalogRegistry { @@ -21,8 +48,7 @@ pub struct CatalogRegistry { pub proof: Proof, pub info: CatalogRegistryInfo, - pub pending_actions: Vec, - pub pending_slots: Vec>, + pub pending_spend: CatalogPendingSpendInfo, } impl CatalogRegistry { @@ -31,52 +57,190 @@ impl CatalogRegistry { coin, proof, info, - pending_actions: vec![], - pending_slots: vec![], + pending_spend: CatalogPendingSpendInfo::new(info.state), } } } impl CatalogRegistry { + #[allow(clippy::type_complexity)] + pub fn pending_info_delta_from_spend( + ctx: &mut SpendContext, + action_spend: Spend, + current_state_and_ephemeral: (NodePtr, CatalogRegistryState), + constants: CatalogRegistryConstants, + ) -> Result< + ( + (NodePtr, CatalogRegistryState), + Vec, // created slot values + Vec, // spent slot values + ), + DriverError, + > { + let mut created_slots = vec![]; + let mut spent_slots = vec![]; + + let register_action = CatalogRegisterAction::from_constants(&constants); + let register_hash = register_action.tree_hash(); + + let refund_action = CatalogRefundAction::from_constants(&constants); + let refund_hash = refund_action.tree_hash(); + + let delegated_state_action = + >::from_constants(&constants); + let delegated_state_hash = delegated_state_action.tree_hash(); + + let actual_solution = ctx.alloc(&clvm_list!( + current_state_and_ephemeral, + action_spend.solution + ))?; + + let output = ctx.run(action_spend.puzzle, actual_solution)?; + let (new_state_and_ephemeral, _) = + ctx.extract::(output)?; + + let raw_action_hash = ctx.tree_hash(action_spend.puzzle); + + if raw_action_hash == register_hash { + spent_slots.extend(register_action.spent_slot_values(ctx, action_spend.solution)?); + + created_slots.extend(register_action.created_slot_values(ctx, action_spend.solution)?); + } else if raw_action_hash == refund_hash { + if let (Some(spent_slot), Some(created_slot)) = ( + refund_action.spent_slot_value(ctx, action_spend.solution)?, + refund_action.created_slot_value(ctx, action_spend.solution)?, + ) { + spent_slots.push(spent_slot); + created_slots.push(created_slot); + } + } else if raw_action_hash != delegated_state_hash { + // delegated state action has no effect on slots + return Err(DriverError::InvalidMerkleProof); + } + + Ok((new_state_and_ephemeral, created_slots, spent_slots)) + } + + pub fn pending_info_from_spend( + ctx: &mut SpendContext, + inner_solution: NodePtr, + initial_state: CatalogRegistryState, + constants: CatalogRegistryConstants, + ) -> Result { + let mut created_slots = vec![]; + let mut spent_slots = vec![]; + + let mut state_incl_ephemeral: (NodePtr, CatalogRegistryState) = + (NodePtr::NIL, initial_state); + + let inner_solution = + ActionLayer::::parse_solution(ctx, inner_solution)?; + + for raw_action in inner_solution.action_spends.iter() { + let res = Self::pending_info_delta_from_spend( + ctx, + *raw_action, + state_incl_ephemeral, + constants, + )?; + + state_incl_ephemeral = res.0; + created_slots.extend(res.1); + spent_slots.extend(res.2); + } + + Ok(CatalogPendingSpendInfo { + actions: inner_solution.action_spends, + created_slots, + spent_slots, + latest_state: state_incl_ephemeral, + signature: Signature::default(), + }) + } + + pub fn set_pending_signature(&mut self, signature: Signature) { + self.pending_spend.signature = signature; + } + + pub fn from_spend( + ctx: &mut SpendContext, + spend: &CoinSpend, + constants: CatalogRegistryConstants, + ) -> Result, DriverError> { + let coin = spend.coin; + let puzzle_ptr = ctx.alloc(&spend.puzzle_reveal)?; + let puzzle = Puzzle::parse(ctx, puzzle_ptr); + let solution_ptr = ctx.alloc(&spend.solution)?; + + let Some(info) = CatalogRegistryInfo::parse(ctx, puzzle, constants)? else { + return Ok(None); + }; + + let solution = ctx.extract::>(solution_ptr)?; + let proof = solution.lineage_proof; + + let pending_spend = + Self::pending_info_from_spend(ctx, solution.inner_solution, info.state, constants)?; + + Ok(Some(CatalogRegistry { + coin, + proof, + info, + pending_spend, + })) + } + + pub fn child_lineage_proof(&self) -> LineageProof { + LineageProof { + parent_parent_coin_info: self.coin.parent_coin_info, + parent_inner_puzzle_hash: self.info.inner_puzzle_hash().into(), + parent_amount: self.coin.amount, + } + } + pub fn from_parent_spend( - allocator: &mut Allocator, - parent_coin: Coin, - parent_puzzle: Puzzle, - parent_solution: NodePtr, + ctx: &mut SpendContext, + parent_spend: &CoinSpend, constants: CatalogRegistryConstants, ) -> Result, DriverError> where Self: Sized, { - let Some(parent_info) = CatalogRegistryInfo::parse(allocator, parent_puzzle, constants)? + let Some(parent_registry) = CatalogRegistry::from_spend(ctx, parent_spend, constants)? else { return Ok(None); }; - let proof = Proof::Lineage(LineageProof { - parent_parent_coin_info: parent_coin.parent_coin_info, - parent_inner_puzzle_hash: parent_info.inner_puzzle_hash().into(), - parent_amount: parent_coin.amount, - }); - - let parent_solution = SingletonSolution::::from_clvm(allocator, parent_solution)?; - let new_state = ActionLayer::::get_new_state( - allocator, - parent_info.state, - parent_solution.inner_solution, - )?; + let proof = Proof::Lineage(parent_registry.child_lineage_proof()); - let new_info = parent_info.with_state(new_state); - let new_coin = Coin::new(parent_coin.coin_id(), new_info.puzzle_hash().into(), 1); + let new_info = parent_registry + .info + .with_state(parent_registry.pending_spend.latest_state.1); + let new_coin = Coin::new( + parent_registry.coin.coin_id(), + new_info.puzzle_hash().into(), + 1, + ); Ok(Some(CatalogRegistry { coin: new_coin, proof, info: new_info, - pending_actions: vec![], - pending_slots: vec![], + pending_spend: CatalogPendingSpendInfo::new(new_info.state), })) } + + pub fn child(&self, child_state: CatalogRegistryState) -> Self { + let new_info = self.info.with_state(child_state); + let new_coin = Coin::new(self.coin.coin_id(), new_info.puzzle_hash().into(), 1); + + CatalogRegistry { + coin: new_coin, + proof: Proof::Lineage(self.child_lineage_proof()), + info: new_info, + pending_spend: CatalogPendingSpendInfo::new(new_info.state), + } + } } impl Registry for CatalogRegistry { @@ -85,17 +249,19 @@ impl Registry for CatalogRegistry { } impl CatalogRegistry { - pub fn finish_spend(self, ctx: &mut SpendContext) -> Result { + pub fn finish_spend(self, ctx: &mut SpendContext) -> Result<(Self, Signature), DriverError> { let layers = self.info.into_layers(); let puzzle = layers.construct_puzzle(ctx)?; let action_puzzle_hashes = self - .pending_actions + .pending_spend + .actions .iter() .map(|a| ctx.tree_hash(a.puzzle).into()) .collect::>(); + let child = self.child(self.pending_spend.latest_state.1); let solution = layers.construct_solution( ctx, SingletonSolution { @@ -111,7 +277,7 @@ impl CatalogRegistry { .ok_or(DriverError::Custom( "Couldn't build proofs for one or more actions".to_string(), ))?, - action_spends: self.pending_actions, + action_spends: self.pending_spend.actions, finalizer_solution: NodePtr::NIL, }, }, @@ -120,27 +286,7 @@ impl CatalogRegistry { let my_spend = Spend::new(puzzle, solution); ctx.spend(self.coin, my_spend)?; - let my_puzzle = Puzzle::parse(ctx, my_spend.puzzle); - let new_self = CatalogRegistry::from_parent_spend( - ctx, - self.coin, - my_puzzle, - my_spend.solution, - self.info.constants, - )? - .ok_or(DriverError::Custom( - "Couldn't parse child registry".to_string(), - ))?; - - Ok(new_self) - } - - pub fn insert(&mut self, action_spend: Spend) { - self.pending_actions.push(action_spend); - } - - pub fn insert_multiple(&mut self, action_spends: Vec) { - self.pending_actions.extend(action_spends); + Ok((child, self.pending_spend.signature)) } pub fn new_action(&self) -> A @@ -150,62 +296,19 @@ impl CatalogRegistry { A::from_constants(&self.info.constants) } - pub fn created_slot_values_to_slots( + pub fn created_slot_value_to_slot( &self, - slot_values: Vec, - ) -> Vec> { + slot_value: CatalogSlotValue, + ) -> Slot { let proof = SlotProof { parent_parent_info: self.coin.parent_coin_info, parent_inner_puzzle_hash: self.info.inner_puzzle_hash().into(), }; - slot_values - .into_iter() - .map(|slot_value| { - Slot::new( - proof, - SlotInfo::from_value(self.info.constants.launcher_id, 0, slot_value), - ) - }) - .collect() - } - - pub fn get_new_slots_from_spend( - &self, - ctx: &mut SpendContext, - solution: NodePtr, - ) -> Result>, DriverError> { - let solution = ctx.extract::>(solution)?; - - let mut slot_infos = vec![]; - - let register_action = CatalogRegisterAction::from_constants(&self.info.constants); - let register_hash = register_action.tree_hash(); - - let inner_solution = ActionLayer::::parse_solution( - ctx, - solution.inner_solution, - )?; - - for raw_action in inner_solution.action_spends { - let raw_action_hash = ctx.tree_hash(raw_action.puzzle); - - if raw_action_hash == register_hash { - slot_infos.extend( - register_action.get_slot_values_from_solution(ctx, raw_action.solution)?, - ); - } - } - - Ok(self.created_slot_values_to_slots(slot_infos)) - } - - pub fn add_pending_slots(&mut self, slots: Vec>) { - for slot in slots { - self.pending_slots - .retain(|s| s.info.value.asset_id != slot.info.value.asset_id); - self.pending_slots.push(slot); - } + Slot::new( + proof, + SlotInfo::from_value(self.info.constants.launcher_id, 0, slot_value), + ) } pub fn actual_neigbors( @@ -217,19 +320,51 @@ impl CatalogRegistry { let mut left = on_chain_left_slot; let mut right = on_chain_right_slot; - let new_slot_value = - CatalogSlotValue::new(new_tail_hash, Bytes32::default(), Bytes32::default()); - - for slot in self.pending_slots.iter() { - if slot.info.value < new_slot_value && slot.info.value >= left.info.value { - left = slot.clone(); + for slot_value in self.pending_spend.created_slots.iter() { + if slot_value.asset_id < new_tail_hash + && slot_value.asset_id >= left.info.value.asset_id + { + left = self.created_slot_value_to_slot(*slot_value); } - if slot.info.value > new_slot_value && slot.info.value <= right.info.value { - right = slot.clone(); + if slot_value.asset_id > new_tail_hash + && slot_value.asset_id <= right.info.value.asset_id + { + right = self.created_slot_value_to_slot(*slot_value); } } (left, right) } + + pub fn actual_slot(&self, slot: Slot) -> Slot { + let mut slot = slot; + for slot_value in self.pending_spend.created_slots.iter() { + if slot.info.value.asset_id == slot_value.asset_id { + slot = self.created_slot_value_to_slot(*slot_value); + } + } + + slot + } + + pub fn insert_action_spend( + &mut self, + ctx: &mut SpendContext, + action_spend: Spend, + ) -> Result<(), DriverError> { + let res = Self::pending_info_delta_from_spend( + ctx, + action_spend, + self.pending_spend.latest_state, + self.info.constants, + )?; + + self.pending_spend.latest_state = res.0; + self.pending_spend.created_slots.extend(res.1); + self.pending_spend.spent_slots.extend(res.2); + self.pending_spend.actions.push(action_spend); + + Ok(()) + } } diff --git a/src/primitives/catalog_registry_info.rs b/src/primitives/catalog_registry_info.rs index fafb3993..1be8939e 100644 --- a/src/primitives/catalog_registry_info.rs +++ b/src/primitives/catalog_registry_info.rs @@ -34,7 +34,7 @@ pub struct CatalogRegistryState { pub struct CatalogRegistryConstants { pub launcher_id: Bytes32, pub royalty_address: Bytes32, - pub royalty_ten_thousandths: u16, + pub royalty_basis_points: u16, pub precommit_payout_puzzle_hash: Bytes32, pub relative_block_height: u32, pub price_singleton_launcher_id: Bytes32, @@ -45,18 +45,18 @@ impl CatalogRegistryConstants { if testnet11 { return CatalogRegistryConstants { launcher_id: Bytes32::from(hex!( - "05183ec35a4ee07049ba629c76f49f2d52b2056a1c4c63d780113244a7307a2f" + "0b705afb0d848794311970de0cb98722468fad6c8f687337735ab9e5286d7704" )), royalty_address: Bytes32::from(hex!( "b3aea098428b2b5e6d57cf3bff6ee82e3950dec338b17df6d8ee20944787def5" )), - royalty_ten_thousandths: 100, + royalty_basis_points: 100, precommit_payout_puzzle_hash: Bytes32::from(hex!( "b3aea098428b2b5e6d57cf3bff6ee82e3950dec338b17df6d8ee20944787def5" )), - relative_block_height: 8, + relative_block_height: 4, price_singleton_launcher_id: Bytes32::from(hex!( - "283caf3922c2ac7f7e3265bad97ae59d8395bcdae61cd7fdc98553e77873d35e" + "45dff01375d9bd681d36a3a186ab3d0c86eb809d7f85fff950f0b37f068ec664" )), }; } diff --git a/src/primitives/medieval_vault.rs b/src/primitives/medieval_vault.rs index 1197995e..bfd70e27 100644 --- a/src/primitives/medieval_vault.rs +++ b/src/primitives/medieval_vault.rs @@ -122,14 +122,8 @@ impl MedievalVault { return Ok(None); }; - let (new_m, new_pubkeys) = if recreate_condition.memos.is_none() { - ( - parent_layers.inner_puzzle.m, - parent_layers.inner_puzzle.public_key_list.clone(), - ) - } else { - let memos = recreate_condition.memos.unwrap(); - if let Ok(memos) = ctx.extract::(memos.value) { + let (new_m, new_pubkeys) = if let Memos::Some(memos) = recreate_condition.memos { + if let Ok(memos) = ctx.extract::(memos) { (memos.m, memos.public_key_list) } else { ( @@ -137,6 +131,11 @@ impl MedievalVault { parent_layers.inner_puzzle.public_key_list.clone(), ) } + } else { + ( + parent_layers.inner_puzzle.m, + parent_layers.inner_puzzle.public_key_list.clone(), + ) }; let parent_info = MedievalVaultInfo::new( @@ -238,7 +237,7 @@ impl MedievalVault { Ok(Conditions::new().create_coin( new_info.inner_puzzle_hash().into(), 1, - Some(Memos::new(memos)), + Memos::Some(memos), )) } @@ -271,11 +270,10 @@ impl MedievalVault { where M: ToClvm, { - let hint = ctx.hint(my_info.launcher_id)?; let conditions = Conditions::new().create_coin( my_info.inner_puzzle_hash().into(), my_coin.amount, - Some(hint), + ctx.hint(my_info.launcher_id)?, ); let genesis_challenge = ctx.alloc(&genesis_challenge)?; @@ -374,7 +372,7 @@ mod tests { let recreate_condition = Conditions::::new().create_coin( current_vault_info.inner_puzzle_hash().into(), 1, - Memos::some(recreate_memos), + Memos::Some(recreate_memos), ); let mut used_keys = 0; diff --git a/src/primitives/medieval_vault_info.rs b/src/primitives/medieval_vault_info.rs index fdbfcf30..c19ce357 100644 --- a/src/primitives/medieval_vault_info.rs +++ b/src/primitives/medieval_vault_info.rs @@ -52,7 +52,7 @@ impl MedievalVaultInfo { } #[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct MedievalVaultHint { pub my_launcher_id: Bytes32, pub m: usize, diff --git a/src/primitives/reserve.rs b/src/primitives/reserve.rs index 9325dcf5..96b589b7 100644 --- a/src/primitives/reserve.rs +++ b/src/primitives/reserve.rs @@ -4,8 +4,8 @@ use chia::{ puzzles::{cat::CatArgs, singleton::SingletonSolution, LineageProof}, }; use chia_wallet_sdk::{ - driver::{Cat, CatSpend, DriverError, Layer, Spend, SpendContext}, - prelude::{CreateCoin, Memos}, + driver::{Cat, CatInfo, CatSpend, DriverError, Layer, Spend, SpendContext}, + prelude::CreateCoin, types::run_puzzle, }; use clvm_traits::{clvm_list, clvm_quote, match_tuple, FromClvm, ToClvm}; @@ -85,8 +85,7 @@ impl Reserve { Cat::new( self.coin, Some(self.proof), - self.asset_id, - self.inner_puzzle_hash, + CatInfo::new(self.asset_id, None, self.inner_puzzle_hash), ) } @@ -145,7 +144,7 @@ impl Reserve { let cc = CreateCoin::new( self.inner_puzzle_hash, new_reserve_amount, - Some(Memos::new(vec![self.inner_puzzle_hash])), + ctx.hint(self.inner_puzzle_hash)?, ); reserve_conditions.insert(0, ctx.alloc(&cc)?); @@ -180,4 +179,19 @@ impl Reserve { )?, )) } + + pub fn child(&self, child_amount: u64) -> Self { + Self::new( + self.coin.coin_id(), + LineageProof { + parent_parent_coin_info: self.coin.parent_coin_info, + parent_inner_puzzle_hash: self.inner_puzzle_hash, + parent_amount: self.coin.amount, + }, + self.asset_id, + self.controller_singleton_struct_hash, + self.nonce, + child_amount, + ) + } } diff --git a/src/primitives/reward_distributor.rs b/src/primitives/reward_distributor.rs index 982a4ded..ff623502 100644 --- a/src/primitives/reward_distributor.rs +++ b/src/primitives/reward_distributor.rs @@ -1,4 +1,5 @@ use chia::{ + bls::Signature, clvm_utils::{tree_hash, ToTreeHash}, protocol::{Bytes32, Coin, CoinSpend}, puzzles::{ @@ -10,18 +11,19 @@ use chia_puzzle_types::singleton::{LauncherSolution, SingletonArgs}; use chia_wallet_sdk::{ driver::{DriverError, Layer, Puzzle, SingletonLayer, Spend, SpendContext}, prelude::{Cat, CatSpend}, - types::{run_puzzle, Condition, Conditions}, + types::{Condition, Conditions}, }; -use clvm_traits::{clvm_list, match_tuple, FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; +use clvm_traits::{clvm_list, match_tuple, FromClvm}; +use clvmr::NodePtr; use crate::{ Action, ActionLayer, ActionLayerSolution, RawActionLayerSolution, Registry, ReserveFinalizerSolution, RewardDistributorAddEntryAction, - RewardDistributorCommitIncentivesAction, RewardDistributorInitiatePayoutAction, - RewardDistributorNewEpochAction, RewardDistributorRemoveEntryAction, - RewardDistributorStakeAction, RewardDistributorUnstakeAction, - RewardDistributorWithdrawIncentivesAction, Slot, SlotInfo, SlotProof, + RewardDistributorAddIncentivesAction, RewardDistributorCommitIncentivesAction, + RewardDistributorInitiatePayoutAction, RewardDistributorNewEpochAction, + RewardDistributorRemoveEntryAction, RewardDistributorStakeAction, RewardDistributorSyncAction, + RewardDistributorUnstakeAction, RewardDistributorWithdrawIncentivesAction, Slot, SlotInfo, + SlotProof, }; use super::{ @@ -30,15 +32,58 @@ use super::{ RewardDistributorSlotNonce, RewardDistributorState, }; -#[derive(Debug, Clone, Default)] -pub struct RewardDistributorPendingItems { - pub pending_actions: Vec, +#[derive(Debug, Clone)] +pub struct RewardDistributorPendingSpendInfo { + pub actions: Vec, + + pub spent_reward_slots: Vec, + pub spent_commitment_slots: Vec, + pub spent_entry_slots: Vec, + + pub created_reward_slots: Vec, + pub created_commitment_slots: Vec, + pub created_entry_slots: Vec, + + pub latest_state: (NodePtr, RewardDistributorState), + + pub signature: Signature, + pub other_cats: Vec, +} + +impl RewardDistributorPendingSpendInfo { + pub fn new(latest_state: RewardDistributorState) -> Self { + Self { + actions: vec![], + created_reward_slots: vec![], + created_commitment_slots: vec![], + created_entry_slots: vec![], + spent_reward_slots: vec![], + spent_commitment_slots: vec![], + spent_entry_slots: vec![], + latest_state: (NodePtr::NIL, latest_state), + signature: Signature::default(), + other_cats: vec![], + } + } - pub pending_spent_slots: Vec<(RewardDistributorSlotNonce, Bytes32)>, // (nonce, value hash) + pub fn add_delta(&mut self, delta: RewardDistributorPendingSpendInfo) { + self.actions.extend(delta.actions); - pub pending_reward_slot_values: Vec, - pub pending_commitment_slot_values: Vec, - pub pending_entry_slot_values: Vec, + self.spent_reward_slots.extend(delta.spent_reward_slots); + self.spent_commitment_slots + .extend(delta.spent_commitment_slots); + self.spent_entry_slots.extend(delta.spent_entry_slots); + + self.created_reward_slots.extend(delta.created_reward_slots); + self.created_commitment_slots + .extend(delta.created_commitment_slots); + self.created_entry_slots.extend(delta.created_entry_slots); + + self.latest_state = delta.latest_state; + + // do not change pending signature + // or other cats + } } #[derive(Debug, Clone)] @@ -49,7 +94,7 @@ pub struct RewardDistributor { pub info: RewardDistributorInfo, pub reserve: Reserve, - pub pending_items: RewardDistributorPendingItems, + pub pending_spend: RewardDistributorPendingSpendInfo, } impl RewardDistributor { @@ -59,78 +104,287 @@ impl RewardDistributor { proof, info, reserve, - pending_items: RewardDistributorPendingItems::default(), + pending_spend: RewardDistributorPendingSpendInfo::new(info.state), } } } impl RewardDistributor { - pub fn from_parent_spend( - allocator: &mut Allocator, - parent_coin: Coin, - parent_puzzle: Puzzle, - parent_solution: NodePtr, + #[allow(clippy::type_complexity)] + pub fn pending_info_delta_from_spend( + ctx: &mut SpendContext, + action_spend: Spend, + current_state_and_ephemeral: (NodePtr, RewardDistributorState), constants: RewardDistributorConstants, - ) -> Result, DriverError> - where - Self: Sized, - { - let Some(parent_info) = RewardDistributorInfo::parse(allocator, parent_puzzle, constants)? - else { + ) -> Result { + let mut spent_reward_slots: Vec = vec![]; + let mut spent_commitment_slots: Vec = vec![]; + let mut spent_entry_slots: Vec = vec![]; + + let mut created_reward_slots: Vec = vec![]; + let mut created_commitment_slots: Vec = vec![]; + let mut created_entry_slots: Vec = vec![]; + + let new_epoch_action = RewardDistributorNewEpochAction::from_constants(&constants); + let new_epoch_hash = new_epoch_action.tree_hash(); + + let commit_incentives_action = + RewardDistributorCommitIncentivesAction::from_constants(&constants); + let commit_incentives_hash = commit_incentives_action.tree_hash(); + + let add_entry_action = RewardDistributorAddEntryAction::from_constants(&constants); + let add_entry_hash = add_entry_action.tree_hash(); + + let remove_entry_action = RewardDistributorRemoveEntryAction::from_constants(&constants); + let remove_entry_hash = remove_entry_action.tree_hash(); + + let stake_action = RewardDistributorStakeAction::from_constants(&constants); + let stake_hash = stake_action.tree_hash(); + + let unstake_action = RewardDistributorUnstakeAction::from_constants(&constants); + let unstake_hash = unstake_action.tree_hash(); + + let withdraw_incentives_action = + RewardDistributorWithdrawIncentivesAction::from_constants(&constants); + let withdraw_incentives_hash = withdraw_incentives_action.tree_hash(); + + let initiate_payout_action = + RewardDistributorInitiatePayoutAction::from_constants(&constants); + let initiate_payout_hash = initiate_payout_action.tree_hash(); + + let add_incentives_action = + RewardDistributorAddIncentivesAction::from_constants(&constants); + let add_incentives_hash = add_incentives_action.tree_hash(); + + let sync_action = RewardDistributorSyncAction::from_constants(&constants); + let sync_hash = sync_action.tree_hash(); + + let actual_solution = ctx.alloc(&clvm_list!( + current_state_and_ephemeral, + action_spend.solution + ))?; + + let output = ctx.run(action_spend.puzzle, actual_solution)?; + let (new_state_and_ephemeral, _) = + ctx.extract::(output)?; + + let raw_action_hash = ctx.tree_hash(action_spend.puzzle); + + if raw_action_hash == new_epoch_hash { + created_reward_slots.push(RewardDistributorNewEpochAction::created_slot_value( + ctx, + action_spend.solution, + )?); + spent_reward_slots.push(RewardDistributorNewEpochAction::spent_slot_value( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash == commit_incentives_hash { + let (comm, rews) = RewardDistributorCommitIncentivesAction::created_slot_values( + ctx, + constants.epoch_seconds, + action_spend.solution, + )?; + + created_commitment_slots.push(comm); + created_reward_slots.extend(rews); + spent_reward_slots.push(RewardDistributorCommitIncentivesAction::spent_slot_value( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash == add_entry_hash { + created_entry_slots.push(RewardDistributorAddEntryAction::created_slot_value( + ctx, + ¤t_state_and_ephemeral.1, + action_spend.solution, + )?); + } else if raw_action_hash == stake_hash { + created_entry_slots.push(RewardDistributorStakeAction::created_slot_value( + ctx, + ¤t_state_and_ephemeral.1, + action_spend.solution, + )?); + } else if raw_action_hash == remove_entry_hash { + spent_entry_slots.push(RewardDistributorRemoveEntryAction::spent_slot_value( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash == unstake_hash { + spent_entry_slots.push(RewardDistributorUnstakeAction::spent_slot_value( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash == withdraw_incentives_hash { + let (rew, cmt) = RewardDistributorWithdrawIncentivesAction::spent_slot_values( + ctx, + action_spend.solution, + )?; + + spent_reward_slots.push(rew); + spent_commitment_slots.push(cmt); + created_reward_slots.push( + RewardDistributorWithdrawIncentivesAction::created_slot_value( + ctx, + constants.withdrawal_share_bps, + action_spend.solution, + )?, + ); + } else if raw_action_hash == initiate_payout_hash { + created_entry_slots.push(RewardDistributorInitiatePayoutAction::created_slot_value( + ctx, + ¤t_state_and_ephemeral.1, + action_spend.solution, + )?); + spent_entry_slots.push(RewardDistributorInitiatePayoutAction::spent_slot_value( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash != add_incentives_hash && raw_action_hash != sync_hash { + // delegated state action has no effect on slots + return Err(DriverError::InvalidMerkleProof); + } + + Ok(RewardDistributorPendingSpendInfo { + actions: vec![action_spend], + spent_reward_slots, + spent_commitment_slots, + spent_entry_slots, + created_reward_slots, + created_commitment_slots, + created_entry_slots, + latest_state: new_state_and_ephemeral, + signature: Signature::default(), + other_cats: vec![], + }) + } + + pub fn pending_info_from_spend( + ctx: &mut SpendContext, + inner_solution: NodePtr, + initial_state: RewardDistributorState, + constants: RewardDistributorConstants, + ) -> Result { + let mut pending_spend_info = RewardDistributorPendingSpendInfo::new(initial_state); + + let inner_solution = + ActionLayer::::parse_solution(ctx, inner_solution)?; + + for raw_action in inner_solution.action_spends.iter() { + let delta = Self::pending_info_delta_from_spend( + ctx, + *raw_action, + pending_spend_info.latest_state, + constants, + )?; + + pending_spend_info.add_delta(delta); + } + + Ok(pending_spend_info) + } + + pub fn from_spend( + ctx: &mut SpendContext, + spend: &CoinSpend, + reserve_lineage_proof: Option, + constants: RewardDistributorConstants, + ) -> Result, DriverError> { + let coin = spend.coin; + let puzzle_ptr = ctx.alloc(&spend.puzzle_reveal)?; + let puzzle = Puzzle::parse(ctx, puzzle_ptr); + let solution_ptr = ctx.alloc(&spend.solution)?; + + let Some(info) = RewardDistributorInfo::parse(ctx, puzzle, constants)? else { return Ok(None); }; - let proof = Proof::Lineage(LineageProof { - parent_parent_coin_info: parent_coin.parent_coin_info, - parent_inner_puzzle_hash: parent_info.inner_puzzle_hash().into(), - parent_amount: parent_coin.amount, - }); - - let parent_solution = SingletonSolution::::from_clvm(allocator, parent_solution)?; - let new_state = ActionLayer::::get_new_state( - allocator, - parent_info.state, - parent_solution.inner_solution, - )?; + let solution = ctx.extract::>(solution_ptr)?; + let proof = solution.lineage_proof; - let new_info = parent_info.with_state(new_state); + let pending_spend = + Self::pending_info_from_spend(ctx, solution.inner_solution, info.state, constants)?; - let new_coin = Coin::new(parent_coin.coin_id(), new_info.puzzle_hash().into(), 1); + let inner_solution = + RawActionLayerSolution::::from_clvm( + ctx, + solution.inner_solution, + )?; - let parent_inner_solution = RawActionLayerSolution::< - NodePtr, - NodePtr, - ReserveFinalizerSolution, - >::from_clvm(allocator, parent_solution.inner_solution)?; - let parent_reserve = Coin::new( - parent_inner_solution.finalizer_solution.reserve_parent_id, - constants.reserve_full_puzzle_hash, - parent_info.state.total_reserves, - ); let reserve = Reserve::new( - parent_reserve.coin_id(), - LineageProof { - parent_parent_coin_info: parent_reserve.parent_coin_info, - parent_inner_puzzle_hash: constants.reserve_inner_puzzle_hash, - parent_amount: parent_reserve.amount, - }, + inner_solution.finalizer_solution.reserve_parent_id, + reserve_lineage_proof.unwrap_or(LineageProof { + parent_parent_coin_info: Bytes32::default(), + parent_inner_puzzle_hash: Bytes32::default(), + parent_amount: 0, + }), // dummy default value constants.reserve_asset_id, - SingletonStruct::new(parent_info.constants.launcher_id) + SingletonStruct::new(info.constants.launcher_id) .tree_hash() .into(), 0, - new_state.total_reserves, + info.state.total_reserves, ); Ok(Some(RewardDistributor { - coin: new_coin, + coin, proof, - info: new_info, + info, reserve, - pending_items: RewardDistributorPendingItems::default(), + pending_spend, + })) + } + + pub fn child_lineage_proof(&self) -> LineageProof { + LineageProof { + parent_parent_coin_info: self.coin.parent_coin_info, + parent_inner_puzzle_hash: self.info.inner_puzzle_hash().into(), + parent_amount: self.coin.amount, + } + } + + pub fn from_parent_spend( + ctx: &mut SpendContext, + parent_spend: &CoinSpend, + constants: RewardDistributorConstants, + ) -> Result, DriverError> + where + Self: Sized, + { + let Some(parent_registry) = Self::from_spend(ctx, parent_spend, None, constants)? else { + return Ok(None); + }; + + let new_info = parent_registry + .info + .with_state(parent_registry.pending_spend.latest_state.1); + + Ok(Some(RewardDistributor { + coin: Coin::new( + parent_registry.coin.coin_id(), + new_info.puzzle_hash().into(), + 1, + ), + proof: Proof::Lineage(parent_registry.child_lineage_proof()), + info: new_info, + reserve: parent_registry.reserve.child(new_info.state.total_reserves), + pending_spend: RewardDistributorPendingSpendInfo::new(new_info.state), })) } + pub fn child(&self, child_state: RewardDistributorState) -> Self { + let new_info = self.info.with_state(child_state); + let new_coin = Coin::new(self.coin.coin_id(), new_info.puzzle_hash().into(), 1); + let new_reserve = self.reserve.child(child_state.total_reserves); + + RewardDistributor { + coin: new_coin, + proof: Proof::Lineage(self.child_lineage_proof()), + info: new_info, + reserve: new_reserve, + pending_spend: RewardDistributorPendingSpendInfo::new(new_info.state), + } + } + #[allow(clippy::type_complexity)] pub fn from_launcher_solution( ctx: &mut SpendContext, @@ -259,6 +513,14 @@ impl RewardDistributor { Ok(Some((new_distributor, slot))) } + + pub fn set_pending_signature(&mut self, signature: Signature) { + self.pending_spend.signature = signature; + } + + pub fn set_pending_other_cats(&mut self, other_cats: Vec) { + self.pending_spend.other_cats = other_cats; + } } impl Registry for RewardDistributor { @@ -271,14 +533,14 @@ impl RewardDistributor { self, ctx: &mut SpendContext, other_cat_spends: Vec, - ) -> Result { + ) -> Result<(Self, Signature), DriverError> { let layers = self.info.into_layers(ctx)?; let puzzle = layers.construct_puzzle(ctx)?; let action_puzzle_hashes = self - .pending_items - .pending_actions + .pending_spend + .actions .iter() .map(|a| ctx.tree_hash(a.puzzle).into()) .collect::>(); @@ -287,6 +549,7 @@ impl RewardDistributor { reserve_parent_id: self.reserve.coin.parent_coin_info, })?; + let child = self.child(self.pending_spend.latest_state.1); let solution = layers.construct_solution( ctx, SingletonSolution { @@ -302,7 +565,7 @@ impl RewardDistributor { .ok_or(DriverError::Custom( "Couldn't build proofs for one or more actions".to_string(), ))?, - action_spends: self.pending_items.pending_actions, + action_spends: self.pending_spend.actions, finalizer_solution, }, }, @@ -320,27 +583,10 @@ impl RewardDistributor { let mut cat_spends = other_cat_spends; cat_spends.push(cat_spend); + cat_spends.extend(self.pending_spend.other_cats); Cat::spend_all(ctx, &cat_spends)?; - let my_puzzle = Puzzle::parse(ctx, my_spend.puzzle); - let new_reward_distributor = RewardDistributor::from_parent_spend( - ctx, - self.coin, - my_puzzle, - solution, - self.info.constants, - )? - .unwrap(); - - Ok(new_reward_distributor) - } - - pub fn insert(&mut self, action_spend: Spend) { - self.pending_items.pending_actions.push(action_spend); - } - - pub fn insert_multiple(&mut self, action_spends: Vec) { - self.pending_items.pending_actions.extend(action_spends); + Ok((child, self.pending_spend.signature)) } pub fn new_action(&self) -> A @@ -350,11 +596,11 @@ impl RewardDistributor { A::from_constants(&self.info.constants) } - pub fn created_slot_values_to_slots( + pub fn created_slot_value_to_slot( &self, - slot_values: Vec, + slot_value: SlotValue, nonce: RewardDistributorSlotNonce, - ) -> Vec> + ) -> Slot where SlotValue: Copy + ToTreeHash, { @@ -363,183 +609,76 @@ impl RewardDistributor { parent_inner_puzzle_hash: self.info.inner_puzzle_hash().into(), }; - slot_values - .into_iter() - .map(|slot_value| { - Slot::new( - proof, - SlotInfo::from_value( - self.info.constants.launcher_id, - nonce.to_u64(), - slot_value, - ), - ) - }) - .collect() + Slot::new( + proof, + SlotInfo::from_value(self.info.constants.launcher_id, nonce.to_u64(), slot_value), + ) } - pub fn get_latest_pending_state( - &self, - allocator: &mut Allocator, - ) -> Result { - let mut state = (NodePtr::NIL, self.info.state); + pub fn insert_action_spend( + &mut self, + ctx: &mut SpendContext, + action_spend: Spend, + ) -> Result<(), DriverError> { + let delta = Self::pending_info_delta_from_spend( + ctx, + action_spend, + self.pending_spend.latest_state, + self.info.constants, + )?; - for action in self.pending_items.pending_actions.iter() { - let actual_solution = clvm_list!(state, action.solution).to_clvm(allocator)?; + self.pending_spend.add_delta(delta); - let output = run_puzzle(allocator, action.puzzle, actual_solution)?; - (state, _) = ::from_clvm( - allocator, output, - )?; - } - - Ok(state.1) + Ok(()) } - pub fn get_latest_pending_ephemeral_state( + pub fn actual_reward_slot_value( &self, - allocator: &mut Allocator, - ) -> Result { - let mut state = (0, self.info.state); - - for action in self.pending_items.pending_actions.iter() { - let actual_solution = clvm_list!(state, action.solution).to_clvm(allocator)?; - - let output = run_puzzle(allocator, action.puzzle, actual_solution)?; - (state, _) = ::from_clvm( - allocator, output, - )?; + slot: Slot, + ) -> Slot { + let mut slot = slot; + + for slot_value in self.pending_spend.created_reward_slots.iter() { + if slot_value.epoch_start == slot.info.value.epoch_start { + slot = self + .created_slot_value_to_slot(*slot_value, RewardDistributorSlotNonce::REWARD); + } } - Ok(state.0) + slot } - pub fn get_pending_items_from_spend( + pub fn actual_entry_slot_value( &self, - ctx: &mut SpendContext, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::>(solution)?; - let inner_solution = ActionLayer::::parse_solution( - ctx, - solution.inner_solution, - )?; - - let mut actions: Vec = vec![]; - let mut reward_slot_values: Vec = vec![]; - let mut commitment_slot_values: Vec = vec![]; - let mut entry_slot_values: Vec = vec![]; - let mut spent_slots: Vec<(RewardDistributorSlotNonce, Bytes32)> = vec![]; - - let new_epoch_action = - RewardDistributorNewEpochAction::from_constants(&self.info.constants); - let new_epoch_hash = new_epoch_action.tree_hash(); - - let commit_incentives_action = - RewardDistributorCommitIncentivesAction::from_constants(&self.info.constants); - let commit_incentives_hash = commit_incentives_action.tree_hash(); - - let add_entry_action = - RewardDistributorAddEntryAction::from_constants(&self.info.constants); - let add_entry_hash = add_entry_action.tree_hash(); - - let remove_entry_action = - RewardDistributorRemoveEntryAction::from_constants(&self.info.constants); - let remove_entry_hash = remove_entry_action.tree_hash(); - - let stake_action = RewardDistributorStakeAction::from_constants(&self.info.constants); - let stake_hash = stake_action.tree_hash(); - - let unstake_action = RewardDistributorUnstakeAction::from_constants(&self.info.constants); - let unstake_hash = unstake_action.tree_hash(); - - let withdraw_incentives_action = - RewardDistributorWithdrawIncentivesAction::from_constants(&self.info.constants); - let withdraw_incentives_hash = withdraw_incentives_action.tree_hash(); + slot: Slot, + ) -> Slot { + let mut slot = slot; + + for slot_value in self.pending_spend.created_entry_slots.iter() { + if slot_value.payout_puzzle_hash == slot.info.value.payout_puzzle_hash { + slot = + self.created_slot_value_to_slot(*slot_value, RewardDistributorSlotNonce::ENTRY); + } + } - let initiate_payout_action = - RewardDistributorInitiatePayoutAction::from_constants(&self.info.constants); - let initiate_payout_hash = initiate_payout_action.tree_hash(); + slot + } - let mut current_state = (NodePtr::NIL, self.info.state); - for raw_action in inner_solution.action_spends { - actions.push(Spend::new(raw_action.puzzle, raw_action.solution)); - - let actual_solution = ctx.alloc(&clvm_list!(current_state, raw_action.solution))?; - - let action_output = run_puzzle(ctx, raw_action.puzzle, actual_solution)?; - (current_state, _) = ctx - .extract::( - action_output, - )?; - - let raw_action_hash = ctx.tree_hash(raw_action.puzzle); - - if raw_action_hash == new_epoch_hash { - let (rew, spent) = - new_epoch_action.get_slot_value_from_solution(ctx, raw_action.solution)?; - - reward_slot_values.push(rew); - spent_slots.push(spent); - } else if raw_action_hash == commit_incentives_hash { - let (comm, rews, spent_slot) = commit_incentives_action - .get_slot_values_from_solution( - ctx, - self.info.constants.epoch_seconds, - raw_action.solution, - )?; - - commitment_slot_values.push(comm); - reward_slot_values.extend(rews); - spent_slots.push(spent_slot); - } else if raw_action_hash == add_entry_hash { - entry_slot_values.push(add_entry_action.get_slot_value_from_solution( - ctx, - ¤t_state.1, - raw_action.solution, - )?); - } else if raw_action_hash == stake_hash { - entry_slot_values.push(stake_action.get_slot_value_from_solution( - ctx, - ¤t_state.1, - raw_action.solution, - )?); - } else if raw_action_hash == remove_entry_hash { - spent_slots.push( - remove_entry_action - .get_spent_slot_value_from_solution(ctx, raw_action.solution)?, - ); - } else if raw_action_hash == unstake_hash { - spent_slots.push( - unstake_action.get_spent_slot_value_from_solution(ctx, raw_action.solution)?, + pub fn actual_commitment_slot_value( + &self, + slot: Slot, + ) -> Slot { + let mut slot = slot; + + for slot_value in self.pending_spend.created_commitment_slots.iter() { + if slot_value.epoch_start == slot.info.value.epoch_start { + slot = self.created_slot_value_to_slot( + *slot_value, + RewardDistributorSlotNonce::COMMITMENT, ); - } else if raw_action_hash == withdraw_incentives_hash { - let (rew, spnt) = withdraw_incentives_action.get_slot_value_from_solution( - ctx, - &self.info.constants, - raw_action.solution, - )?; - - reward_slot_values.push(rew); - spent_slots.extend(spnt); - } else if raw_action_hash == initiate_payout_hash { - let (mirr, spent) = initiate_payout_action.get_slot_value_from_solution( - ctx, - ¤t_state.1, - raw_action.solution, - )?; - - entry_slot_values.push(mirr); - spent_slots.push(spent); } } - Ok(RewardDistributorPendingItems { - pending_actions: actions, - pending_spent_slots: spent_slots, - pending_reward_slot_values: reward_slot_values, - pending_commitment_slot_values: commitment_slot_values, - pending_entry_slot_values: entry_slot_values, - }) + slot } } diff --git a/src/primitives/slot.rs b/src/primitives/slot.rs index 19bfa7f2..602711fa 100644 --- a/src/primitives/slot.rs +++ b/src/primitives/slot.rs @@ -131,7 +131,7 @@ pub struct Slot2ndCurryArgs { } #[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct SlotSolution { pub parent_parent_info: Bytes32, pub parent_inner_puzzle_hash: Bytes32, diff --git a/src/primitives/state_scheduler.rs b/src/primitives/state_scheduler.rs index d695b4fb..04d50077 100644 --- a/src/primitives/state_scheduler.rs +++ b/src/primitives/state_scheduler.rs @@ -123,6 +123,7 @@ where #[cfg(test)] mod tests { + use chia_puzzle_types::Memos; use chia_wallet_sdk::{ driver::{Launcher, SingletonLayer}, test::Simulator, @@ -239,7 +240,7 @@ mod tests { new_state.tree_hash().to_vec().into(), vec![state_scheduler_puzzle_hash_ptr], ) - .create_coin(other_singleton_inner_puzzle_hash.into(), 1, None), + .create_coin(other_singleton_inner_puzzle_hash.into(), 1, Memos::None), )?; let other_singleton_spend = other_singleton.construct_spend( ctx, diff --git a/src/primitives/state_scheduler_info.rs b/src/primitives/state_scheduler_info.rs index c2d4e441..ece6985f 100644 --- a/src/primitives/state_scheduler_info.rs +++ b/src/primitives/state_scheduler_info.rs @@ -3,6 +3,7 @@ use chia::{ protocol::Bytes32, puzzles::singleton::{LauncherSolution, SingletonArgs, SingletonStruct}, }; +use chia_puzzle_types::Memos; use chia_wallet_sdk::{ driver::{DriverError, SingletonLayer}, types::Condition, @@ -63,7 +64,7 @@ where .into(), message, clvm_quote!(vec![ - Condition::<()>::create_coin(next_puzzle_hash, 1, None), + Condition::<()>::create_coin(next_puzzle_hash, 1, Memos::None), Condition::assert_height_absolute(required_block_height), ]), ) diff --git a/src/primitives/verification.rs b/src/primitives/verification.rs index 197207ec..347eeb70 100644 --- a/src/primitives/verification.rs +++ b/src/primitives/verification.rs @@ -178,6 +178,7 @@ pub struct VerificationLauncherKVList { mod tests { use anyhow::Ok; use chia::protocol::Bytes; + use chia_puzzle_types::Memos; use chia_puzzles::SINGLETON_LAUNCHER_HASH; use chia_wallet_sdk::{ driver::{Launcher, StandardLayer}, @@ -204,7 +205,7 @@ mod tests { let did = did.update( ctx, &p2, - Conditions::new().create_coin(SINGLETON_LAUNCHER_HASH.into(), 0, None), + Conditions::new().create_coin(SINGLETON_LAUNCHER_HASH.into(), 0, Memos::None), )?; let verification_launcher = Launcher::new(did.coin.parent_coin_info, 0); // we don't need an extra mojo for the verification coin since it's melted in the same tx diff --git a/src/primitives/verification_asserter.rs b/src/primitives/verification_asserter.rs index 21877aa7..e52bd4a5 100644 --- a/src/primitives/verification_asserter.rs +++ b/src/primitives/verification_asserter.rs @@ -167,7 +167,7 @@ impl

VerificationAsserterArgs

{ } #[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct VerificationAsserterSolution { pub verifier_proof: LineageProof, pub verification_inner_puzzle_maker_solution: S, @@ -201,7 +201,7 @@ impl CatalogVerificationInnerPuzzleMakerArgs { } #[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(solution)] +#[clvm(list)] pub struct CatalogVerificationInnerPuzzleMakerSolution { pub comment: String, } diff --git a/src/primitives/xchandles_registry.rs b/src/primitives/xchandles_registry.rs index 9ebe9e44..776411bb 100644 --- a/src/primitives/xchandles_registry.rs +++ b/src/primitives/xchandles_registry.rs @@ -1,20 +1,18 @@ use chia::{ + bls::Signature, clvm_utils::ToTreeHash, - protocol::{Bytes, Bytes32, Coin}, + protocol::{Bytes32, Coin, CoinSpend}, puzzles::{singleton::SingletonSolution, LineageProof, Proof}, }; use chia_puzzle_types::singleton::{LauncherSolution, SingletonArgs}; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, Spend, SpendContext}, - types::run_puzzle, -}; -use clvm_traits::{clvm_list, match_tuple, FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; +use chia_wallet_sdk::driver::{DriverError, Layer, Puzzle, Spend, SpendContext}; +use clvm_traits::{clvm_list, match_tuple}; +use clvmr::NodePtr; use crate::{ - eve_singleton_inner_puzzle, Action, ActionLayer, ActionLayerSolution, CliError, - DelegatedStateAction, Registry, XchandlesExpireAction, XchandlesExtendAction, - XchandlesOracleAction, XchandlesRefundAction, XchandlesRegisterAction, XchandlesUpdateAction, + eve_singleton_inner_puzzle, Action, ActionLayer, ActionLayerSolution, DelegatedStateAction, + Registry, XchandlesExpireAction, XchandlesExtendAction, XchandlesOracleAction, + XchandlesRefundAction, XchandlesRegisterAction, XchandlesUpdateAction, }; use super::{ @@ -22,12 +20,27 @@ use super::{ XchandlesSlotValue, }; -#[derive(Debug, Clone, Default)] -pub struct XchandlesRegistryPendingItems { +#[derive(Debug, Clone)] +pub struct XchandlesPendingSpendInfo { pub actions: Vec, - pub spent_slots: Vec, pub created_slots: Vec, + + pub latest_state: (NodePtr, XchandlesRegistryState), + + pub signature: Signature, +} + +impl XchandlesPendingSpendInfo { + pub fn new(latest_state: XchandlesRegistryState) -> Self { + Self { + actions: vec![], + created_slots: vec![], + spent_slots: vec![], + latest_state: (NodePtr::NIL, latest_state), + signature: Signature::default(), + } + } } #[derive(Debug, Clone)] @@ -37,7 +50,7 @@ pub struct XchandlesRegistry { pub proof: Proof, pub info: XchandlesRegistryInfo, - pub pending_items: XchandlesRegistryPendingItems, + pub pending_spend: XchandlesPendingSpendInfo, } impl XchandlesRegistry { @@ -46,7 +59,7 @@ impl XchandlesRegistry { coin, proof, info, - pending_items: XchandlesRegistryPendingItems::default(), + pending_spend: XchandlesPendingSpendInfo::new(info.state), } } } @@ -57,46 +70,232 @@ impl Registry for XchandlesRegistry { } impl XchandlesRegistry { + #[allow(clippy::type_complexity)] + pub fn pending_info_delta_from_spend( + ctx: &mut SpendContext, + action_spend: Spend, + current_state_and_ephemeral: (NodePtr, XchandlesRegistryState), + constants: XchandlesConstants, + ) -> Result< + ( + (NodePtr, XchandlesRegistryState), // pending state + Vec, // created slot values + Vec, // spent slot values + ), + DriverError, + > { + let mut created_slots = vec![]; + let mut spent_slots = vec![]; + + let expire_action = XchandlesExpireAction::from_constants(&constants); + let expire_action_hash = expire_action.tree_hash(); + + let extend_action = XchandlesExtendAction::from_constants(&constants); + let extend_action_hash = extend_action.tree_hash(); + + let oracle_action = XchandlesOracleAction::from_constants(&constants); + let oracle_action_hash = oracle_action.tree_hash(); + + let register_action = XchandlesRegisterAction::from_constants(&constants); + let register_action_hash = register_action.tree_hash(); + + let update_action = XchandlesUpdateAction::from_constants(&constants); + let update_action_hash = update_action.tree_hash(); + + let refund_action = XchandlesRefundAction::from_constants(&constants); + let refund_action_hash = refund_action.tree_hash(); + + let delegated_state_action = + >::from_constants(&constants); + let delegated_state_action_hash = delegated_state_action.tree_hash(); + + let actual_solution = ctx.alloc(&clvm_list!( + current_state_and_ephemeral, + action_spend.solution + ))?; + + let output = ctx.run(action_spend.puzzle, actual_solution)?; + let (new_state_and_ephemeral, _) = + ctx.extract::(output)?; + + let raw_action_hash = ctx.tree_hash(action_spend.puzzle); + + if raw_action_hash == extend_action_hash { + spent_slots.push(XchandlesExtendAction::spent_slot_value( + ctx, + action_spend.solution, + )?); + created_slots.push(XchandlesExtendAction::created_slot_value( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash == oracle_action_hash { + let slot_value = XchandlesOracleAction::spent_slot_value(ctx, action_spend.solution)?; + + spent_slots.push(slot_value.clone()); + created_slots.push(slot_value); + } else if raw_action_hash == update_action_hash { + spent_slots.push(XchandlesUpdateAction::spent_slot_value( + ctx, + action_spend.solution, + )?); + created_slots.push(XchandlesUpdateAction::created_slot_value( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash == refund_action_hash { + if let Some(slot_value) = + XchandlesRefundAction::spent_slot_value(ctx, action_spend.solution)? + { + spent_slots.push(slot_value.clone()); + created_slots.push(slot_value); + }; + } else if raw_action_hash == expire_action_hash { + spent_slots.push(XchandlesExpireAction::spent_slot_value( + ctx, + action_spend.solution, + )?); + created_slots.push(XchandlesExpireAction::created_slot_value( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash == register_action_hash { + spent_slots.extend(XchandlesRegisterAction::spent_slot_values( + ctx, + action_spend.solution, + )?); + created_slots.extend(XchandlesRegisterAction::created_slot_values( + ctx, + action_spend.solution, + )?); + } else if raw_action_hash != delegated_state_action_hash { + // delegated state action has no effect on slots + return Err(DriverError::InvalidMerkleProof); + } + + Ok((new_state_and_ephemeral, created_slots, spent_slots)) + } + + pub fn pending_info_from_spend( + ctx: &mut SpendContext, + inner_solution: NodePtr, + initial_state: XchandlesRegistryState, + constants: XchandlesConstants, + ) -> Result { + let mut created_slots = vec![]; + let mut spent_slots = vec![]; + + let mut state_incl_ephemeral: (NodePtr, XchandlesRegistryState) = + (NodePtr::NIL, initial_state); + + let inner_solution = + ActionLayer::::parse_solution(ctx, inner_solution)?; + + for raw_action in inner_solution.action_spends.iter() { + let res = Self::pending_info_delta_from_spend( + ctx, + *raw_action, + state_incl_ephemeral, + constants, + )?; + + state_incl_ephemeral = res.0; + created_slots.extend(res.1); + spent_slots.extend(res.2); + } + + Ok(XchandlesPendingSpendInfo { + actions: inner_solution.action_spends, + created_slots, + spent_slots, + latest_state: state_incl_ephemeral, + signature: Signature::default(), + }) + } + + pub fn from_spend( + ctx: &mut SpendContext, + spend: &CoinSpend, + constants: XchandlesConstants, + ) -> Result, DriverError> { + let coin = spend.coin; + let puzzle_ptr = ctx.alloc(&spend.puzzle_reveal)?; + let puzzle = Puzzle::parse(ctx, puzzle_ptr); + let solution_ptr = ctx.alloc(&spend.solution)?; + + let Some(info) = XchandlesRegistryInfo::parse(ctx, puzzle, constants)? else { + return Ok(None); + }; + + let solution = ctx.extract::>(solution_ptr)?; + let proof = solution.lineage_proof; + + let pending_spend = + Self::pending_info_from_spend(ctx, solution.inner_solution, info.state, constants)?; + + Ok(Some(XchandlesRegistry { + coin, + proof, + info, + pending_spend, + })) + } + + pub fn set_pending_signature(&mut self, signature: Signature) { + self.pending_spend.signature = signature; + } + + pub fn child_lineage_proof(&self) -> LineageProof { + LineageProof { + parent_parent_coin_info: self.coin.parent_coin_info, + parent_inner_puzzle_hash: self.info.inner_puzzle_hash().into(), + parent_amount: self.coin.amount, + } + } + pub fn from_parent_spend( - allocator: &mut Allocator, - parent_coin: Coin, - parent_puzzle: Puzzle, - parent_solution: NodePtr, + ctx: &mut SpendContext, + parent_spend: &CoinSpend, constants: XchandlesConstants, ) -> Result, DriverError> where Self: Sized, { - let Some(parent_info) = XchandlesRegistryInfo::parse(allocator, parent_puzzle, constants)? - else { + let Some(parent_registry) = Self::from_spend(ctx, parent_spend, constants)? else { return Ok(None); }; - let proof = Proof::Lineage(LineageProof { - parent_parent_coin_info: parent_coin.parent_coin_info, - parent_inner_puzzle_hash: parent_info.inner_puzzle_hash().into(), - parent_amount: parent_coin.amount, - }); + let proof = Proof::Lineage(parent_registry.child_lineage_proof()); - let parent_solution = SingletonSolution::::from_clvm(allocator, parent_solution)?; - let new_state = ActionLayer::::get_new_state( - allocator, - parent_info.state, - parent_solution.inner_solution, - )?; - - let new_info = parent_info.with_state(new_state); - - let new_coin = Coin::new(parent_coin.coin_id(), new_info.puzzle_hash().into(), 1); + let new_info = parent_registry + .info + .with_state(parent_registry.pending_spend.latest_state.1); + let new_coin = Coin::new( + parent_registry.coin.coin_id(), + new_info.puzzle_hash().into(), + 1, + ); Ok(Some(XchandlesRegistry { coin: new_coin, proof, info: new_info, - pending_items: XchandlesRegistryPendingItems::default(), + pending_spend: XchandlesPendingSpendInfo::new(new_info.state), })) } + pub fn child(&self, child_state: XchandlesRegistryState) -> Self { + let new_info = self.info.with_state(child_state); + let new_coin = Coin::new(self.coin.coin_id(), new_info.puzzle_hash().into(), 1); + + XchandlesRegistry { + coin: new_coin, + proof: Proof::Lineage(self.child_lineage_proof()), + info: new_info, + pending_spend: XchandlesPendingSpendInfo::new(new_info.state), + } + } + // Also returns initial registration asset id #[allow(clippy::type_complexity)] pub fn from_launcher_solution( @@ -190,7 +389,7 @@ impl XchandlesRegistry { coin: registry_coin, proof, info, - pending_items: XchandlesRegistryPendingItems::default(), + pending_spend: XchandlesPendingSpendInfo::new(info.state), }, slots, initial_registration_asset_id, @@ -200,18 +399,19 @@ impl XchandlesRegistry { } impl XchandlesRegistry { - pub fn finish_spend(self, ctx: &mut SpendContext) -> Result { + pub fn finish_spend(self, ctx: &mut SpendContext) -> Result<(Self, Signature), DriverError> { let layers = self.info.into_layers(); let puzzle = layers.construct_puzzle(ctx)?; let action_puzzle_hashes = self - .pending_items + .pending_spend .actions .iter() .map(|a| ctx.tree_hash(a.puzzle).into()) .collect::>(); + let child = self.child(self.pending_spend.latest_state.1); let solution = layers.construct_solution( ctx, SingletonSolution { @@ -227,7 +427,7 @@ impl XchandlesRegistry { .ok_or(DriverError::Custom( "Couldn't build proofs for one or more actions".to_string(), ))?, - action_spends: self.pending_items.actions, + action_spends: self.pending_spend.actions, finalizer_solution: NodePtr::NIL, }, }, @@ -236,27 +436,7 @@ impl XchandlesRegistry { let my_spend = Spend::new(puzzle, solution); ctx.spend(self.coin, my_spend)?; - let my_puzzle = Puzzle::parse(ctx, my_spend.puzzle); - let new_self = XchandlesRegistry::from_parent_spend( - ctx, - self.coin, - my_puzzle, - my_spend.solution, - self.info.constants, - )? - .ok_or(DriverError::Custom( - "Couldn't parse child registry".to_string(), - ))?; - - Ok(new_self) - } - - pub fn insert(&mut self, action_spend: Spend) { - self.pending_items.actions.push(action_spend); - } - - pub fn insert_multiple(&mut self, action_spends: Vec) { - self.pending_items.actions.extend(action_spends); + Ok((child, self.pending_spend.signature)) } pub fn new_action(&self) -> A @@ -266,188 +446,19 @@ impl XchandlesRegistry { A::from_constants(&self.info.constants) } - pub fn created_slot_values_to_slots( + pub fn created_slot_value_to_slot( &self, - slot_values: Vec, - ) -> Vec> { + slot_value: XchandlesSlotValue, + ) -> Slot { let proof = SlotProof { parent_parent_info: self.coin.parent_coin_info, parent_inner_puzzle_hash: self.info.inner_puzzle_hash().into(), }; - slot_values - .into_iter() - .map(|slot_value| { - Slot::new( - proof, - SlotInfo::from_value(self.info.constants.launcher_id, 0, slot_value), - ) - }) - .collect() - } - - pub fn get_latest_pending_state( - &self, - allocator: &mut Allocator, - ) -> Result { - let mut state = (NodePtr::NIL, self.info.state); - - for action in self.pending_items.actions.iter() { - let actual_solution = clvm_list!(state, action.solution).to_clvm(allocator)?; - - let output = run_puzzle(allocator, action.puzzle, actual_solution)?; - (state, _) = ::from_clvm( - allocator, output, - )?; - } - - Ok(state.1) - } - - pub async fn get_pending_items_from_spend( - &self, - ctx: &mut SpendContext, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::>(solution)?; - let inner_solution = ActionLayer::::parse_solution( - ctx, - solution.inner_solution, - )?; - - let mut actions: Vec = vec![]; - let mut spent_slots: Vec = vec![]; - let mut created_slots: Vec = vec![]; - - let expire_action = XchandlesExpireAction::from_constants(&self.info.constants); - let expire_action_hash = expire_action.tree_hash(); - - let extend_action = XchandlesExtendAction::from_constants(&self.info.constants); - let extend_action_hash = extend_action.tree_hash(); - - let oracle_action = XchandlesOracleAction::from_constants(&self.info.constants); - let oracle_action_hash = oracle_action.tree_hash(); - - let register_action = XchandlesRegisterAction::from_constants(&self.info.constants); - let register_action_hash = register_action.tree_hash(); - - let update_action = XchandlesUpdateAction::from_constants(&self.info.constants); - let update_action_hash = update_action.tree_hash(); - - let refund_action = XchandlesRefundAction::from_constants(&self.info.constants); - let refund_action_hash = refund_action.tree_hash(); - - let delegated_state_action = - >::from_constants( - &self.info.constants, - ); - let delegated_state_action_hash = delegated_state_action.tree_hash(); - - let mut current_state = (NodePtr::NIL, self.info.state); - for raw_action in inner_solution.action_spends { - actions.push(Spend::new(raw_action.puzzle, raw_action.solution)); - - let actual_solution = ctx.alloc(&clvm_list!(current_state, raw_action.solution))?; - - let action_output = - run_puzzle(ctx, raw_action.puzzle, actual_solution).map_err(DriverError::from)?; - (current_state, _) = ctx - .extract::( - action_output, - )?; - - let raw_action_hash = ctx.tree_hash(raw_action.puzzle); - - if raw_action_hash == delegated_state_action_hash { - // slots were not created or spent - continue; - } - - if raw_action_hash == extend_action_hash { - let spent_slot_value = XchandlesExtendAction::get_spent_slot_value_from_solution( - ctx, - raw_action.solution, - )?; - - let new_slot_value = XchandlesExtendAction::get_created_slot_value_from_solution( - ctx, - raw_action.solution, - )?; - - spent_slots.push(spent_slot_value); - created_slots.push(new_slot_value); - } else if raw_action_hash == oracle_action_hash { - let spent_slot_value = XchandlesOracleAction::get_spent_slot_value_from_solution( - ctx, - raw_action.solution, - )?; - - spent_slots.push(spent_slot_value.clone()); - created_slots.push(spent_slot_value); - } else if raw_action_hash == update_action_hash { - let spent_slot_value = XchandlesUpdateAction::get_spent_slot_value_from_solution( - ctx, - raw_action.solution, - )?; - - let new_slot_value = XchandlesUpdateAction::get_created_slot_value_from_solution( - ctx, - raw_action.solution, - )?; - - spent_slots.push(spent_slot_value); - created_slots.push(new_slot_value); - } else if raw_action_hash == refund_action_hash { - let Some(spent_slot_value) = - XchandlesRefundAction::get_spent_slot_value_from_solution( - ctx, - raw_action.solution, - )? - else { - continue; - }; - - spent_slots.push(spent_slot_value.clone()); - created_slots.push(spent_slot_value); - } else if raw_action_hash == expire_action_hash { - let spent_slot_value = XchandlesExpireAction::get_spent_slot_value_from_solution( - ctx, - raw_action.solution, - )?; - - let new_slot_value = XchandlesExpireAction::get_created_slot_value_from_solution( - ctx, - raw_action.solution, - )?; - - spent_slots.push(spent_slot_value); - created_slots.push(new_slot_value); - } else if raw_action_hash == register_action_hash { - // register - let spent_slot_values = - XchandlesRegisterAction::get_spent_slot_values_from_solution( - ctx, - raw_action.solution, - )?; - - let new_slot_values = - XchandlesRegisterAction::get_created_slot_values_from_solution( - ctx, - raw_action.solution, - )?; - - spent_slots.extend(spent_slot_values); - created_slots.extend(new_slot_values); - } else { - return Err(CliError::Custom("Unknown action".to_string())); - } - } - - Ok(XchandlesRegistryPendingItems { - actions, - spent_slots, - created_slots, - }) + Slot::new( + proof, + SlotInfo::from_value(self.info.constants.launcher_id, 0, slot_value), + ) } pub fn actual_neigbors( @@ -459,33 +470,51 @@ impl XchandlesRegistry { let mut left = on_chain_left_slot; let mut right = on_chain_right_slot; - let new_slot_value = XchandlesSlotValue::new( - new_handle_hash, - Bytes32::default(), - Bytes32::default(), - 0, - Bytes32::default(), - Bytes::default(), - ); - - for slot_value in self.pending_items.created_slots.iter() { - if slot_value.handle_hash < new_slot_value.handle_hash + for slot_value in self.pending_spend.created_slots.iter() { + if slot_value.handle_hash < new_handle_hash && slot_value.handle_hash >= left.info.value.handle_hash { - left = self - .created_slot_values_to_slots(vec![slot_value.clone()]) - .remove(0); + left = self.created_slot_value_to_slot(slot_value.clone()); } - if slot_value.handle_hash > new_slot_value.handle_hash + if slot_value.handle_hash > new_handle_hash && slot_value.handle_hash <= right.info.value.handle_hash { - right = self - .created_slot_values_to_slots(vec![slot_value.clone()]) - .remove(0); + right = self.created_slot_value_to_slot(slot_value.clone()); } } (left, right) } + + pub fn actual_slot(&self, slot: Slot) -> Slot { + let mut slot = slot; + for slot_value in self.pending_spend.created_slots.iter() { + if slot.info.value.handle_hash == slot_value.handle_hash { + slot = self.created_slot_value_to_slot(slot_value.clone()); + } + } + + slot + } + + pub fn insert_action_spend( + &mut self, + ctx: &mut SpendContext, + action_spend: Spend, + ) -> Result<(), DriverError> { + let res = Self::pending_info_delta_from_spend( + ctx, + action_spend, + self.pending_spend.latest_state, + self.info.constants, + )?; + + self.pending_spend.latest_state = res.0; + self.pending_spend.created_slots.extend(res.1); + self.pending_spend.spent_slots.extend(res.2); + self.pending_spend.actions.push(action_spend); + + Ok(()) + } }